What kind of pointer returned if I use "&" to get address of a value type in C++\CLI? - c++-cli

Suppose I write the following code:
public ref class Data
{
public:
Data()
{
}
Int32 Age;
Int32 year;
};
public void Test()
{
int age = 30;
Int32 year = 2010;
int* pAge = &age;
int* pYear = &year;
Data^ data = gcnew Data();
int* pDataYear = &data->Year; // pData is interior pointer and the compiler will throw error
}
If you compile the program, the compiler will throw error:
error C2440: 'initializing' : cannot convert from 'cli::interior_ptr' to 'int *'
So I learned the "&data->Year" is a type of interior pointer.
UPDATES: I tried to use "&(data->Year)", same error.
But how about pAge and pYear?
Are they native pointers, interior pointers or pinned pointers??
If I want to use them in the following native function:
void ChangeNumber(int* pNum);
Will it be safe to pass either pAge or pYear?

They (pAge and pYear) are native pointers, and passing them to a native function is safe. Stack variables (locals with automatic storage lifetime) are not subject to being rearranged by the garbage collector, so pinning is not necessary.
Copying managed data to the stack, then passing it to native functions, solves the gc-moving-managed-data-around problem in many cases (of course, don't use it in conjunction with callbacks that expect the original variable to be updated before your wrapper has a chance to copy the value back).
To get a native pointer to managed data, you have to use a pinning pointer. This can be slower than the method of copying the value to the stack, so use it for large values or when you really need the function to operate directly on the same variable (e.g. the variable is used in callbacks or multi-threading).
Something like:
pin_ptr<int> p = &mgd_obj.field;
See also the MSDN documentation

Related

Is that an in or in/out parameter? Doxygen, C++

If a pointer is passed to a function for read only, then this pointer is an IN parameter.
If a pointer is passed to a function for read only, but this function makes a copy of the pointer to have access to it in module related functions for read only operations, this pointer is still IN.
If the function still uses the pointer as read only, but the other module related functions use the pointer for write operations, what does that make the pointer?
An IN parameter, but without const? An in/out parameter?
Example of what I mean:
class SteeringWheel {
public: float rotation;
public: SteeringWheel(void) {
this->rotation = 0.f;
}
};
class Car {
private: SteeringWheel *steeringWheel;
public:
/**
* #param[?] steeringWheel Is the steering wheel in or in/out?
*/
Car (SteeringWheel *steeringWheel) {
this->steeringWheel = steeringWheel;
}
/**
* #param[in] degree Steering amount in degrees.
*/
void steer(float degree)
{
this->steeringWheel->rotation += degree;
}
};
int main(int argc, char **argv)
{
SteeringWheel steeringWheel();
/* car() uses steeringWheel as read only. */
Car car(&steeringWheel);
/* steer() uses steeringWheel from car() to write. */
car.steer(50.f);
return 0;
}
I believe that the in and out specifiers do not exactly mean what you think. From the doxygen documentation of the param tag:
The \param command has an optional attribute, (dir), specifying the
direction of the parameter. Possible values are "[in]", "[in,out]",
and "[out]", note the [square] brackets in this description. When a
parameter is both input and output, [in,out] is used as attribute.
The direction of the parameter usually mean the following:
in: The parameter is injected into the function as input, but not written to.
out: The parameter is injected into the function, but not as input. Rather, it is written to by the function.
in, out: The parameter is injected into the function as input and is eventually written to by the function.
In your example:
/**
* #param[?] steeringWheel Is the steering wheel in or in/out?
*/
Car (SteeringWheel *steeringWheel) {
this->steeringWheel = steeringWheel;
}
I think the steeringWheel parameter is in because you inject it and use it in your method. However, you never write to it (i.e. to the parameter itself), so it is not out. In other words, you only use your method to inject an address to your function, nothing else. The same apply for your second method, where you inject the degree parameter, but never write to it.
To clarify a bit more on the meaning of in and out, here is an example of an out parameter:
/**
* #param[out] p_param We write to the parameter!
*/
void makeFour(int * p_param)
{
*p_param = 4; // Out because of this line!
}
Notice that we write a new value directly into the parameter. This is the meaning of out: information comes out of the method through the parameter. You can now write:
int main()
{
int myInt = 0;
std::cout << myInt; // prints 0.
makeFour(&myInt); // p_param == &myInt here.
std::cout << myInt; // prints 4: the method wrote directly
// in the parameter (out)!
return 0;
}
Hope this helps!
It is not easy to decide, but I would still mark your parameter as in,out (or out), as it is a pointer to a non-const object, and you may change the state of that outside object directly or indirectly later - as in your example.
Marking it in hides the detail that the pointed SteeringWheel object may change later upon usage of Car.
Also, it can puzzle users why an input only pointer parameter is not marked const.
Making it in,out may not be accurate completely, but is surely more error prone.
An alternative could be something like the following (a note regarding the lifetime of the SteeringWheel should come handy here anyway):
/**
* #param[in] steeringWheel Pointer to the SteeringWheel object.
* #warning The memory address of the pointed object is saved.
* It must outlive this object, and can change upon usage of this object.
*/
Car (SteeringWheel *steeringWheel) {
this->steeringWheel = steeringWheel;
}
But I would just probably stick with marking it in,out.
Specifying the direction of parameters in C++ may be complicated, and frankly speaking, I am not too much in favor of them, as having tokens for pointers, references, and the keyword for constness provide enough information in the signature on how a parameter may be used. Thus, marking it in the DoxyPress documentation is a bit redundant, not expressive enough (as your example shows), and may get out of sync with the implementation. Documenting parameter directions may play a bigger role in case of other languages that lack these additional constructs in function signatures.

Cannot cast pointer field while can cast same pointer defined within method in managed classes

I have unmanaged object of WtfClass.
class WtfClass { };
And I also have managed class which uses pointer to this object.
ref class MyClass //works fine if you remove "ref"
{
public:
void MyMethod();
void WtfMethod(void * pVoid);
WtfClass *pWtfStruct;
};
void MyClass::MyMethod()
{
/*WtfClass* pWtfStruct; //if you uncomment this it will compile even with ref*/
WtfMethod((int*)(&pWtfStruct)); //(!!!invalid type conversion here)
}
void MyClass::WtfMethod(void *pVoid)
{}
I can't cast WtfClass* pointer from field, but can easily cast the same pointer defined within MyMethod(). If make MyClass unmanaged it works in any case.
It's better to look at screenshots:
https://ibin.co/2iOcN1ooaC7A.png [using ref-bad.png]
https://ibin.co/2iOcYtP84H0e.png [using ref-good.png]
ibin.co/2iOcjCCc2gQe.png [without ref.png] (sorry not enough reputation to paste more than 2 links)
Of course I can have workaround like this, but I'd like to understand why this happening:
void MyClass::MyMethod()
{
WtfClass* pWorkAround = pWtfStruct; //not required in this case
WtfMethod((void*)(&pWorkAround));
}
OK, so to summarize, without the duplicate field & local variable names:
ref class MyClass
{
WtfClass* fieldWtfPtr;
void foo()
{
WtfClass* localvarWtfPtr;
WtfMethod((int*)(&fieldWtfPtr)); // Error
WtfMethod((int*)(&localvarWtfPtr)); // Works
}
};
Side question: &fieldWtfPtr is of type WtfClass**, a double pointer. Did you mean to cast that to a int**, also a double pointer? Or perhaps did you want to take fieldWtfPtr as a WtfClass* single pointer and cast that to a int* single pointer?
Here's why you're getting the error: MyClass is a managed object. The garbage compiler is allowed to move it around at any point, without telling you. So, it's location in memory can change at any point. So when you try to take the address of a class field, it's not valid because the address of that field can change at any point!
Why the other things make it work:
Local variables are stored on the stack, and the stack doesn't get moved around by the garbage collector, so it is valid to take the address of a local variable.
If you remove the ref, then MyClass is no longer a managed object, so the garbage collector won't move it around, so now the addresses of its fields won't change willy-nilly.
For this case, the easiest fix would be to make use of a local temporary variable.
void foo()
{
WtfClass* localCopyWtfPtr = this->fieldWtfPtr;
WtfMethod((int*)(&localCopyWtfPtr)); // Works
// If WtfMethod changed the data, write it back.
this->fieldWtfPtr = localCopyWtfPtr;
}
When I tried to recreate this, the compiler generated the following error:
error C2440: 'type cast' : cannot convert from 'cli::interior_ptr<CWtfClass*>' to 'LPVOID *'
I think what is going on here is some magic that allows managed classes to have unmanaged members. The MSDN documentation for cli::interior_ptr describes what's going on - basically this is used to allow for the managed object to change its memory address in the managed heap, which would cause problems when native pointers come in to play.
The reason that assigning the member to a variable first works is most likely because it has an implicit conversion to the template parameter, but since it is a managed type the compiler won't allow you to get the address of the variable (since the garbage collector can move it around in memory as needed).
The workaround in your question is probably the best way to fix this compiler error.
David answered why this happens and suggested a workaround for your case.
I'll just post a different solution here: You can pin your managed object to tell the GC not to move it around. The most lightweight way to do that is through pin_ptr (the GC won't even know you pinned something unless it stumbles upon your code in the middle of a collection). As long as it stays in scope, the managed object will be pinned and won't move. It's best if you avoid pinning for too long, but this lets you get a pointer to a chunk of managed memory which is guaranteed not to move - it's helpful when you want to avoid copying things around.
Here's how to do it:
pin_ptr<WtfClass*> pin(&pWtfStruct);
WtfMethod(pin);
pin acts just like a WtfClass**.
Regarding side question of David Yaw.
I faced with this problem while used some WINAPI functions.
IAudioEndpointVolume* pWtfVolume = NULL;
pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, (void**)&pWtfVolume);
pWtfVolume->SetMute(BST_CHECKED, pGuidMyContext);
And it's working only if I pass &pWtfVolume. Ironically you can pass argument without "&", just pFieldVolume and compiler will say OKAY, but interface IAudioEndpointVolume will not work.
Look at this:
ref class MyClass
{
WtfClass* fieldWtfPtr;
void foo()
{
WtfClass* localvarWtfPtr;
WtfMethod((int*)(&fieldWtfPtr)); // Error
WtfMethod((int*)(&localvarWtfPtr)); // Works
WtfMethod((int*)(fieldWtfPtr)); // Compiles!!!
}
};

