2012-08-29 40 views
0

我遇到了从C++中的P/Invoke C++ API获取正确数据的问题。 C++函数设置为取指针来存储请求的数据,以及大小和您想要检索的确切参数。显然,我的设置有问题,我正在寻找建议。 谢谢!在.Net中获取和读取非托管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()正确读取返回的指针?

在此先感谢!

+0

我可以帮助你的第一件事是你需要使调用约定匹配。他们目前没有。 –

+0

根据MSDN DWORD相当于C#中的uint ...第一个显然是一个指针...我有几个其他C++原型执行其他操作在类似的庄园中设置,他们都工作正常... – devHead

+0

@丹 - 你知道吗我的意思是确保您的C#代码的调用约定与您的C++代码相匹配? –

回答

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

+0

是的, 感谢您清理那个指针声明。实际上我正在使用C++ API,我无法访问源代码,只有头文件。最后一个参数看起来不是什么......我刚刚做了这个例子......它确实需要一个引用设置的id,设置的状态将存储在分配的指针中。 谢谢 – devHead

+0

哦, 我将返回值hr命名为hr,因为该函数仅返回SUCCESS或FAIL ...为了保持一致性,我保留了数据类型uint。 – devHead