DllImport 自动选择x64或x86 dll
前言
標(biāo)題不知道怎么確切地命名,在.net的托管世界里,有時(shí)不得不使用c的某個(gè)動(dòng)態(tài)庫(kù),比如ocr、opencv等,如果幸運(yùn),有前人已經(jīng)包裝出.net版本,但有些不非常流行的庫(kù),只能自己使用pinvoke或c++ cli包裝了,比如筆者就遇到了一個(gè),mqtt客戶端庫(kù)。
Pinvoke的多平臺(tái)問(wèn)題
如果您沒(méi)有接觸過(guò)如何調(diào)用非托管dll,沒(méi)有了解過(guò)c#的DllImportAttribute,可以看看以下資料:
1、DllImportAttribute
2、Pinvoke
3、extern 關(guān)鍵字
多平臺(tái)支持問(wèn)題來(lái)源:
1、c的庫(kù)是編譯時(shí)確定了平臺(tái),比如x86或x64,一個(gè)dll不能在運(yùn)行時(shí)既支持x86也支持x64,所以如果引用它的.net程序還想支持any cpu,只能在運(yùn)行后根據(jù)平臺(tái)去加載對(duì)應(yīng)平臺(tái)的c的庫(kù);
2、DllImport 特性要求傳入string?dllName參數(shù),這個(gè)參數(shù)可以是相對(duì)路徑或絕對(duì)路徑,但.Net的特性有個(gè)要求:特性實(shí)參必須是特性形參類型的常量表達(dá)式、typeof 表達(dá)式或數(shù)組創(chuàng)建表達(dá)式。也就是說(shuō)string?dllName這個(gè)值必須在寫(xiě)代碼的時(shí)候(編譯時(shí))就是常量的,而不能在運(yùn)行時(shí)傳給它;
3、DllImport 特性是密封的,我們不能繼承它或修改它的什么邏輯,到達(dá)運(yùn)行時(shí)得到與平臺(tái)匹配的string?dllName的值 ;
?
Pinvoke的多平臺(tái)解決方案
1、繞過(guò)DllImport
InteropDotNet
這是開(kāi)源在github上的一個(gè)項(xiàng)目,作者使用了LoadLibrary(c.dll) +?GetProcAddress 轉(zhuǎn)換為.Net委托的思想來(lái)完成,對(duì)于c.dll的所有函數(shù)的調(diào)用上,實(shí)際上已經(jīng)完全脫離了.Net提供的DllImport特性,所以不受到上面問(wèn)題2與3的約束,使用本項(xiàng)目,調(diào)用c.dll的.net程序也可是any cpu了。
?
2、筆者的方案
筆者的方案還是沿用.Net的DllImport特性,我們知道DllImport會(huì)幫我們自動(dòng)查找到加載c.dll,然后大概才把DllImport聲明的外部實(shí)現(xiàn)方法與c.dll的函數(shù)地址映射上,如果我們?cè)跍?zhǔn)備調(diào)用c.dll的外部方法之前,通過(guò)LoadLibrary Api把c.dll加載到.net程序里,DllImport會(huì)不會(huì)就不再搜索c.dll而是直接使用?
實(shí)驗(yàn)開(kāi)始
將c.dll對(duì)應(yīng)的x86與x64兩個(gè)版本都放在.net程序的子目錄,構(gòu)造如下:
dotnet.exe
x86\c.dll
x64\c.dll
?
dotnet.exe DllImport聲明如下:
[DllImport("c.dll")]
static extern int MethodC ( );
?
實(shí)驗(yàn)結(jié)果
如果默認(rèn)運(yùn)行,一定會(huì)報(bào)找不到dll文件的異常,因?yàn)镈llImport的本程序目錄或系統(tǒng)目錄或path環(huán)境下都沒(méi)有找到c.dll;
如果我們?cè)谡{(diào)用 MethodC 之前,檢測(cè)當(dāng)前進(jìn)程是32位還是64位,使用windows api 的LoadLibrary 函數(shù)將x86\c.dll或x64\c.dll加載到本進(jìn)程,就不會(huì)報(bào)找不到文件的異常,而且調(diào)用MethodC 也是正常的。
?
實(shí)驗(yàn)總結(jié)
可以一如既往的使用DllImport特性,如果想要any cpu的效果,在調(diào)用外部實(shí)現(xiàn)方法之前,先將它的dll手動(dòng)加載。
以下是我的實(shí)現(xiàn)代碼,在靜態(tài)構(gòu)造器里加載正確的dll就行,支持自動(dòng)x86或x64,而且在asp.net里也能正確找到非托管的dll
static class MQTTAsync{ private const string mqtt3a_dll = "paho-mqtt3a.dll";[DllImport(mqtt3a_dll, CallingConvention = CallingConvention.Cdecl)]public static extern MqttError MQTTAsync_connect(IntPtr handle, ref MQTTAsync_connectOptions options);[DllImport("kernel32")]
private static extern IntPtr LoadLibraryA([MarshalAs(UnmanagedType.LPStr)] string fileName);
static MQTTAsync(){ var dllFile = Path.Combine(Environment.Is64BitProcess ? "x64" : "x86", mqtt3a_dll); if (HttpContext.Current != null){dllFile = Path.Combine("~\\bin", dllFile);dllFile = HttpContext.Current.Server.MapPath(dllFile);}MQTTAsync.LoadLibraryA(dllFile);} }
筆者最近在搞mqtt,使用pinvoke將c版本的mqtt客戶端包裝,項(xiàng)目開(kāi)源在github上,如果你感興趣,可以過(guò)來(lái)看看
https://github.com/xljiulang/Paho.MqttDotnet
原文地址:http://www.cnblogs.com/kewei/p/7011387.html
.NET社區(qū)新聞,深度好文,微信中搜索dotNET跨平臺(tái)或掃描二維碼關(guān)注
總結(jié)
以上是生活随笔為你收集整理的DllImport 自动选择x64或x86 dll的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 来腾讯云开发者实验室 学习.NET
- 下一篇: .Net Core 图片文件上传下载