在.Net中获取和读取非托管C ++指针

时间:2012-08-29 16:15:26

标签: c# c++ marshalling

我遇到了从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()正确读取返回的指针吗?

提前致谢!

1 个答案:

答案 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()函数上设置断点。