我不太熟悉.NET桌面应用程序(使用Visual Studio 2005)。是否可以从单个.exe文件运行整个应用程序?
今天,在2015年,您可以使用Costura.Fody。使用它相当于将NuGet包添加到您的项目中并重新编译。我不确定它是否像问题中那样适用于Visual Studio 2005,但现在也不是2008年。我在一些项目中使用过它,效果很好。
Fody是一种通用Code Weaver,它是免费和开源的。它允许对编译的.NET代码进行后处理,以增强其功能。例如,可以将日志记录添加到每个方法调用中,等等。在我们的例子中,它将依赖的DLL文件打包到程序集资源中,这样它们就可以在程序运行时加载,就像它们是独立的依赖项一样。
是的。在.NET中,您可以将整个应用程序封装为一个EXE文件只需确保您的解决方案中只有一个Windows应用程序项目(除了设置之外,没有其他项目)。
.NET项目创建的EXE文件将不是一个独立的可执行文件,但它唯一的依赖项将是.NET运行时(除非您添加对其他DLL程序集的引用)。如果您使用.NET 2.0(我建议您这样做),运行时预装在较新的PC上,并且在较旧的计算机上设置非常简单快捷(安装程序大约为23MB)。
如果您的应用程序确实需要引用其他程序集(如数据访问DLL或.NET类库DLL项目),您可以使用此处其他海报引用的工具之一,将您的EXE和所有引用的DLL组合到一个EXE文件中。然而,传统做法会要求简单地将EXE文件和任何依赖的DLL部署为单独的文件。在.NET中,相关DLL的部署非常简单:只需将它们与客户端计算机上的EXE文件放在同一文件夹中,就可以完成。
将应用程序(无论是一个文件还是多个文件)部署为单个文件安装程序(setup.EXE或setup.MSI)是一种很好的做法。.NET提供了部署项目模板,可以很容易地为您创建安装程序。
稍微偏离主题:您可以使用NGEN将.NET应用程序编译为本机EXE,但它仍然依赖于.NET运行时。原生编译的优点是,有些东西可以预先编译,但我从未见过这种微小的性能提升值得麻烦的情况。
现在是2021,对这一点的支持已经有了突飞猛进的改善。
如果你已经跳转到.NET 5(它支持Windows窗体!),你可以制作一个单独的exe文件,甚至可以嵌入本机二进制文件。您必须从命令行运行publish命令,但它将生成一个带有任何配置或内容文件的exe。目标计算机上不需要存在dotnet sdk。
dotnet.exe publish YourProject.csproj -f net5.0 -o package/win-x64 -c Release -r win-x64 /p:PublishTrimmed=true /p:TrimMode=Link /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true
几点注意事项
PublishTrimmed
can be set tofalse
to eliminate code removal in case of heavy reflection use.TrimMode
can be set tocopyused
orlink
. More details here: https://learn.microsoft.com/en-us/dotnet/core/deploying/trim-self-contained.- The
-f
parameter specifies the framework version, i.e. net5.0, etc. - The
-c
parameter is configuration, usuallyRelease
. - The
-r
parameter is the runtime to build for, can bewin-x86
,win-x64
andlinux-x64
. There may be options for ARM as well. - The
-o
parameter is the output folder.
完整参考:https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-publish
有一个名为.NET Reactor可以为您做到这一点。我没有使用过该工具,所以不确定它的效果如何。
我使用了.NETZ.NET开源可执行打包器,用于将EXE和DLL文件打包到单个EXE文件中。以下是如何将DLL文件打包成一个文件的命令行示例:
netz -s application.exe foo.dll bar.dll
Jeffrey Richter在他的书籍摘录,使用可以注册应用程序域的ResolveAssembly事件以启用CLR在程序初始化期间查找第三方程序集和DLL文件:
AppDomain.CurrentDomain.AssemblyResolve += (sender,
args) => {
String resourceName = "AssemblyLoadingAndReflection." +
new AssemblyName(args.Name).Name + ".dll";
using (var stream =
Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)){
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
};
免责声明:我自己没有使用过。据我所知,客户端仍然需要安装.NET框架。
正如前面所说,您可以使用ILMerge。
但是,如果您使用免费的Phoenix保护程序,它也保护您的代码。
我正在使用.netshrink我自己,它完全可以满足您的需要。它将主程序集和额外程序集(DLL文件)打包到一个可执行映像中。
我已经使用它一年了,我不会再使用ILMerge了(它总是在某个时候崩溃…)。
您可以尝试NBox实用程序。
َ
ILMerge可以将程序集合并为一个程序集,前提是该程序集只有托管代码。您可以使用命令行应用程序,或添加对EXE文件的引用并以编程方式合并。对于GUI版本,有Eazfuscator,以及.Netz,两者都是免费的。付费应用程序包括BoxedApp和智能装配。
如果必须将程序集与非托管代码合并,我建议SmartAssembly。我从未用SmartAssembly,但与所有其他程序一起使用。在这里,它可以将所需的依赖项作为资源嵌入到主EXE文件中。
您可以手动完成所有这些操作,无需担心程序集是托管的还是处于混合模式,方法是将DLL文件嵌入资源中,然后依赖AppDomain的assembly<code>ResolveHandler</code>。这是一个一站式解决方案,采用了最坏的情况,即具有非托管代码的程序集。
class Program
{
[STAThread]
static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
string assemblyName = new AssemblyName(args.Name).Name;
if (assemblyName.EndsWith(".resources"))
return null;
string dllName = assemblyName + ".dll";
string dllFullPath = Path.Combine(GetMyApplicationSpecificPath(), dllName);
using (Stream s = Assembly.GetEntryAssembly().GetManifestResourceStream(typeof(Program).Namespace + ".Resources." + dllName))
{
byte[] data = new byte[stream.Length];
s.Read(data, 0, data.Length);
// Or just byte[] data = new BinaryReader(s).ReadBytes((int)s.Length);
File.WriteAllBytes(dllFullPath, data);
}
return Assembly.LoadFrom(dllFullPath);
};
}
}
其中<code>程序</code>是类名。这里的关键是将字节写入文件并从其位置加载。为了避免鸡和蛋的问题,必须确保在访问程序集之前声明处理程序,并且不要访问加载(程序集解析)部分内的程序集成员(或实例化必须处理程序集的任何东西)。此外,请注意确保GetMyApplicationSpecificPath()
不是任何临时目录,因为其他程序或您自己可能会试图擦除临时文件(并不是说当您的程序访问DLL文件时会删除它,但至少它很麻烦。AppData是一个很好的位置)。还要注意,每次都必须写入字节;不能仅仅因为DLL文件已经驻留在该位置就从该位置加载。
对于托管DLL文件,您不需要写入字节,而是直接从DLL文件的位置加载,或者只需读取字节并从内存加载程序集。像这样或那样:
using (Stream s = Assembly.GetEntryAssembly().GetManifestResourceStream(typeof(Program).Namespace + ".Resources." + dllName))
{
byte[] data = new byte[stream.Length];
s.Read(data, 0, data.Length);
return Assembly.Load(data);
}
// Or just
return Assembly.LoadFrom(dllFullPath); // If location is known.
是的,您可以将dotnetwindows应用程序压缩为一个.exe文件。
您只需遵循以下流程:
- Goto Manage NuGet Packages right clicking on your project.
- Install Costura.Fody
- Clean Debug folder inside the bin folder(Delete all files and folder).
- Run the project.
- Goto debug folder, then to app.publish folder, you will get a single exe file here.
VS2022净6.0。
在PS1文件中使用此命令(例如,调用文件publishSingleFile.PS1):
$startFolder = $PSScriptRoot
$container = $startFolder + "/SingleFileExe"
dotnet publish --runtime win-x86 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true --output $container
然后将文件放在projectName.sln文件的同一文件夹中。右键点击ps1文件,然后选择“使用powershell运行”(如果不可用,您必须首先在窗口上启用powershell),这将在您的项目中创建一个名为“SingleFileExe”的文件夹,其中包含您的单个文件。
您可以删除projectName.xml和projectName.pdb文件。您将拥有包含所有内容的projectName.exe文件。
干杯
- winforms
- combobox
- fogbugz
- java
- date
- internationalization
- asp.net
- iis
- url-rewriting
- urlrewriter
- c#
- enums
- ocaml
- haxe
- algorithm
- string
- viewstate
- .net
- c++
- c
- symbol-table
- mysql
- database
- postgresql
- licensing
- migration
- vb.net
- vb6
- declaration
- vb6-migration
- python
- psycopg2
- backup
- vmware
- virtualization
- gnu-screen
- authentication
- desktop
- excel
- xll
- cultureinfo
- regioninfo
- oracle
- client
- session
- download
- html
- virtual
- constructor
- scenarios
- perl
- full-text-search
- javascript
- ajax
- testing
- oop
- inheritance
- vim
- encapsulation
- information-hiding