以前歷來沒搞過C++,最近被安排的任務須要調用C++的接口,對於一個沒用過 Dependency 的小白來講,本來覺得像平時的Http接口那樣,協議,端口必定義,方法參數一寫就沒事,結果踩了無數的坑。如今從0基礎開始記錄。A發了一個SDK文件夾過來,先無論cpp、h、lib五花八門的後綴文件,直接看文檔說明,代表須要調哪些方法。網上簡單的查閱下資料,發現直接引用動態庫Dll 的方式是經過 DllImport去實現,命名空間爲 using System.Runtime.InteropServices; c++
按照文檔中方法名、參數類型的說明,寫下對應代碼api
[DllImport("ConX.dll", EntryPoint = "add")] public static extern int add(byte[] cfg_dir_name); //VS2017中 方法名首字母須要大寫爲 Add public void Test1() { int a=0; try { string str = "123"; byte[] bts = Encoding.Default.GetBytes(str); a = add(bts); } catch (Exception ex) { string strEx = ex.Message; } Console.WriteLine(a); Console.ReadLine(); }
一運行,提示 " 試圖加載格式不正確的程序。 (異常來自 HRESULT:0x8007000B)" ,這通常是版本不匹配的緣由,肯定dll 版本爲64位後,將Debug中設置爲 x64 便可 (32位則設置爲x86),接着運行 ,會提示 " 找不到Dll的入口點 "函數
用 DepenDency 查看下該Dll ,發現所謂的函數名變化了,並非add,變成了下圖一長串的字符(CallingConvention.Cdecl 編碼)學習
相關資料顯示,在導出C++程序是,能夠選擇C方式,和C++方式,C方式不會變動函數名,C++則會, 項目右鍵--屬性--配置屬性--C/C++--高級--編譯爲--①C ②C++ ,固然還能夠在原函數中的前面加上Extern C來限定導出後函數名不變,目前沒有源碼,只有dll,因此對於這種狀況,只須要將變動的函數名做爲入口點 賦值給 EntryPoint 便可 測試
[DllImport("ConX.dll", EntryPoint = "?add@@YAHABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z")]編碼
接着運行,這個時候 又會提示 " 請檢查PInvoke 簽名的調用約定和參數與非託管的目標籤名是否匹配 " , 資料顯示,調用平臺的默認約定 爲Winapi , 而這種變動方法後的格式 " ?方法名@@YA-----------@Z " 爲Cdecl 約定,因而再次更改導入dll的代碼
spa
[DllImport("ConX.dll", EntryPoint = "?add@@YAHABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z",CallingConvention=CallingConvention.Cdecl)]3d
如此折騰了一番,運行後, 若是報 " 沒法加載 DLL「face_export.dll」: 找不到指定的程序 " 那就是路徑有問題,通常處理方法以下調試
①直接把Dll 拷貝到 執行文件exe所在的目錄下,記住經過Dependency 查看dll時,看下有沒有缺失的dll ,若是沒有,在將所依賴的非系統的dll 一併拷貝到 執行文件exe所在的目錄下,code
②使用 Dll 的絕對路徑
③將 Dll 拷貝至系統的文件下,64位系統 對應的32位Dll則爲SysWOW ,64爲Dll 則爲System32
正常狀況下,到這裏就沒有什麼大問題,若是報參數問題,那就須要查閱 C++ 對應的 C# 數據類型。匹配正確便可,關鍵就在於我這裏仍然報錯,外部組件異常,外部組件異常,外部組件異常,查閱資料顯示,網上沒什麼好的解決方案,由於這種問題的緣由五花八門,是一個很籠統的錯誤,但是恰恰就被我遇到了,我這邊按接口中函數的申明,照葫蘆畫瓢寫了一個C++ 的Dll,用C#調用本身寫的Dll 是OK 。同事用C++調用 第三方的 Dll 也沒問題(說明別人提供的Dll沒問題)。這樣一來就尷尬了,思路不能沉寂在這裏。網上有人說是Net 版本可能不兼容,我挨個嘗試一遍從3.5 切換到 4.6.1 還是外部組件異常的錯誤。 最後我用VS2017 打開,調試程序,仍然是外部組件異常。如今能夠排除的是 不是依賴問題(報找不到Dll),不是沒加載指定Dll問題, 由於不會報入口點找不到的錯誤,也不是參數的問題,版本的問題已經用VS2017嘗試過。還會有什麼方面的緣由呢?
未完待續...
最後通過翻來覆去的測試,發現問題出在 c++ 的dll上,最後從新封裝了一邊dll,再次調用就沒問題了,看來仍是本身學習的不夠...