C#調用C++Dll封裝時遇到的一系列問題

來源:互聯網
上載者:User

最近幫底層開發的同時用C#重新封裝一下dll,也就是用C#類來封裝C++Dll裡的方法,以供使用者使用。

之前也用到過類似的應用,大多數問題都出在類型轉換上,但是這次的應用程式層出不窮,所以在這裡總結一下,以供自己以後查閱,也希望對大家能夠有所協助。

  

首先,重複一下一些基本使用方法。具體的那些方式在這裡就不重複講了,網上很多的。比如http://blog.csdn.net/sunboyljp/archive/2009/12/31/5110639.aspx

c++ 標頭檔中的定義:

NPD_API int   NP_Init();

C#中定義函數

[DllImport("npd_api.dll")]

public static extern int NP_Init();

 

基本類型轉換見下表(我用到過的):

BSTR——StringBuilder

LPCTSTR ——StringBuilder

LPCWSTR ——IntPtr

handle ——IntPtr

hwnd ——IntPtr

char *  ——string

int * ——ref int

int & ——ref int

void * ——IntPtrs

unsigned char * ——ref byte    

BOOL ——bool

DWORD ——uint或int(我用的是uint,沒出過什麼問題)

 

我的問題來了,長期的經驗教訓我知道了:

1、指標做參數時在C#中一定要使用ref 或out關鍵字,尤其是結構體指標,要不會報記憶體讀取錯誤,即使不報錯資料也是不太對的。呵呵

   SIPCLIENT_API void WINAPI SCCleanup(SipClient * psip);

   [DllImport("sipclient.dll")]
       public static extern void SCCleanup(ref SipClient psip);

  其中SipClient是一個結構體。 

 

2、重寫結構體的時候,之前有指明類型長度或數組長度的地方,也要進行相應的標註,要不也會導致記憶體錯誤。       

代碼

 typedef struct { 

     char sDVRIP[16]; /* DVR IP地址 */

     char sDVRIPMask[16]; /* DVR IP位址遮罩 */

     DWORD dwNetInterface; /* 10M/100M自適應,索引 */

     WORD wDVRPort; /* 連接埠號碼 */

     BYTE byMACAddr[MACADDR_LEN]; /* 伺服器的物理地址 */

 }NET_POSA_ETHERNET;



   public struct NET_POSA_ETHERNET
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string sDVRIP; //DVR IP地址
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string sDVRIPMask; // DVR IP位址遮罩
public uint dwNetInterface; //網路介面 1-10MBase-T 2-10MBase-T全雙工系統 3-100MBase-TX 4-100M全雙工系統 5-10M/100M自適應
public uint wDVRPort; //連接埠號碼
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public byte[] byMACAddr; //[MACADDR_LEN]; //PPPoE使用者名稱//伺服器的物理地址
}



 

3、遇到這樣一個問題,折騰了大半天時間——http://space.cnblogs.com/q/16616/。

  最後是在C++那邊做了修改解決的,通過制定模組定義 (.def) 檔案,統一制定匯出函數對應的名稱。傳回值為結構體指標的函數用IntPtr也能使用了。  

代碼

 SIPCLIENT_API SipClient* SCInit(const char * reaml,    const char * from_ip, int from_port,     const char * to_ip, int to_port, const char * server_id,    const char * user_id, const char * user_name, void * user_obj_param);


[DllImport("sipclient.dll")]
public static extern IntPtr SCInit(string reaml, string from_ip, int from_port,
string to_ip, int to_port, string server_id,
string user_id, string user_name, IntPtr user_obj_param);
  IntPtr client = IntPtr.Zero;
   client = SIPCLIENT_API.SCInit(REALM, CLIENT_IP, CLIENT_PORT, SERVER_IP,     SERVER_PORT, SERVER_ID, USER_ID, USER_ID, IntPtr.Zero);
    if (client != IntPtr.Zero)
        sipclient = (SipClient)Marshal.PtrToStructure(client, typeof(SipClient));
   else
        MessageBox.Show("SipClient初始化失敗!");

 

4、後來還遇到個回呼函數導致的崩潰問題,又耽誤了大半天時間,下班了還耽擱了會終於找的解決發辦法了。

  剛開始同事分析出了崩潰的原因,都是回收方式惹的禍,可參見http://www.hudong.com/wiki/WINAPI,嘗試使用__stdcall,但是還是沒有解決問題

  後來實踐證明,程式是很嚴謹的,半點鐘差錯都不能出才不會導致錯誤,思路還是__stdcall,只不過少改了東西,有兩個地方需要改,才能保證不出錯。

  參考http://hi.baidu.com/tease/blog/item/1fe7213802780f22b9998f5a.html。

  關鍵就是這兩句話

  typedef void (_stdcall *CiCiCallBack) (bool started, void* client,char *message);
  將匯出函數修改為:
  extern "C" _declspec(dllexport) bool _stdcall Test(char* fileName, CiCiCallBack callback)

  一開始的時候就只修改了定義那,卻忘記了匯出時的修改,差點就放棄了這條解決思路了,不過還好,所謂堅持就是勝利!

  
 5、後來封裝好拿到使用者那裡用,卻總是提示說找不到C++那些dll.

  網上一查,初步定位是開發環境引起的,跟環境部署有關係。我們的開發環境是vs2008,而客戶使用的vs2010,通過幾次嘗試,問題終於了。

  首先考慮是缺少某些C++必備的運行庫,存在相互依賴關係,所以導致找不到dll。用查看Dependency Walker查看才發現真的是客戶機子上少了一些東西。

    但是此路不通,將缺少的那些東西拷貝到可執行程式目錄下,問題依舊沒有解決。但是依舊堅持這條路~

  嘗試安裝vcredist_x86.exe,以排除是否還是缺少了某些運行庫的可能,問題依然存在。

  後來我想起來之前搜尋問題的時候,看到好像跟dll的Releas\Debug版本還有關係,所有又嘗試提議讓同事將他們的c++dll改為Release版的。

    因為項目是多個人一起做了,編譯Release版還花了不少時間,不過好歹問題終於解決了!

  總結:直接安裝vcredist_x86.exe,所有dll必須使用Release版的。如果使用Debug版的就必須保證可執行程式目錄下的dll是完整的,缺一不可!

  網上詳細的講解也很多,感覺這個總結的很好http://hi.baidu.com/fairysky/blog/item/e7a8366dbaa735f3431694c8.html。

 

做程式就怕出現問題,出現問題就怕不知道原因,知道原因了就好找解決的辦法啦!

 

  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.