I encountered an issue where allocating memory for a struct with new in the C++ function does not correctly transfer the instance back to C#.
It seems that the correct approach is to avoid using new
in the C++ function and directly set the values of the out parameter. However, I couldn't find documentation that explicitly describes this behavior or explains how out parameters automatically handle instance creation.
Do you have this information somewhere on Microsoft Document?
I would like to know if you know of it.
C++ code:
struct MyStruct {
int value1;
float value2;
};
extern "C" __declspec(dllexport) void GetValues(MyStruct* outStruct) {
// outStruct = new MyStruct(); // NG
outStruct->value1 = 42;
outStruct->value2 = 3.14f;
}
C# code:
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct {
public int value1;
public float value2;
}
[DllImport("MyNativeLib.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void GetValues(out MyStruct result);
public static void TestInterop() {
MyStruct result;
GetValues(out result);
}
Are out struct parameters automatically initialized in C++ when using P/Invoke in C#?
The answer is: no.
I am not aware of specfific documentation that specifies this, it's simply a basic issue of how C++ works, regardless of P/Invoke.
how out parameters automatically handle instance creation
They don't.
The creation of the instance is done in your case on the C# side with:
MyStruct result;
Note that since MyStruct
is a struct and therefore a value-type, it does not require new
ing (although it's optional).
The instance is created on the stack.
A pointer to this instance (outStruct
) is then passed to C++, and it gets filled via this pointer by the C++ function.
A side note:
The reason that using outStruct = new MyStruct();
inside GetValues
did not have the effect you expected is that in C++ (as well as C) parameters are generally passed by value (in C++ we also have pass-by-ref but this is not the case here).
In this case the pointer (holding an address) is passed by value. Changing the pointer itself in the function will not affect the caller.
In order to affect the caller you need to pass a pointer-to-a-pointer.
See this post for more info: C++ why double pointer for out/return function parameter?.