C++ <--> C# modify a marshalled array of bytes
I have an unmanaged C++ function which is calling a managed C# method in a DLL. The purpose of the C# method is to take an array of bytes (allocated by the C++ caller), populate the array, and return it. I can get the array INTO the C# method, but the populated data are lost when they get back to the C++ function. Right now, this is my test code to debug the process:
C# DLL Method:
// Take an array of bytes and modify it
p开发者_JS百科ublic ushort GetBytesFromBlaster([MarshalAs(UnmanagedType.LPArray)] byte[] dataBytes)
{
dataBytes[0] = (byte)'a';
dataBytes[1] = (byte)'b';
dataBytes[2] = (byte)'c';
return 3;
}
C++ function which calls the DLL:
// bytes[] has been already allocated by its caller
short int SimGetBytesP2P(unsigned char bytes[])
{
unsigned short int numBytes = 0;
bytes[0] = 'x';
bytes[1] = 'y';
bytes[2] = 'z';
// bytes[] are {'x', 'y', 'z'} here
guiPtr->GetBytesFromBlaster(bytes, &numBytes);
// bytes[] SHOULD be {'a', 'b', 'c'} here, but they are still {'x', 'y', 'z'}
return(numBytes);
}
I believe it has something to do with C# turning the C++ pointer into a new managed array, but modifying the original one. I have tried several variations using the "ref" modifyer, etc., but no luck. Also, these data are NOT null-terminated strings; the date bytes are raw 1-byte values, not null-terminated.
Can anyone please shed some light on this? Thanks!
Stuart
You could do the marshaling yourself. Have the C# function accept a parameter by value of type IntPtr. Also a second parameter indicating array length. No special marshaling attributes are needed or wanted.
Then, use Marshal.Copy and copy the array from the unmanaged pointer to a managed byte[] array that you allocated. Do your thing, and then when you're done, use Marshal.Copy to copy it back to the C++ unmanaged array.
These particular overloads should get you started:
http://msdn.microsoft.com/en-us/library/ms146625.aspx
http://msdn.microsoft.com/en-us/library/ms146631.aspx
For example:
public ushort GetBytesFromBlaster(IntPtr dataBytes, int arraySize)
{
byte[] managed = new byte[arraySize];
Marshal.Copy(dataBytes, managed, 0, arraySize);
managed[0] = (byte)'a';
managed[1] = (byte)'b';
managed[2] = (byte)'c';
Marshal.Copy(managed, 0, dataBytes, arraySize);
return 3;
}
Alternatively you could implement a custom marshaller as described in http://msdn.microsoft.com/en-us/library/w22x2hw6.aspx if the default one isn't doing what you need it to. But that looks like more work.
I believe that you just need to add a SizeConst
attribute:
public ushort GetBytesFromBlaster(
[MarshalAs(UnmanagedType.LPArray, SizeConst=3)]
byte[] dataBytes
)
and the default marshaller should do the rest for you.
精彩评论