C#程序(含多個Dll)合并成一個Exe的簡單方法
開發(fā)程序的時候經(jīng)常會引用一些第三方的DLL,然后編譯生成的exe文件就不能脫離這些DLL獨(dú)立運(yùn)行了。
但是,很多時候我們本想開發(fā)一款只需要一個exe就能完美運(yùn)行的小工具。那該怎么辦呢?
下文介紹一種超簡單的方法,不用寫一行代碼就可輕松實(shí)現(xiàn)。
這里我們需要用到一款名為Fody.Costura的工具。Fody.Costura是一個Fody框架下的插件,可通過Nuget安裝到VS工程中。安裝之后,就可以將項目所依賴的DLL(甚至PDB)文件全部打包到EXE文件里。
使用方法
- 在VS中,通過Nuget為目標(biāo)EXE工程安裝Costura.Fody?;蛘咄ㄟ^NuGet控制臺用命令行安裝:Install-Package Costura.Fody -Version 1.3.3
- 重新構(gòu)建項目。
構(gòu)建完成后,到項目的輸出目錄下找到新生成的EXE文件,你同時會發(fā)現(xiàn)輸出目錄下仍然存在那些DLL。不過不用擔(dān)心,這個EXE已經(jīng)能夠獨(dú)立運(yùn)行了。你可以把這些DLL全部刪除后再運(yùn)行EXE試試。
另外,F(xiàn)ody.Costura還支持一些進(jìn)階的特性,例如:
- 臨時程序集文件:在運(yùn)行EXE前自動,自動將DLL從EXE中解壓到文件夾系統(tǒng)中,再通過常規(guī)的方式加載該DLL。
- 合并非托管的DLL:Fody.Costura可以合并非托管的DLL,但是不會自動合。如果你的程序涉及非托管DLL,那么你需要通過修改Fody.Costura的配置文件來顯示地告訴它你想合并哪些非托管的DLL。
- 預(yù)加載DLL:Fody.Costura可以幫助你在程序啟動時預(yù)先加載某些DLL,你甚至可以指定這些DLL的加載順序。
以上這些進(jìn)階特性都需要你通過修改Fody.Costura的配置文件來實(shí)現(xiàn),具體的操作步驟可以參考它的官方文檔。
好了,F(xiàn)ody.Costura的使用方式已經(jīng)介紹完了。如果你對Fody.Costura的實(shí)現(xiàn)原理感到好奇,可以接著往下看。
合并非托管的DLL
<?xml version="1.0" encoding="utf-8"?> <Weavers> <Costura> <Unmanaged32Assemblies> SQLite.Interop </Unmanaged32Assemblies> <Unmanaged64Assemblies> SQLite.Interop </Unmanaged64Assemblies> </Costura> </Weavers>
實(shí)現(xiàn)原理介紹
當(dāng)CLR試圖加載一個程序集但加載失敗時,它會引發(fā)AppDomain.AssemblyResolve事件。我們的程序可以監(jiān)聽這個事件,并且在這個事件的處理函數(shù)中返回這個CLR試圖加載的程序集,從而使程序得以繼續(xù)正常運(yùn)行。
Fody.Costura在構(gòu)建項目時會把EXE引用到的DLL全部嵌入到EXE文件中。當(dāng)程序在運(yùn)行的過程中用到其中某個DLL的時候(此時由于CLR無法找到該DLL文件,導(dǎo)致AppDomain.AssemblyResolve事件被觸發(fā))再從EXE文件的嵌入資源中提取所需的DLL。
下面這兩個函數(shù)就是Fody.Costura實(shí)現(xiàn)這部分邏輯的代碼。
public static void Attach() { var currentDomain = AppDomain.CurrentDomain; currentDomain.AssemblyResolve += (s, e) => ResolveAssembly(e.Name); } public static Assembly ResolveAssembly(string assemblyName) { if (nullCache.ContainsKey(assemblyName)) { return null; } var requestedAssemblyName = new AssemblyName(assemblyName); var assembly = Common.ReadExistingAssembly(requestedAssemblyName); if (assembly != null) { return assembly; } Common.Log("Loading assembly '{0}' into the AppDomain", requestedAssemblyName); assembly = Common.ReadFromEmbeddedResources(assemblyNames, symbolNames, requestedAssemblyName); if (assembly == null) { nullCache.Add(assemblyName, true); // Handles retargeted assemblies like PCL if (requestedAssemblyName.Flags == AssemblyNameFlags.Retargetable) { assembly = Assembly.Load(requestedAssemblyName); } } return assembly; }
可以看到,Attach方法監(jiān)聽了AppDomain.AssemblyResolve事件。當(dāng)CLR無法成功加載某個程序集時, AssemblyResolve事件處理函數(shù)會被執(zhí)行。AssemblyResolve會嘗試通過Common.ReadFromEmbeddedResources方法從已加載的程序集的嵌入資源中獲取目標(biāo)程序集,并返回給CLR。
看到這里,你可能會問,Attach方法是在什么時候執(zhí)行的呢?
其實(shí)是這樣的,對于C#語言來說,CLR隱藏了一個大招——CLR可以在每個模塊(每個程序集都含有一個或多個模塊)加載之前執(zhí)行一些初始化的代碼。但是很遺憾,C#語言無法控制這部分代碼。Fody.Costura則是在內(nèi)部將IL代碼直接注入到EXE程序集內(nèi)部模塊的初始化函數(shù)中,而這部分IL代碼其實(shí)就是執(zhí)行了Attach方法。這樣一來,EXE程序集被加載后,Attach方法就能夠立即得到調(diào)用了。
以上就是Fody.Costura實(shí)現(xiàn)原理的簡單介紹。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持我們。
上一篇:C#的泛型方法解析
欄 目:C#教程
下一篇:解析C#的擴(kuò)展方法
本文標(biāo)題:C#程序(含多個Dll)合并成一個Exe的簡單方法
本文地址:http://mengdiqiu.com.cn/a1/C_jiaocheng/6118.html
您可能感興趣的文章
- 01-10WinForm實(shí)現(xiàn)程序一段時間不運(yùn)行自動關(guān)閉的方法
- 01-10C#實(shí)現(xiàn)將程序鎖定到Win7任務(wù)欄的方法
- 01-10C#使用windows服務(wù)開啟應(yīng)用程序的方法
- 01-10C#一個簡單的定時小程序?qū)崿F(xiàn)代碼
- 01-10C#實(shí)現(xiàn)程序等待延遲執(zhí)行的方法
- 01-10C#使用Mutex簡單實(shí)現(xiàn)程序單實(shí)例運(yùn)行的方法
- 01-10C#計算程序執(zhí)行過程花費(fèi)時間的方法
- 01-10C#實(shí)現(xiàn)將應(yīng)用程序設(shè)置為開機(jī)啟動的方法
- 01-10C#實(shí)現(xiàn)ComboBox控件顯示出多個數(shù)據(jù)源屬性的方法
- 01-10WPF實(shí)現(xiàn)類似360安全衛(wèi)士界面的程序源碼分享


閱讀排行
本欄相關(guān)
- 01-10C#通過反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
- 01-10WinForm實(shí)現(xiàn)仿視頻 器左下角滾動新
- 01-10C#停止線程的方法
- 01-10C#實(shí)現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實(shí)現(xiàn)讀取注冊表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機(jī)閱讀
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 04-02jquery與jsp,用jquery
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10delphi制作wav文件的方法
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-11ajax實(shí)現(xiàn)頁面的局部加載