我遇到了从C#中P / Invoke的C ++ API中获取正确数据的问题。 C ++函数设置为使用指针来存储所请求的数据,以及要检索的大小和确切参数。我的设置显然有问题,我正在寻找建议。 谢谢!
C ++ Proto:
DECL_FOOAPIDLL DWORD WINAPI FOO_GetVal(
VOID *Val, //pointer to memory where the data will be stored by the function
DWORD Len, //length of Val in bytes
DWORD Id //identification number of the parameter
);
C#P / Invoke签名:
[DllImport(FOO_API, CharSet = CharSet.Auto)]
static public extern uint FOO_GetVal(IntPtr val, uint len, uint id);
我的C#代码获取有关设置的信息:
IntPtr Ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
uint hr = FOOWrapper.FOO_GetVal(Ptr, (uint)Marshal.SizeOf(Ptr), FOOWrapper.CMD_RUNNING);
int result = Marshal.ReadInt32(Ptr);
Marshal.FreeHGlobal(Ptr);
所以最大的问题是我是通过Marshal.ReadInt32()正确读取返回的指针吗?
提前致谢!
答案 0 :(得分:1)
pinvoke声明没有任何问题。你使用它的方式是不正确的,你正在为IntPtr保留空间但是正在读取int。正确的代码应该是:
uint len = (uint)Marshal.SizeOf(typeof(int));
IntPtr ptr = Marshal.AllocHGlobal(len);
uint hr = FOOWrapper.FOO_GetVal(ptr, len, FOOWrapper.CMD_RUNNING);
if (hr != 0) throw new COMException("FOO_GetVal failed", hr);
int result = Marshal.ReadInt32(ptr);
Marshal.FreeHGlobal(ptr);
添加很重要,您当然不想忽略错误返回码。如果它实际上是一个错误代码,那么你使用" hr"建议它确实如此,但声明表明它不是。如果它是实际数据的大小,则将其更改为:
uint actual = FOOWrapper.FOO_GetVal(ptr, len, FOOWrapper.CMD_RUNNING);
if (actual != len) throw new Exception("Improper data size");
这进一步假设您要求的参数实际上是一个int。不可能说,但是" CMD_RUNNING"听起来更像是一个bool,C ++中的一个字节。
只需调试一下即可找出问题所在。勾选"启用非托管代码调试" Project + Properties,Debug选项卡中的复选框。并在本机代码中的FOO_GetVal()函数上设置断点。