從 C# 匯出 unmanaged DLL 詳細步驟
雖然一年前寫過簡短的介紹,但最近使用又遇到一些挫折,那就再寫一篇更詳細的吧!
簡單介紹
如果你對這些基本概念沒興趣的話可以跳過,我沒正式學過、寫過 C#,對這些名詞概念頗陌生,因此記錄下來。
在談什麼是 unmanaged(非受控)之前,我們先了解什麼是 CLR(Common Language Runtime),這是微軟用來執行 .NET 程式的「虛擬機」,類似於 Java 的 JVM 都是用來將程式中間碼(CIL)即時編譯並且執行(JIT 技術),兩者間詳細的比較可以參考 [1]。
因此受到 CLR 管理的程式碼就稱為 managed code,泛指基於 .NET framework 的程式碼。
不受到 CLR 管理的成就就稱為 unmanaged code,如:MFC、VC++、VB 等。
更多內容可以參考前輩的介紹文章。
「C# 那麼好寫,我可不可以用 C# 寫完輸出 DLL 給 unmanaged 程式使用?」答案是可以的!
實際操作
建立專案
這邊建立 [類別庫 (.NET Framework)],取個名字後直接建立專案。
使用 DllExport
使用開源專案 DllExport,最新的執行檔可以在這邊找到。
相關資源:
- 作者有附上操作影片教學可以參考
- 快速開始文件(英文版)
- 範例程式(C++、C#、VB)
- Java 使用說明影片
首先,將下載的 DllExport.bat
放入專案資料夾,執行後可以看到下面操作介面:
- 勾選 [Installed] 安裝(反之則是解除安裝)
- 選擇對應的 Namespace,這邊採用
[Interop.Services](http://interop.Services)
(需另外引入) - 選擇想要輸出的格式(筆者只想輸出成 x86)
- 視情況勾選,預設都是取消的
- 前者專給
inf
錯誤(後面會詳述) - 後者專給
nan
錯誤(後面會詳述)
- 前者專給
選好後,點擊右上角 [Apply] 即可套用到專案。
如果這時候你的專案是開啟的,會看到下面情況,請點選 [全部重新載入]
在專案中:
引入 InteropServices
,並且在 static function
上方加入 [DllExport]
。
注意,簡單起見這邊限定使用於回傳 int
跟 void
的函數,其他型態頗複雜,後面說明。
using System.Runtime.InteropServices;
...
[DllExport]
public static void hello() { /* ... */ }
[DllExport]
public static int world() { /* ... */ }
編譯後,即可在 專案資料夾\bin\Debug
中(依照個人設定)看到輸出的 DLL,可能會有好幾個。
如果,你想將所有 DLL 合併成一個?
如果,你想使用於回傳其他型態函數?
後面都會說明處理方式!
檢測 DLL 匯出狀況
-
使用 CFF Explorer
-
將 DLL 拖進去即可,在 [Export Directory] 可以看到兩個被匯出的函式
-
-
使用 dumpbin
-
需要安裝 Visual C++
-
執行檔路徑在這(不同環境版本略有差異)
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\bin\Hostx64\x64
-
執行
.\dumpbin.exe -Exports xxxx.dll
-
測試專案
在 Windows 上唯一會的 unmanaged 程式開發是 MFC,但那是我大二資演惡夢… Python 那麼棒,為什麼不用 Python 測試呢😆
由於我輸出的是 32 bit 程式,裝 Python 64-bit 版本會沒辦法執行,錯誤訊息如下:
%1 is not a valid win32 application
因此改裝 Python 32-bit,使用測試碼如下:
from ctypes import*
mydll = cdll.LoadLibrary("./mylib.dll")
result1 = mydll.world()
或是可以使用這種呼叫方式。
合併 DLL
開啟 DllExport.bat
.\DllExport.bat -action Configure
選擇索引標籤 [Pre-processing],勾選 [Merge modules via ILMerge],並且在下方填入所有想要合併的 DLL 名稱(使用空格分開,不含最終 DLL),最後點選 Apply。
在
專案.csproj
中就可以看到ILMergeConsolePath
相關字串
這時候回到專案編譯,正常來說不會有錯誤訊息,且可以發現目標 DLL 檔案大小明顯大了許多。
如果遇到錯誤訊息如:
-inf
錯誤 C:\jackkuo\Desktop\MyProj\Class1.cs(16707566) : error : syntax error at token '-' in: IL_0027: ldc.r8 -inf MyProj
或是 -nan(ind)
錯誤 C:\jackkuo\Desktop\MyProj\Class1.cs(16707566) : error : syntax error at token '-' in: IL_0027: ldc.r8 -nan(ind) MyProj
那則需要根據不同的錯誤訊息把 “4” 開啟
想使用於回傳其他型態函數?
這部分複雜許多,請參考作者教學影片2。
- 需從 NuGet 中安裝
regXwild
跟Conari
- 勾選 [Integrate Conari]
再來就是各種記憶體串接,這部分是作者自幹常見格式讓不同語言間可以互接,詳情請參考作者的影片。
其他方式
網路上有其他方式能夠從 C# 中輸出 unmanaged DLL,不過我都沒成功…
- .NET C# 建立 COM元件 (5) — UnManaged Exports dll
- C#的dll檔如何讓 Foxpro 呼叫
- HOW DO I EXECUTE A DLL IN VIUSUAL FOXPRO
參考資料:
comments powered by Disqus