2012-08-29 66 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