How can I use a 'native' pointer in a reference class in C++/CLI?

I am trying to write a small library which will use DirectShow. This library is to be utilised by a .NET application so I thought it would be best to write it in C++/CLI.
I am having trouble with this line however:
HRESULT hr = CoCreateInstance( CLSID_FilterGraph,
NULL,
CLSCTX_INPROC_SERVER,
IID_IGraphBuilder,
(void**)(&graphBuilder) ); //error C2440:
Where graphBuilder is declared:
public ref class VideoPlayer
{
public:
VideoPlayer();
void Load(String^ filename);
IGraphBuilder* graphBuilder;
};
If I am understanding this page correctly, I can use */& as usual to denote 'native' pointers to unmanaged memory in my C++/CLI library; ^ is used to denote a pointer to a managed object. However, this code produces:
error C2440: 'type cast' : cannot convert from 'cli::interior_ptr' to 'void **'
The error suggests that graphBuilder is considered to be a 'cli::interior_ptr<Type>'. That is a pointer/handle to managed memory, isn't it? But it is a pure native pointer. I am not trying to pass the pointer to a method expecting a handle or vice versa - I simply want to store it in my managed class) If so, how do I say graphBuilder is to be a 'traditional' pointer?
(This question is similar but the answer, to use a pin_ptr, I do not see helping me, as it cannot be a member of my class)
The error message is a bit cryptic, but the compiler is trying to remind you that you cannot pass a pointer to a member of a managed class to unmanaged code. That cannot work by design, disaster strikes when the garbage collector kicks in while the function is executing and moves the managed object. Invalidating the pointer to the member in the process and causing the native code to spray bytes into the gc heap at the wrong address.
The workaround is simple, just declare a local variable and pass a pointer to it instead. Variables on the stack can't be moved. Like this:
void init() {
IGraphBuilder* builder; // Local variable, okay to pass its address
HRESULT hr = CoCreateInstance(CLSID_FilterGraph,
NULL,
CLSCTX_INPROC_SERVER,
IID_IGraphBuilder,
(void**)(&builder) );
if (SUCCEEDED(hr)) {
graphBuilder = builder;
// etc...
}
}

