ILMerge生成的程序集不会运行,虽然日志输出报告没有错误 - 为什么会这样?

时间:2011-11-16 21:11:58

标签: .net ilmerge

我正在为一个新项目测试ILMerge,虽然.exe文件似乎是正确创建的,但它不会运行。

我已经通过.msi安装程序(在http://www.microsoft.com/download/en/confirmation.aspx?id=17630找到)安装了ILMerge,并且正在使用批处理文件运行测试项目。下面是批处理文件,以及运行后的后续输出日志。所有日志中都显示正常,未报告错误。我正在为这个测试项目运行.NET framework 4.0。

当我尝试运行.exe时,它失败并带有标准的“此程序已停止工作”。

我已经读过有些人在运行.NET 4时遇到了问题,但我认为我已经添加了正确的参数来处理这个问题。无论我是否添加了.NET 4 args,我都会得到相同的结果。

任何人都可以看到为什么会这样吗?提前谢谢。

批处理文件

REM Clear directory first

CD C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\CombinedDLL

DEL . /s/q

REM Change dir to iLMerge install (installed via msi installer) 
REM Installer Download: http://www.microsoft.com/download/en/confirmation.aspx?id=17630

CD C:\Program Files (x86)\Microsoft\ILMerge\

REM Combine assemblies with logging

ilmerge.exe /lib:"C:\Windows\Microsoft.NET\Framework\v4.0.30319" /lib:"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies" /t:exe /log:C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\CombinedDLL\MergeLog.txt /target:winexe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework\v4.0.30319 /out:C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\CombinedDLL\CombinedDLL.exe C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\TestILMerge.exe C:\WORKING\DIR\TestILMerge\TestDLL2\bin\Debug\TestDLL2.dll C:\WORKING\DIR\TestILMerge\TestDLL3\bin\Debug\TestDLL3.dll

日志输出:

ILMerge version 2.11.1103.0
Copyright (C) Microsoft Corporation 2004-2006. All rights reserved.
ILMerge /lib:C:\Windows\Microsoft.NET\Framework\v4.0.30319 /lib:C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies /t:exe /log:C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\CombinedDLL\MergeLog.txt /target:winexe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework\v4.0.30319 /out:C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\CombinedDLL\CombinedDLL.exe C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\TestILMerge.exe C:\WORKING\DIR\TestILMerge\TestDLL2\bin\Debug\TestDLL2.dll C:\WORKING\DIR\TestILMerge\TestDLL3\bin\Debug\TestDLL3.dll 
Set platform to 'v4', using directory 'C:\Windows\Microsoft.NET\Framework\v4.0.30319' for mscorlib.dll
Running on Microsoft (R) .NET Framework v2.0.50727
mscorlib.dll version = 2.0.0.0
The list of input assemblies is:
    C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\TestILMerge.exe
    C:\WORKING\DIR\TestILMerge\TestDLL2\bin\Debug\TestDLL2.dll
    C:\WORKING\DIR\TestILMerge\TestDLL3\bin\Debug\TestDLL3.dll
Trying to read assembly from the file 'C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\TestILMerge.exe'.
    Successfully read in assembly.
    There were no errors reported in TestILMerge's metadata.
Trying to read assembly from the file 'C:\WORKING\DIR\TestILMerge\TestDLL2\bin\Debug\TestDLL2.dll'.
    Successfully read in assembly.
    There were no errors reported in TestDLL2's metadata.
Trying to read assembly from the file 'C:\WORKING\DIR\TestILMerge\TestDLL3\bin\Debug\TestDLL3.dll'.
    Successfully read in assembly.
    There were no errors reported in TestDLL3's metadata.
Checking to see that all of the input assemblies have a compatible PeKind.
    TestILMerge.PeKind = ILonly, Requires32bits
    TestDLL2.PeKind = ILonly
    TestDLL3.PeKind = ILonly
All input assemblies have a compatible PeKind value.
Using assembly 'TestILMerge' for assembly-level attributes for the target assembly.
Merging assembly 'TestILMerge' into target assembly.
Merging assembly 'TestDLL2' into target assembly.
Merging assembly 'TestDLL3' into target assembly.
Copying 2 Win32 Resources from assembly 'TestILMerge' into target assembly.
Transferring entry point 'TestILMerge.Program.Main(System.String[])' from assembly 'TestILMerge' to assembly 'CombinedDLL'.
    There were no errors reported in the target assembly's metadata.
ILMerge: Writing target assembly 'C:\WORKING\DIR\TestILMerge\TestILMerge\bin\Debug\CombinedDLL\CombinedDLL.exe'.
Location for referenced assembly 'mscorlib' is 'C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll'
    There were no errors reported in  mscorlib's metadata.
ILMerge: Done.

更新:这是反汇编 - 看起来像我期望的那样

Dissassembly

enter image description here

更新2

我发现如果我从另一个项目引用并且用作程序集而不是独立的可执行文件,该组件可以工作。

5 个答案:

答案 0 :(得分:9)

如果您编写了所有要合并的程序集,ILMerge会很棒,而且您知道它们都没有对程序集组织做出假设。但在许多情况下(尤其是涉及重度反射或动态语言运行时的情况),ILMerge只是不起作用。有时事情以令人惊讶和神秘的方式失败。

当ILMerge失败时,Jeffrey Richter有a more reliable way to get applications with multiple DLL dependencies to be deployable as a single assembly

这不是没有权衡,但即使是ILMerge的作者Mike Barnett也在博客文章的评论帖中说:“作为ILMerge的作者,我觉得这太棒了!如果我知道这个,我从来没有写过ILMerge。“

如果你可以使用里希特的方法,你就不会绊倒大多数反射或动力陷阱。

实施步骤

  1. 将您依赖的所有第三方程序集嵌入到应用程序的资源中。
  2. AppDomain.CurrentDomain.AssemblyResolve活动中注册ResolveEventHandler
  3. 使用您在Resources中存储的程序集调用处理程序时,请加载程序集。
  4. 您按照以下方式执行第3部分:

    var resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name);
    return Assembly.Load(new BinaryReader(resourceStream).ReadBytes(int.MaxValue));
    

