I'm creating a C++ DLL library to be used in a C# application through P/Invoke. The C++ library exposes a function like this:
int getData(unsigned char *ptr) {
ptr = new unsigned char[5];
ptr[0] = 10;
ptr[1] = 20;
ptr[2] = 30;
ptr[3] = 40;
ptr[4] = 50;
return 0;
}
where ptr
is a pointer to an array of length 5. In C#, I have the following code:
using System.Runtime.InteropServices;
[DllImport(CppLibPath, CallingConvention = CallingConvention.Cdecl)]
private static extern int getData(ref IntPtr ptr);
public static void GetData() {
var size = 5;
var ptr = Marshal.AllocHGlobal(size);
var arr = new byte[size];
var result = getData(ref ptr, shouldDetect);
Marshal.Copy(ptr, arr, 0, size);
Marshal.FreeHGlobal(ptr);
}
I expect arr
to be an array of size 5 containing the values 10, 20, 30, 40, and 50. However, the actual values are different and seem to change every time I run the C# script. Can anyone help me understand why this is happening?
ptr = new unsigned char[5];
is just wrong: C# has no way of releasing that memory, and it's just overwriting the original pointer. So remove that line from the code in C++. The pointer will already be set by C#.
On the C# side, you can use an array, instead of doing custom marshalling.
[DllImport(CppLibPath, CallingConvention = CallingConvention.Cdecl)]
private static extern int getData
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
byte[] ptr
);
public static void GetData()
{
var arr = new byte[size];
var result = getData(arr);
}