0

我在从 C# 中的 P/Invoke 的 C++ API 获取正确数据时遇到问题。C++ 函数设置为采用一个指针来存储请求的数据,以及大小和要检索的确切参数。我的设置显然有问题,我正在寻找建议。谢谢!

C++ 原型:

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() 正确读取返回的指针?

提前致谢!

4

1 回答 1

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”听起来更像是一个布尔值,在 C++ 中是一个字节。

只需调试它以找出问题可能是什么。在“项目+属性”的“调试”选项卡中勾选“启用非托管代码调试”复选框。并在本机代码中的 FOO_GetVal() 函数上设置断点。

于 2012-08-29T22:54:23.587 回答