C ++< - > C#修改一个编组的字节数组

时间:2011-08-10 13:28:45

标签: c# c++ interop pinvoke marshalling

我有一个非托管C ++函数,它在DLL中调用托管C#方法。 C#方法的目的是获取一个字节数组(由C ++调用者分配),填充数组并返回它。我可以将数组转换为C#方法,但填充的数据在返回C ++函数时会丢失。现在,这是我调试过程的测试代码:

C#DLL方法:

// Take an array of bytes and modify it
public ushort GetBytesFromBlaster([MarshalAs(UnmanagedType.LPArray)] byte[] dataBytes)
{
    dataBytes[0] = (byte)'a';
    dataBytes[1] = (byte)'b';
    dataBytes[2] = (byte)'c';
    return 3;
}

调用DLL的C ++函数:

// 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);

}

我认为它与C#有关,将C ++指针转换为新的托管数组,但修改原始数据。我使用“ref”修改器等尝试了几种变体,但没有运气。此外,这些数据不是以空字符结尾的字符串;日期字节是原始的1字节值,不是以空值终止的。

任何人都可以对此有所了解吗?谢谢!

斯图尔特

2 个答案:

答案 0 :(得分:4)

你可以自己做编组。让C#函数接受IntPtr类型的值的参数。也是表示数组长度的第二个参数。不需要或不需要特殊的编组属性。

然后,使用Marshal.Copy并将数组从非托管指针复制到您分配的托管byte []数组。做你的事,然后当你完成后,使用Marshal.Copy将其复制回C ++非托管数组。

这些特殊的重载应该让你开始:

http://msdn.microsoft.com/en-us/library/ms146625.aspx
http://msdn.microsoft.com/en-us/library/ms146631.aspx

例如:

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;
}

或者,您可以实现自定义编组程序,如http://msdn.microsoft.com/en-us/library/w22x2hw6.aspx中所述,如果默认值不是您需要的话。但这看起来更像是工作。

答案 1 :(得分:0)

我相信您只需要添加SizeConst属性:

public ushort GetBytesFromBlaster(
    [MarshalAs(UnmanagedType.LPArray, SizeConst=3)] 
    byte[] dataBytes
)

并且默认的编组应该为你完成其余的工作。