答案 1 :(得分:4)

可以在Visual Studio 2010中轻松创建完全独立的可执行文件,此方法根本不需要ILMerge。

步骤:

  • 创建一个空的可执行项目
  • 将您的DLL(和您的EXE文件)添加为资源。 (在解决方案资源管理器中右键单击项目名称,属性,资源,添加资源)

此Visual Studio将自动创建一个名为Resources的新类,您必须在新项目中使用它。

  • 将以下两种方法添加到Program.cs中,以使最终的应用程序正常工作。

然后你必须使用Visual Studio编译程序,就是这样。

static void Main(string[] args)
{
    // Load your assembly with the entry point from resources:
    Assembly start = Assembly.Load((byte[]) Properties.Resources.NameOfDllOrExeInYourResources);
    Type t = start.GetType("Foo.Bar.Program");

    // Install the resolver event
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

    // Find Program.Main in the loaded assembly
    MethodInfo m = t.GetMethod("Main", BindingFlags.Public | BindingFlags.Static);

    // Launch the application
    m.Invoke(null, new object[] { args });
}

static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    string assemblyName = new AssemblyName(args.Name).Name.Replace('.', '_');

    // Locate and load the contents of the resource 
    byte[] assemblyBytes = (byte[]) Properties.Resources.ResourceManager.GetObject(assemblyName, Properties.Resources.Culture);

    // Return the loaded assembly
    return Assembly.Load(assemblyBytes);
}

答案 2 :(得分:1)

也许这不会解决您的问题,但我认为验证您的ilmerged可执行文件不包含对合并库的引用是很好的。您可以使用ILSpy(http://wiki.sharpdevelop.net/ILSpy.ashx)进行检查 - 只需反汇编您的ilmerged可执行文件并在树中检查引用中的程序集。 ILSpy还可以帮助您验证您的ilmerged可执行文件是否包含来自合并程序集的类。

下一个选项也可以在尝试启动ilmerged应用程序时调试程序集绑定(http://msdn.microsoft.com/en-us/library/e74a18c4%28v=VS.100%29.aspx)。

您还可以尝试调试ilmerged程序集,以确定应用程序是否在调用main函数之前崩溃,或者可能在某处内部崩溃。

我认为识别无法找到的特定类型可以帮助解决问题。

答案 3 :(得分:0)

检查您的事件查看器是否有任何详细的错误消息。

包裹void Main(string args[])方法的正文
try
{
...
}
catch (Exception ex)
{
  Console.WriteLine(ex.ToString());
}

还可以尝试将平台目标更改为x86。

如果指定/lib,则不需要在/targetplatform/targetplatform:v4命令行开关上指定.net框架目录。

答案 4 :(得分:0)

经过几个小时的斗争,我删除了我的项目文件夹,并从git做了一个新的拉。我尝试清理并重建我的项目,同样的问题。然后我比较了我的同事项目和 * \ Library \ Build * 内部,我错过了 结果 文件夹。添加文件夹 \ Library \ Build \ Results 后,我的解决方案构建没有错误。