2011-05-08 79 views
2

在我的C#代碼中我想導入一個C++ DLL。我使用dllimport,它可以很好地處理一些函數。但在一個函數中,我得到一個HANDLE,我稍後需要調用另一個函數。DLLImport - >如何處理C#中的HANDLE

[DllImport("SiUSBXp.dll")] 
    public static extern int SI_Open(UInt32 deviceNum,ref IntPtr devHandle); // this function gets the HANDLE 
    [DllImport("SiUSBXp.dll")] 
    public static extern int SI_Write([In]IntPtr devHandle, [In, Out] byte[] inputByte, UInt32 size,ref UInt32 bytesWritten); // this function needs the HANDLE 

在我的代碼調用這些函數是這樣的:

IntPtr devHandle = new IntPtr(); 
    UInt32 bytesWritten = new UInt32(); 
    byte[] byteArr = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 
    SI_Open(0, ref devHandle); 
    SI_Write(devHandle, byteArr, 10, ref bytesWritten); 

如果我不喜歡這樣,我得到一個「System.AccessViolationException」。我在這裏和互聯網搜索,但沒有找到具體的答案。我如何正確使用IntPtr,所以它的工作原理? 問候

託比

+2

做SI_Open和SI_Write C++函數的原型是什麼樣的? – 2011-05-08 15:54:21

+0

您正在將字節數組初始化爲10個元素,但這對於SI_Write函數是否足夠? – 2011-05-08 15:58:08

+0

SI_STATUS WINAPI SI_Open( \t DWORD dwDevice, \t HANDLE * cyHandle \t); – Toby 2011-05-08 15:59:36

回答

1

SI_Write函數看起來很像Windows Kernel32的WriteFile

所以,我這樣做:

[DllImport("SiUSBXp.dll", SetLastError = true)] 
static extern int SI_Open(uint dwDevice, ref IntPtr cyHandle); 

[DllImport("SiUSBXp.dll", SetLastError = true)] 
static extern int SI_Write(IntPtr cyHandle, byte[] lpBuffer, 
    uint dwBytesToWrite, out uint lpdwBytesWritten); 

編輯:我在網上找到了這個文件USBXPRESS® PROGRAMMER’S GUIDE,並指出SI_Write原型看起來確實更接近WriteFile的比我想象。該文檔的狀態是:

SI_STATUS SI_Write (HANDLE Handle, LPVOID Buffer, DWORD NumBytesToWrite, 
DWORD *NumBytesWritten, OVERLAPPED* o = NULL) 

這意味着.NET原型應該是這個:

[DllImport("SiUSBXp.dll")] 
static extern int SI_Write(IntPtr Handle, byte[] Buffer, 
    uint NumBytesToWrite, out uint NumBytesWritten, IntPtr o); 

Ø是可選的,所以你可以通過IntPtr.Zero。

+0

可悲的是,這個doenst工作要麼...... :( – Toby 2011-05-08 20:16:06

+0

@Toby - 奇怪,也許C++的實現做了一些不尋常的事情,當你說它不起作用的時候,它仍然是AccessViolationException錯誤嗎? – 2011-05-09 07:04:14

+0

Ye exactly .... I d不知道問題在哪裏。我可以解決這個問題,如果我a)在SI_Write中聲明緩衝區爲out(但就像在另一個答案中已經提到的那樣,實際上是錯誤的) - 如果我這樣做,我會得到奇怪的值到達設備。和b)如果我聲明要寫入的字節數爲零,但嘿,這也不是解決方案^^ - 但我認爲問題出在字節數組中,因爲我可以使用IntPtr調用SI_Close函數(未提及這裏)沒有問題! – Toby 2011-05-09 07:46:50

1

試試這個:

[DllImport("SiUSBXp.dll")] 
    public static extern int SI_Open(UInt32 deviceNum, ref IntPtr devHandle); // this function gets the HANDLE 
    [DllImport("SiUSBXp.dll")] 
    public static extern int SI_Write(IntPtr devHandle, ref byte[] inputByte, UInt32 size, ref UInt32 bytesWritten); // this function needs the HANDLE 

編輯:

@Hans帕桑特是正確的。這是將字節[]傳遞給LPVOID參數的正確方法。 ref用於將對象強制轉換爲LPVOID,但對於數組不是必需的。當你嘗試這個時會發生什麼?

[DllImport("SiUSBXp.dll")] 
    public static extern int SI_Write(IntPtr devHandle, byte[] inputByte, UInt32 size, ref UInt32 bytesWritten); // this function needs the HANDLE 

您是否嘗試過@Simon Mourier給出的答案?他首先提供這一聲明,他的答案值得接受。

+0

是的,它做到了!謝謝!!!! – Toby 2011-05-08 18:43:34

+0

但是我嘗試寫入的字節在uC上寫法不正確:( – Toby 2011-05-08 18:44:23

+0

調用後bytesWritten的值是多少? – hsmiths 2011-05-08 18:46:38

1

您正在製作一個經典的C程序員錯誤,您不檢查函數的返回值。它告訴你該功能是否失敗。可能的情況是SI_Open()返回了失敗代碼。你忽略它並使用未初始化的句柄值。一個kaboom並不罕見。

下一個可能的錯誤是您不使用[DllImport]語句中的CallingConvention屬性。這很可能是需要的,除非使用__stdcall聲明本地函數,否則Cdecl是默認值。也是一個調用kaboom的好方法。如果你仍然有麻煩,那麼你將不得不調試本地代碼。

順便說一句,你被利用擺脫尷尬的語法出代替REF。在這兩個函數中。

[DllImport("SiUSBXp.dll", CallingConvention = CallingConvention.Cdecl)] 
    public static extern int SI_Open(UInt32 deviceNum, out IntPtr devHandle); 
+0

我其實確實檢查了返回值(和SI_Open成功),但我只是將其擦除,以便更清楚地瞭解源代碼的關鍵點。 – Toby 2011-05-08 18:45:55

+0

但你是什麼意思的Cdecl ....它第一次使用dllimport ...? – Toby 2011-05-08 18:46:22

+0

請毫不猶豫地在MSDN Library中查找。發佈更新。 – 2011-05-08 19:00:07

0

不好:static extern void DoStuff(**byte[] inputByte**);

好:static extern void DoStuff(**[In, MarshalAs(UnmanagedType.LPArray)] byte[] inputByte**);