我有一些带有结构描述的 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
感谢大家的帮助
答案 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