Marshalling simple and complex datatypes to/from Object^% / void*

I guess this will be simple for C++/CLI gurus.
I am creating a wrapper which will expose high-performance C++ native classes to C# WinForms application.
Everything went fine with simple known objects and I could wrap also a callback function to delegate. But now I am a bit confused.
The native C++ class has a following method:
int GetProperty(int propId, void* propInOut)
At first I thought I could use void* as IntPtr, but then I found out that I need to access it from C#. So I thought about a wrapper method:
int GetProperty(int propId, Object^ propInOut)
but as I looked through the C++ source, I found out that the method needs to modify the objects. So obviously I need:
int GetProperty(int propId, Object^% propInOut)
Now I cannot pass Objects to native methods so I need to know how to treat them in the wrapper. As the caller should always know what kind of data he/she is passing/receiving, I declared a wrapper:
int GetProperty(int propId, int dataType, Object^% propInOut)
I guess, I can use it to pass reference and value types, for example, an int like this:
Object count = 100; // yeah, I know boxing is bad but this will not be real-time call anyway
myWrapper.GetProperty(Registry.PROP_SMTH, DATA_TYPE_INT, ref count);
I just added a bunch of dataType constants for all the data types I need:
DATA_TYPE_INT, DATA_TYPE_FLOAT, DATA_TYPE_STRING, DATA_TYPE_DESCRIPTOR, DATA_TYPE_BYTE_ARRAY
(DATA_TYPE_DESCRIPTOR is a simple struct with two fields: int Id and wstring Description - this type will be wrapped too, so I guess marshaling will be simple copying data back and forth; all the native strings are Unicode).
Now, the question is - how to implement the wrapper method for all these 5 types?
When I can just cast Object^% to something (is int, float safe to do that?) and pass to native method, when do I need to use pin_ptr and when I need some more complex marshaling to native and back?
int GetProperty(int propId, int dataType, Object^% propInOut)
{
if(dataType == DATA_TYPE_INT)
{
int* marshaledPropInOut = ???
int result = nativeObject->GetProperty(propId, (void*)marshaledPropInOut);
// need to do anything more?
return result;
}
else
if(dataType == DATA_TYPE_FLOAT)
{
float* marshaledPropInOut = ???
int result = nativeObject->GetProperty(propId, (void*)marshaledPropInOut);
// need to do anything more ?
return result;
}
else
if(dataType == DATA_TYPE_STRING)
{
// will pin_ptr be needed or it is enough with the tracking reference in the declaration?
// the pointers won't get stored anywhere in C++ later so I don't need AllocHGlobal
int result = nativeObject->GetProperty(propId, (void*)marshaledPropInOut);
// need to do anything more?
return result;
}
else
if(dataType == DATA_TYPE_BYTE_ARRAY)
{
// need to convert form managed byte[] to native char[] and back;
// user has already allocated byte[] so I can get the size of array somehow
return result;
}
else
if(dataType == DATA_TYPE_DESCRIPTOR)
{
// I guess I'll have to do a dumb copying between native and managed struct,
// the only problem is pinning of the string again before passing to the native
return result;
}
return -1;
}
P.S. Maybe there is a more elegant solution for wrapping this void* method with many possible datatypes?
It doesn't necessarily make sense to equate a C# object to a void*. There isn't any way to marshal arbitrary data. Even with an object, C# still knows what type it is underneath, and for marshaling to take place -- meaning a conversion from the C++ world to C# or vice-versa -- the type of data needs to be known. A void* is just a pointer to memory of a completely unknown type, so how would you convert it to an object, where the type has to be known?
If you have a limited number of types as you describe that could be passed in from the C# world, it is best to make several overloads in your C++/CLI code, each of which took one of those types, and then you can pin the type passed in (if necessary), convert it to a void*, pass that to your C++ function that takes a void*, and then marshal back as appropriate for the type.
You could implement a case statement as you listed, but then what do you do if you can't handle the type that was passed in? The person calling the function from C# has no way to know what types are acceptable and the compiler can't help you figure out that you did something wrong.

