如何在 wpf/winforms 应用程序中将 DLL 与 .exe 结合(带图片) [英] How to combine DLLs with .exe inside of a wpf / winforms application (with pictures)
问题描述
如何将多个dll合并到主.exe文件中?(不使用第三方程序)
更新 3
.Net 内置了这个
5 - 现在到代码部分:
首先导入这个命名空间
vb.net
导入 System.Reflection
c#
使用 System.Reflection;
在构造函数(vb中的[Sub New])中添加这段代码
Vb.net
Public Sub New()AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf OnResolveAssembly结束子
c#.net
公共应用程序(){AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;}
然后添加OnResolveAssembly
函数
vb.net
''' <摘要>''' 告诉程序它正在寻找的程序集位于嵌入式资源中''' <see cref="Assembly.GetManifestResourceNames"/>获取所有资源的函数''' </summary>''' <param name="sender"></param>''' <param name="args"></param>''' <returns></returns>''' <remarks>请注意,如果 dll 与应用程序位于同一文件夹中(有时),则不会触发此事件</remarks>私有共享函数 OnResolveAssembly(sender As Object, args As ResolveEventArgs) As Assembly尝试'获取主程序集Dim parentAssembly = Assembly.GetExecutingAssembly()'args.Name 将是这样的'[ MahApps.Metro, Version=1.1.3.81, Culture=en-US, PublicKeyToken=null ]'所以我们采用程序集的名称 (MahApps.Metro) 然后向其中添加 (.dll)Dim finalname = args.Name.Substring(0, args.Name.IndexOf(","c)) &.dll"'在这里我们搜索我们的 dll 的资源并获得第一个匹配项Dim ResourcesList = parentAssembly.GetManifestResourceNames()Dim OurResourceName As String = Nothing'(您可以将其替换为 [Find] 或 [First] 等 LINQ 扩展名)For i As Integer = 0 To ResourcesList.Count - 1昏暗名称 = ResourcesList(i)如果 name.EndsWith(finalname) 然后'获取名称然后关闭循环以获取第一个出现的值我们的资源名称 = 名称退出万一下一个如果不是 String.IsNullOrWhiteSpace(OurResourceName) 然后'获取代表我们资源的流,然后将其加载为字节使用流作为流 = parentAssembly.GetManifestResourceStream(OurResourceName)'在 vb.net 中使用 [New Byte(stream.Length - 1)]'在 c#.net 中使用 [ new byte[stream.Length];]Dim block As Byte() = New Byte(stream.Length - 1) {}流.读取(块,0,块.长度)返回 Assembly.Load(块)结束使用别的什么都不返回万一Catch ex 作为例外什么都不返回结束尝试结束函数
c#.net
////<摘要>///告诉程序它正在寻找的程序集位于嵌入的资源中///<see cref="Assembly.GetManifestResourceNames"/>获取所有资源的函数///</总结>///<param name="sender"></param>//////<returns></returns>///<remarks>请注意,如果 dll 与应用程序位于同一文件夹中(有时),则不会触发此事件</remarks>私有静态程序集 OnResolveAssembly(对象发送者,ResolveEventArgs args){尝试 {//获取主程序集var parentAssembly = Assembly.GetExecutingAssembly();//args.Name 将是这样的//[ MahApps.Metro, Version=1.1.3.81, Culture=en-US, PublicKeyToken=null ]//所以我们取程序集的名称(MahApps.Metro)然后添加(.dll)到它var finalname = args.Name.Substring(0, args.Name.IndexOf(',')) + ".dll";//在这里我们搜索我们的dll的资源并获得第一个匹配项var ResourcesList = parentAssembly.GetManifestResourceNames();字符串 OurResourceName = null;//(您可以将其替换为 [Find] 或 [First] 等 LINQ 扩展名)for (int i = 0; i <= ResourcesList.Count - 1; i++) {var name = ResourcesList(i);if (name.EndsWith(finalname)) {//获取名称然后关闭循环以获取第一个出现的值我们的资源名称 = 名称;休息;}}if (!string.IsNullOrWhiteSpace(OurResourceName)) {//获取一个代表我们资源的流,然后将其作为字节加载使用(流流 = parentAssembly.GetManifestResourceStream(OurResourceName)){//在 vb.net 中使用 [New Byte(stream.Length - 1)]//在c#.net中使用[新字节[stream.Length];]字节 [] 块 = 新字节 [流.长度];stream.Read(block, 0, block.Length);返回 Assembly.Load(block);}} 别的 {返回空;}} 捕捉(异常前){返回空;}}
6 - 现在发布应用程序或构建它,您的所有 dll 都将嵌入到单个 EXE 文件中(加载它们有一些额外的毫秒延迟)
更新 DLL
1 - 只需将您的新 dll 拖放到与旧 dll 相同的文件夹中,然后接受覆盖(确保检查 [Build Action = Embedded Resources] AND [Copy To Output Directory = Do not复制])
添加新的 DLL
只需重复步骤 1 =>3
学分:
http://richarddingwall.name/2009/05/14/wpf-how-to-combine-mutliple-assemblies-into-a-single-exe/
*如果您有任何问题,请随时询问
How to combine multiple dlls into the main .exe file? (without using third-party programs)
Update 3
.Net has this built in https://docs.microsoft.com/en-us/dotnet/core/deploying/single-file
Update 2
you don't even have to include the dlls as embedded resources at all, just use Fody.Costura and it will resolve the referenced assemblies and auto-include them
Also if you are using .net core 3+ you can use the Single file executable & Assembly linking features
Update
if you want an easy tool to merge the assemblies without worrying about doing ANY work at all then Fody.Costura is the best choice you have, as all you need to do is just include the dlls and change their Build Action to Embedded Resource and it will work right away.
1 - make a folder that contains all of the Dlls or place them separately as you like
2 - Click on each DLL from the "Solution Explorer" and make sure they have these properties
Build Action = Embedded Resources
Copy To Output Directory = Do not copy
3 - Go to : Project > Properties > References , And make sure every Dll you add has the same name as the assembly like this :
In References :-
In Solution Explorer :-
Note :-
It's Better to Make copy local = True in references as it will give you an updated DLL each time you publish the project
Now at this point you have your DLLs added to the EXE , all is remaining now is to tell the program how to read these DLLs from the EXE (that's why we made build action = Embedded resources)
4 - In Solution Explorer Open your (Application.xaml.vb) file ([App.xaml.cs] in c#)
OR
Go To : Project > Properties > Application > View Application Events
Now in this page we are going to handle the very first event of the application (Construction event) to tell the program how to handle the assemblies we add as DLLs before loading/reading them by using the AssemblyResolve
Event
Check this MSDN page for more Info about the AssemblyResolve Event https://msdn.microsoft.com/en-us/library/system.appdomain.assemblyresolve(v=vs.110).aspx
5 - Now to The code part :
first of all Import this namespace
vb.net
Imports System.Reflection
c#
using System.Reflection;
In the Constructor ([Sub New] in vb) add this code
Vb.net
Public Sub New()
AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf OnResolveAssembly
End Sub
c#.net
public App()
{
AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;
}
Then add the OnResolveAssembly
Function
vb.net
''' <summary>
''' Tells the program that the Assembly it's Seeking is located in the Embedded resources By using the
''' <see cref="Assembly.GetManifestResourceNames"/> Function To get All the Resources
''' </summary>
''' <param name="sender"></param>
''' <param name="args"></param>
''' <returns></returns>
''' <remarks>Note that this event won't fire if the dll is in the same folder as the application (sometimes)</remarks>
Private Shared Function OnResolveAssembly(sender As Object, args As ResolveEventArgs) As Assembly
Try
'gets the main Assembly
Dim parentAssembly = Assembly.GetExecutingAssembly()
'args.Name will be something like this
'[ MahApps.Metro, Version=1.1.3.81, Culture=en-US, PublicKeyToken=null ]
'so we take the name of the Assembly (MahApps.Metro) then add (.dll) to it
Dim finalname = args.Name.Substring(0, args.Name.IndexOf(","c)) & ".dll"
'here we search the resources for our dll and get the first match
Dim ResourcesList = parentAssembly.GetManifestResourceNames()
Dim OurResourceName As String = Nothing
'(you can replace this with a LINQ extension like [Find] or [First])
For i As Integer = 0 To ResourcesList.Count - 1
Dim name = ResourcesList(i)
If name.EndsWith(finalname) Then
'Get the name then close the loop to get the first occuring value
OurResourceName = name
Exit For
End If
Next
If Not String.IsNullOrWhiteSpace(OurResourceName) Then
'get a stream representing our resource then load it as bytes
Using stream As Stream = parentAssembly.GetManifestResourceStream(OurResourceName)
'in vb.net use [ New Byte(stream.Length - 1) ]
'in c#.net use [ new byte[stream.Length]; ]
Dim block As Byte() = New Byte(stream.Length - 1) {}
stream.Read(block, 0, block.Length)
Return Assembly.Load(block)
End Using
Else
Return Nothing
End If
Catch ex As Exception
Return Nothing
End Try
End Function
c#.net
/// <summary>
/// Tells the program that the Assembly its Seeking is located in the Embedded resources By using the
/// <see cref="Assembly.GetManifestResourceNames"/> Function To get All the Resources
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
/// <returns></returns>
/// <remarks>Note that this event won't fire if the dll is in the same folder as the application (sometimes)</remarks>
private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
try {
//gets the main Assembly
var parentAssembly = Assembly.GetExecutingAssembly();
//args.Name will be something like this
//[ MahApps.Metro, Version=1.1.3.81, Culture=en-US, PublicKeyToken=null ]
//so we take the name of the Assembly (MahApps.Metro) then add (.dll) to it
var finalname = args.Name.Substring(0, args.Name.IndexOf(',')) + ".dll";
//here we search the resources for our dll and get the first match
var ResourcesList = parentAssembly.GetManifestResourceNames();
string OurResourceName = null;
//(you can replace this with a LINQ extension like [Find] or [First])
for (int i = 0; i <= ResourcesList.Count - 1; i++) {
var name = ResourcesList(i);
if (name.EndsWith(finalname)) {
//Get the name then close the loop to get the first occuring value
OurResourceName = name;
break;
}
}
if (!string.IsNullOrWhiteSpace(OurResourceName)) {
//get a stream representing our resource then load it as bytes
using (Stream stream = parentAssembly.GetManifestResourceStream(OurResourceName)) {
//in vb.net use [ New Byte(stream.Length - 1) ]
//in c#.net use [ new byte[stream.Length]; ]
byte[] block = new byte[stream.Length];
stream.Read(block, 0, block.Length);
return Assembly.Load(block);
}
} else {
return null;
}
} catch (Exception ex) {
return null;
}
}
6 - now publish the application or build it and all your dlls will be embedded in a single EXE file (with some extra milliseconds delay to load them)
To Update the DLLs
1 - Simply drag and drop your new dll to the Solution Explorer as the same folder as the old dll then accept the override (make sure to check that [Build Action = Embedded Resources] AND [Copy To Output Directory = Do not copy])
To Add New DLLs
just repeat step 1 => 3
Credits :
http://richarddingwall.name/2009/05/14/wpf-how-to-combine-mutliple-assemblies-into-a-single-exe/
*Feel free to ask if you had any problem
这篇关于如何在 wpf/winforms 应用程序中将 DLL 与 .exe 结合(带图片)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!