如何将带有unsigned char *的struct从C#传递给C ++?

时间:2016-03-18 08:43:06

标签: c# c++ marshalling

我有一些带有结构描述的 C ++ dll 和一些方法:

struct MSG_STRUCT {  
    unsigned long dataSize;
    unsigned char* data;
}

并且功能例如:

unsigned long ReadMsg( unsigned long msgId, MSG_STRUCT* readMsg)
{
    readMsg->dataSize = someDataSize;
    readMsg->data = someData;
}

所以我想从 C#

中调用此函数
[StructLayout(LayoutKind.Sequential)]
struct MSG_STRUCT 
{
    UInt32 dataSize;
    byte[] data;
}

[DllImport("mydll.dll")]
public static Int32 ReadMsg( UInt32 msgId, ref MSG_STRUCT readMsg);

所以我试着调用 C#函数,如:

var readMsg = new MSG_STRUCT();
readMsg.data = new byte[4128];
Int32 res = ReadMsg( someMsgId, ref readMsg);

但我没有在数据中保持正常。 我还尝试使用ReadMsg类型参数调用IntPrt,但Marshal.PtrToStructure有时会给我AccessViolationException

我没有任何想法如何将指针从 C#传递到 C ++ MSG_STRUCT并接收结果为{{1 }}

最终解决方案对我有用: 我使用了xanatos提供的解决方案的一部分: 我为我的DllImport函数设置了MSG_STRUCT.data。 我发现我还需要改变:

CallingConvention = CallingConvention.Cdecl

感谢大家的帮助

2 个答案:

答案 0 :(得分:3)

您可以尝试:

[StructLayout(LayoutKind.Sequential)]
public struct MSG_STRUCT 
{
    int dataSize;
    IntPtr data;

    public byte[] GetData() 
    {
        var bytes = new byte[dataSize];
        Marshal.Copy(data, bytes, 0, dataSize);
        return bytes;
    }
}

[DllImport("NativeLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern uint ReadMsg(uint msgId, ref MSG_STRUCT readMsg);

然后:

MSG_STRUCT msg = new MSG_STRUCT();
uint res = ReadMsg(123, ref msg);
byte[] bytes = msg.GetData();

您的C函数正在重新分配data指针,因此您必须将其编组回C#。对我来说最简单的方法就是简单地传递IntPtr并做一些明确的Marshal.Copy(...)

另一种方法是让data成为byte[],但是在C面,您必须memcpy(readMsg->data, someData, someDataSize)而不是简单地指定readMsg->data = someData

答案 1 :(得分:2)

尝试从

更改属性
[StructLayout(LayoutKind.Sequential)]

[StructLayout(LayoutKind.Sequential, Pack=X)]

其中X是1,2,4,8 ..

c ++中的默认打包为8,因此请尝试设置Pack = 8