Tracking reference in C++/CLI

Can someone please explain me the following code snippet?
value struct ValueStruct {
int x;
};
void SetValueOne(ValueStruct% ref) {
ref.x = 1;
}
void SetValueTwo(ValueStruct ref) {
ref.x = 2;
}
void SetValueThree(ValueStruct^ ref) {
ref->x = 3;
}
ValueStruct^ first = gcnew ValueStruct;
first->x = 0;
SetValueOne(*first);
ValueStruct second;
second.x = 0;
SetValueTwo(second); // am I creating a copy or what? is this copy Disposable even though value types don't have destructors?
ValueStruct^ third = gcnew ValueStruct;
third->x = 0;
SetValueThree(third); // same as the first ?
And my second question is: is there any reason to have something like that?:
ref struct RefStruct {
int x;
};
RefStruct% ref = *gcnew RefStruct;
// rather than:
// RefStruct^ ref = gcnew RefStruct;
// can I retrieve my handle from ref?
// RefStruct^ myref = ???
What is more: I see no difference between value type and ref type, since both can be pointed by handler ;(
Remember that the primary use of C++/CLI is for developing class libraries for consumption by GUIs / web services built in other .NET languages. So C++/CLI has to support both reference and value types because other .NET languages do.
Furthermore, C# can have ref parameters that are value typed as well, this isn't unique to C++/CLI and it doesn't in any way make value types equivalent to reference types.
To answer the questions in your code comments:
am I creating a copy or what?
Yes, SetValueTwo takes its parameter by value, so a copy is made.
is this copy Disposable even though value types don't have destructors?
Incorrect. Value types can have destructors. Value types cannot have finalizers. Since this particular value type has a trivial destructor, the C++/CLI compiler will not cause it to implement IDisposable. In any case, if a parameter is an IDisposable value type, the C++/CLI compiler will ensure that Dispose is called when the variable goes out of scope, just like stack semantics for local variables. This includes abnormal termination (thrown exception), and allows managed types to be used with RAII.
Both
ValueStruct% ref = *gcnew ValueStruct;
and
ValueStruct^ ref = gcnew ValueStruct;
are allowed, and put a boxed value type instance on the managed heap (which isn't a heap at all, but a FIFO queue, however Microsoft chooses to call it a heap like the native memory area for dynamic allocation).
Unlike C#, C++/CLI can keep typed handles to boxed objects.
If a tracking reference is to a value type instance on the stack or embedded in another object, then the value type content has to be boxed in the process of formed the reference.
Tracking references can also be used with reference types, and the syntax to obtain a handle is the same:
RefClass^ newinst = gcnew RefClass();
RefClass% reftoinst = *newinst;
RefClass^% reftohandle = newinst;
RefClass stacksem;
RefClass^ ssh = %stacksem;
One thing that I can never seem to remember completely is that the syntax isn't 100% consistent compared to native C++.
Declare a reference:
int& ri = i; // native
DateTime% dtr = dt; // managed tracking reference
Declare a pointer:
int* pi; // native
Stream^ sh; // tracking handle
Form a pointer:
int* pi = &ri; // address-of native object
DateTime^ dth = %dtr; // address-of managed object
Note that the unary address-of operator is the same as the reference notation in both standard C++ and C++/CLI. This seems to contradict a tracking reference cannot be used as a unary take-address operator (MSDN) which I'll get back to in a second.
First though, the inconsistency:
Form a reference from a pointer:
int& iref = *pi;
DateTime% dtref = *dth;
Note that the unary dereference operator is always *. It is the same as the pointer notation only in the native world, which is completely opposite of address-of which, as mentioned above, are always the same symbol as the reference notation.
Compilable example:
DateTime^ dth = gcnew DateTime();
DateTime% dtr = *dth;
DateTime dt = DateTime::Now;
DateTime^ dtbox = %dt;
FileInfo fi("temp.txt");
// FileInfo^ fih = &fi; causes error C3072
FileInfo^ fih = %fi;
Now, about unary address-of:
First, the MSDN article is wrong when it says:
The following sample shows that a tracking reference cannot be used as a unary take-address operator.
The correct statement is:
% is the address-of operator for creation of a tracking handle. However its use is limited as follows:
A tracking handle must point to an object on the managed heap. Reference types always exist on the managed heap so there is no problem. However, value types and native types may be on the stack (for local variables) or embedded within another object (member variables of value type). Attempts to form a tracking handle will form a handle to a boxed copy of the variable: the handle is not linked to the original variable. As a consequence of the boxing process, which requires metadata which does not exist for native types, it is never possible to have a tracking handle to an instance of a native type.
Example code:
int i = 5;
// int^ ih = %i; causes error C3071
System::Int32 si = 5;
// System::Int32^ sih = %si; causes error C3071
// error C3071: operator '%' can only be applied to an instance
// of a ref class or a value-type
If System::Int32 isn't a value type then I don't know what is. Let's try System::DateTime which is a non-primitive value type:
DateTime dt = DateTime::Now;
DateTime^ dtbox = %dt;
This works!
As a further unfortunate restriction, primitive types which have dual identity (e.g. native int and managed value type System::Int32) are not handled correctly, the % (form tracking reference) operator cannot perform boxing even when the .NET name for the type is given.