一个.NET的Windows应用程序可以压缩成一个单一的。

我不太熟悉.NET桌面应用程序(使用Visual Studio 2005 )。 是否有可能从一个单一的.exe文件运行整个应用程序?

是的,您可以使用ILMerge工具。

是。 在.NET中,您可以将整个应用程序封装为一个EXE文件。 只要确保你的解决scheme只有一个Windows应用程序项目(并没有其他项目除了设置)。

由您的.NET项目创build的EXE文件不会是一个独立的可执行文件,但唯一的依赖项将是.NET运行时 (除非您添加对其他DLL程序集的引用)。 如果您使用.NET 2.0(我推荐),运行时预装在较新的PC上,并且在旧机器上安装非常简单快捷(安装程序大约23 MB)。

如果您的应用程序需要引用其他程序集(如数据访问DLL或.NET类库DLL项目),则可以使用其他海报引用的工具之一将您的EXE和所有引用的DLL组合到一个EXE文件中。 但是, 传统的做法会指示简单地将EXE文件和任何相关的DLL一起部署为单独的文件 。 在.NET中,依赖DLL的部署非常简单:只需将它们放在与客户端计算机上的EXE文件相同的文件夹中,即可完成。

将您的应用程序(无论是一个文件还是多个)部署为单一文件安装程序 (setup.EXE或setup.MSI)是一种很好的做法。 .NET自带了部署项目模板,可以很容易地为您创build安装程序。

稍微偏离主题:您可以使用NGEN将.NET应用程序编译为本地EXE,但仍然依赖于.NET运行时。 本地编译的优点是有些东西可以预编译,但是我从来没有看到过这种微小的性能提升值得费心的情况。

今天,在2015年,你可以使用Costura.Fody 。 使用它等于将NuGet包添加到您的项目并重新编译。 我不确定它是否与Visual Studio 2005一样在问题中起作用,但是那也不是2008年。 我已经在我的一些项目中使用过,效果很好。

Fody是一个免费且开源的通用代码编织器 。 它允许对编译后的.NET代码进行后续处理,以增强function。 例如,可以将日志logging添加到每个方法调用等等。在我们的例子中,将依赖的DLL文件打包到程序集资源中,以便在程序运行时期间加载它们,就好像它们是独立的依赖项一样。

有一个名为.NET Reactor的第三方工具可以为你做这个。 我没有使用该工具,所以我不知道它的工作原理。

我已经使用了.NETZ .NET开源可执行打包程序将EXE和DLL文件打包到单个EXE文件中。 这里是一个命令行示例如何将DLL文件打包到一个文件中:

netz -s application.exe foo.dll bar.dll 

如前所述,您可以使用ILMerge 。

但是,如果您使用免费的Phoenix保护器 ,它也可能更容易,它也保护您的代码。

你可以试试NBox工具。

Jeffrey Richter在他的书中摘录了一个带有应用程序域的 ResolveAssembly事件的callback方法,它可以注册以使CLR能够在程序初始化期间find第三方程序集和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框架。

您不能将它分解成多个程序集(通常是Visual Studio解决scheme中的项目)。 无论如何.NET框架是必需的,没有办法 – 这是正确的方法 – embedded它。

是的,你可以创build一个单一的EXE文件。 两篇好文章是:

  1. 如何将所有相关的DLL包含到一个EXE文件中
  2. .NET运行时 – 单个EXE文件

如果程序集只有托pipe代码, ILMerge可以将程序集合到一个程序集中 。 您可以使用命令行应用程序,或者添加对EXE文件的引用并以编程方式进行合并。 对于一个GUI版本,有Eazfuscator和.Netz ,两者都是免费的。 付费应用程序包括BoxedApp和SmartAssembly 。

如果您必须将程序集与非托pipe代码合并,我会build议使用SmartAssembly 。 我从来没有与SmartAssembly打嗝,但与所有其他人。 在这里,它可以将所需的依赖项作为资源embedded到主EXE文件中。

您可以手动执行所有这些操作,无需担心程序集是否被pipe理,或者通过将DLL文件embedded到资源中,然后依靠AppDomain的Assembly ResolveHandler进行混合模式。 这是采用最糟糕的情况的一站式解决scheme,即具有非托pipe代码的程序集。

 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); }; } } 

哪里Program是类名称。 这里的关键是将字节写入文件并从其位置加载。 为了避免鸡与鸡蛋的问题,你必须确保你在访问程序集之前声明处理程序,并且不要在加载(程序集parsing)中访问程序集成员(或实例化任何与程序集有关的东西)部分。 还要注意确保GetMyApplicationSpecificPath()不是任何临时目录,因为临时文件可能会被其他程序或自己删除(而不是在您的程序访问DLL文件时将被删除,但至less是令人讨厌的AppData是一个很好的位置)。 另外请注意,你必须每次写入字节; 您不能仅仅因为DLL文件已经驻留在那里而从位置加载。

对于托pipe的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. 

如果程序集完全不受pipe理,您可以看到这个链接或这个如何加载这样的DLL文件。

我正在使用.net收缩自己,它正是你所需要的。 它将主要和额外程序集(DLL文件)打包成一个可执行映像。

我已经使用了一年了,而且我不回到ILMerge(它总是在某个时候崩溃…)。

.net从产品页面打开主窗口