2016-02-13 79 views
1

我有原生C++ dll函數,可以找到連接到計算機的攝像頭數量並返回它們的序列號。我試圖在C#應用程序中使用本機C++ DLL,但我不斷收到訪問衝突錯誤(試圖讀取或寫入受保護的內存)。C#中的原生C++ dll問題#

有問題的功能是

uint32_t GetSerialNumList(char** theBufList, int theBufSize, int theListLength); 

我使用的PInvoke的方法如下:

[DllImport(CameraDll, EntryPoint = "GetSerialNumList", CallingConvention = CallingConvention.Cdecl)] 
    private static extern uint GetSerialNumList(out byte[] pBuf, int BufSize, int ListLength); 

如果我創建本地的C++應用程序使用的DLL和使用功能如下:

char* theSerialNumb;  
theSerialNumb = (char *) malloc(sizeof(char)* 8); 
status = TRI_GetSerialNumList(&theSerialNumb, 8, 1); 

它工作正常但是,如果我在C#中使用它如下給我上面提到的錯誤:

byte[] BufList; 
BufList = new byte[8]; 
rv = GetSerialNumList(out BufList, 8, 1); 
+0

爲什麼在你的'C++'的例子中你需要調用'malloc'?您無論如何都將指針的地址傳遞給'TRI_GetSerialNumList',這意味着此函數將負責將指針指向適當的內存。看起來像一個內存泄漏給我。 – PaulMcKenzie

+0

這是我的第一個想法,但TRI_GetSerialNumList沒有做分配。如果我沒有分配地址傳遞指針的地址,它會給訪問衝突錯誤寫入位置。 –

+0

幻數'8'來自'malloc'的調用?那麼C#程序應該如何取消分配這個內存(即使你的程序正常工作)呢?至於API崩潰,如果您需要使用神奇的數字來分配,則寫得很差,更不用說分配了。這是記錄的嗎?將指針指向指針的函數幾乎毫無例外,它們負責獲取指針並初始化該指針,並且不期望指向某處的指針有效(因爲該函數將指向某處有效)。 – PaulMcKenzie

回答

0

好的,我從羅素和kvr那裏得到了一些指示,並且做了一些挖掘,並且跟蹤了我提出的方案。

原始本地函數調用:

uint32_t GetSerialNumList(char** theBufList, int theBufSize, int theListLength); 

我使用的PInvoke的方式如下:

[DllImport(CameraDll, EntryPoint = "GetSerialNumList", CallingConvention = CallingConvention.Cdecl)] 
     private static extern int GetSerialNumList(ref IntPtr pBuf, int BufSize, int ListLength); 

byte[] BufIn; 
BufIn = new byte[8 * ListLength]; 
IntPtr pBuf = IntPtr.Zero; 
pBuf = Marshal.AllocHGlobal(8 * ListLength); 
Console.WriteLine("Calling GetSerialNumList"); 
       rv = GetSerialNumList(ref pBuf, 8, ListLength); 
       Marshal.Copy(pBuf, BufIn, 0, 8*ListLength); 

我覺得這是有點長,但它給了我想要的結果。

2

你在c#中傳遞的參數是一個指向字節數組的指針。你在C++中傳遞的是一個指向字節數組的指針。另外,在C++示例中,您將數據傳遞給函數,但在C#示例中,您將它作爲輸出傳遞給ref,而不是ref。

雖然我不確定這會工作,我會嘗試創建一個包含字節數組的結構並將該結構傳遞給外部函數。

要回答上面的一些評論,這些功能通常修改傳遞給它的內存,而不是嘗試分配額外的內存,因爲程序創建堆的方式不同。

1

我要檢查的第一件事就是使用的C#導入簽名。有免費的P/Invoke Interop Assistant工具here

加載你的函數簽名改成工具,將它轉換爲:

public partial class NativeMethods { 

    /// Return Type: unsigned int 
    ///theBufList: char** 
    ///theBufSize: int 
    ///theListLength: int 
    [System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="GetSerialNumList")] 
public static extern uint GetSerialNumList(ref System.IntPtr theBufList, int theBufSize, int theListLength) ; 

} 

的第二件事,是因爲你是在C++ /原生版本的緩衝區分配內存;當使用C#時,也許你還需要傳遞一個預先分配的緩衝區。

希望這會有所幫助。