我对.NET桌面应用程序不太熟悉(使用Visual Studio 2005)。是否可以从单个.exe文件运行整个应用程序?
答案 0 :(得分:32)
是的,您可以使用ILMerge工具。
答案 1 :(得分:8)
是。在.NET中,您可以将整个应用程序封装为单个EXE文件。只需确保您的解决方案中只有一个Windows应用程序项目(除设置外没有其他项目)。
.NET项目创建的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附带了可以非常轻松地为您创建安装程序的部署项目模板。
稍微偏离主题:您可以使用NGEN将.NET应用程序编译为本机EXE,但它仍然依赖于.NET运行时。本机编译的优点是可以预编译一些东西,但我从未见过这种微小的性能提升值得打扰的情况。
答案 2 :(得分:5)
有一个名为.NET Reactor的第三方工具可以为您执行此操作。我没有使用过该工具,因此不确定它的工作情况。
答案 3 :(得分:5)
我使用.NETZ .NET开源可执行文件打包程序将EXE和DLL文件打包到单个EXE文件中。以下是如何将DLL文件打包到一个文件中的命令行示例:
netz -s application.exe foo.dll bar.dll
答案 4 :(得分:2)
如上所述,您可以使用ILMerge。
但是,如果您使用the free Phoenix protector,这也可能更容易,这也可以保护您的代码。
答案 5 :(得分:2)
现在是 2021 年,对此的支持已经突飞猛进。
如果您已跳转到 .NET 5(支持 Windows 窗体!),您可以制作一个甚至嵌入本机二进制文件的单个文件 exe。您必须从命令行运行发布命令,但它会生成一个带有任何配置或内容文件的单个 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
可以设置为 false
以在大量反射使用的情况下消除代码删除。TrimMode
可以设置为 copyused
或 link
。更多详情请访问:https://docs.microsoft.com/en-us/dotnet/core/deploying/trim-self-contained。-f
参数指定框架版本,即 net5.0 等。-c
参数是配置,通常是 Release
。-r
参数是要为其构建的运行时,可以是 win-x86
、win-x64
和 linux-x64
。也可能有 ARM 的选项。-o
参数是输出文件夹。完整参考:https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish
答案 6 :(得分:1)
您可以尝试使用NBox实用程序。
答案 7 :(得分:1)
Jeffrey Richter在他的book excerpt中写道,可以注册一个带有application domain’s 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框架。
答案 8 :(得分:0)
您不能将其拆分为多个程序集(通常是Visual Studio解决方案中的项目)。无论如何都需要.NET Framework,没有办法 - 而且这是正确的方法 - 嵌入它。
答案 9 :(得分:0)
是的,您可以创建一个EXE文件。两篇好文章是:
答案 10 :(得分:0)
ILMerge可以将程序集组合到一个程序集中。您可以使用命令行应用程序,或添加对EXE文件的引用并以编程方式合并。对于GUI版本,有Eazfuscator和.Netz,两者都是免费的。付费应用包括BoxedApp和SmartAssembly。
如果必须使用非托管代码合并程序集,我建议SmartAssembly。我从未与SmartAssembly打嗝,但与其他所有人打嗝。在这里,它可以将所需的依赖项作为资源嵌入到主EXE文件中。
您可以手动执行所有操作,无需担心程序集是否受管理或处于混合模式,方法是将DLL文件嵌入资源中,然后依赖AppDomain的程序集ResolveHandler
。这是采用最坏情况的一站式解决方案,即具有非托管代码的程序集。
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
是类名。这里的关键是将字节写入文件并从其位置加载。为了避免鸡与蛋的问题,你必须确保在访问程序集之前声明处理程序,并且在加载(程序集解析)中不访问程序集成员(或实例化必须处理程序集的任何内容)部分。还要注意确保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.
答案 11 :(得分:0)