如何将指定关联DLL与C# WinForms程序合并为单个EXE?
问题
我有一个包含两个C#项目的解决方案:一个WinForms应用程序(exe)和一个类库(dll),同时引用了多个外部DLL。希望将自有项目的输出合并为单个exe文件,同时保留其他外部DLL独立存在,文件结构变化如下:
原结构:
- myApp.exe
- myLib.dll
- externalLib1.dll
- externalLib2.dll
- ...
目标结构:
- myMergedAppAndLib.exe
- externalLib1.dll
- externalLib2.dll
- ...
已知限制:
- ILMerge已被弃用,不确定是否支持只合并自有项目而排除外部DLL
- Visual Studio的“生成单个文件”发布选项会合并所有外部DLL,不符合需求
- 无法合并两个自有项目,因为该类库还要给第三个WinForms项目使用
可行方案
完全可以实现需求,以下是几种实用的实现方式:
方法1:使用ILRepack(ILMerge的开源替代工具)
ILRepack是专门用于合并.NET程序集的开源工具,支持选择性合并指定程序集,完美匹配你的需求。
操作步骤:
- 安装工具:可以通过NuGet安装
ILRepack包,或者直接下载ILRepack可执行文件 - 执行合并命令:
直接指定仅合并自有项目的exe和dll,未提及的外部DLL会自动保留为独立文件:
也可以显式排除外部DLL(避免误合并):ILRepack /out:myMergedAppAndLib.exe myApp.exe myLib.dllILRepack /out:myMergedAppAndLib.exe myApp.exe myLib.dll /exclude:externalLib1.dll /exclude:externalLib2.dll - 执行完成后,输出目录会生成
myMergedAppAndLib.exe,外部DLL保持独立存在。
方法2:将类库嵌入为资源并手动加载
把myLib.dll作为嵌入资源打包进WinForms项目,程序启动时从资源中加载该类库,无需依赖外部的myLib.dll文件。
操作步骤:
- 在WinForms项目中添加对
myLib.dll的引用,将引用的复制本地属性设置为False - 将
myLib.dll文件添加到WinForms项目中,设置其生成操作为嵌入的资源 - 在
Program.cs的入口方法前添加程序集解析逻辑:using System.Reflection; [STAThread] static void Main() { // 注册程序集解析事件,按需从嵌入资源加载myLib AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { var assemblyName = new AssemblyName(args.Name).Name + ".dll"; // 替换为你的WinForms项目实际命名空间 var resourceName = $"YourWinFormsNamespace.{assemblyName}"; using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) { if (stream == null) return null; var assemblyBytes = new byte[stream.Length]; stream.Read(assemblyBytes, 0, assemblyBytes.Length); return Assembly.Load(assemblyBytes); } }; Application.SetHighDpiMode(HighDpiMode.SystemAware); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } - 编译后生成的exe已包含
myLib.dll的内容,外部DLL仍保持独立。
方法3:通过MSBuild任务自动合并
在WinForms项目的.csproj文件中添加MSBuild任务,实现编译完成后自动执行合并,无需手动操作命令行。
操作步骤:
- 通过NuGet安装
ILRepack.MSBuild.Task包 - 编辑WinForms项目的
.csproj文件,添加以下配置:<Target Name="ILRepack" AfterTargets="Build"> <ItemGroup> <InputAssemblies Include="$(OutputPath)myApp.exe" /> <InputAssemblies Include="$(OutputPath)myLib.dll" /> </ItemGroup> <ILRepack OutputFile="$(OutputPath)myMergedAppAndLib.exe" InputAssemblies="@(InputAssemblies)" CopyDependencies="false" <!-- 不复制外部依赖,保留独立文件 --> AllowDuplicateResources="true" /> </Target> - 编译项目时,会自动在输出目录生成合并后的exe文件。
内容的提问来源于stack exchange,提问作者Thomas853
相关产品推荐
相关产品推荐

