Reputation: 1309
I'm trying to marshal primitive structure from C++ to C#, and have following code:
using System;
using System.Runtime.InteropServices;
namespace dotNet_part
{
class Program
{
static void Main(string[] args)
{
Custom custom = new Custom();
Custom childStruct = new Custom();
IntPtr ptrToStructure = Marshal.AllocCoTaskMem(Marshal.SizeOf(childStruct));
Marshal.StructureToPtr(childStruct, ptrToStructure, true);
custom.referenceType = ptrToStructure;
custom.valueType = 44;
Custom returnedStruct = structureReturn(custom);
Marshal.FreeCoTaskMem(ptrToStructure);
returnedStruct = (Custom)Marshal.PtrToStructure(returnedStruct.referenceType, typeof(Custom));
Console.WriteLine(returnedStruct.valueType); // Here 'm receiving 12 instead of 44
}
[return:MarshalAs(UnmanagedType.I4)]
[DllImport("CPlusPlus part.dll")]
public static extern int foo(Custom param);
// [return:MarshalAs(UnmanagedType.Struct)]
[DllImport("CPlusPlus part.dll")]
public static extern Custom structureReturn(Custom param);
}
[StructLayout(LayoutKind.Sequential)]
struct Custom
{
[MarshalAs(UnmanagedType.I4)]
public int valueType;
public IntPtr referenceType;
}
}
And C++ part:
typedef struct Custom CUSTOM;
extern "C"
{
struct Custom
{
int valueType;
Custom* referenceType;
} Custom;
_declspec(dllexport) int foo(CUSTOM param)
{
return param.referenceType->valueType;
}
_declspec(dllexport) CUSTOM structureReturn(CUSTOM param)
{
return param;
}
}
Why I'm receiving 12 instead of 44 in returnedStruct.valueType
?
Upvotes: 4
Views: 1134
Reputation: 168988
You have two errors here:
Semantically, you are setting custom.valueType = 44
but on return of the structure, you are checking custom.referenceType->valueType
, which should not be 44 -- it should be 0.
The second error is that you are calling Marshal.FreeCoTaskMem()
on this pointer (custom.referenceType
) before you unmarshal it! Which means that you are unmarshalling unallocated memory into your Custom
struct. At this point, this is undefined behavior, and an answer of 12 is just as valid an outcome as receiving an access violation.
To fix the first problem, you either need to check returnedStruct.valueType
without unmarshalling returnedStruct.referenceType
, or you need to set childStruct.valueType
to 44 before you marshal it into ptrToStructure
.
To fix the second problem, you need to reverse the order in which you call Marshal.PtrToStructure()
and Marshal.FreeCoTaskMem()
.
Upvotes: 4