2011-10-07 80 views
1

我有VS解决方案,其中包含三个项目 - 一个生成一个EXE和另外两个生成DLL。它以这种方式组织,因为DLL包含与其他EXE共享的代码。当我部署EXE时,我希望能够将EXE复制到bin目录并运行,而无需复制额外的DLL。这一点尤其重要,因为bin目录中的其他EXE将针对早期版本的DLL构建。.NET - 在EXE中嵌入引用的DLL,当他们是项目引用

所以我将包含在EXE中的两个项目构建的DLL作为嵌入式资源包含在内,并挂载了AppDomain.CurrentDomain.AssemblyResolve以在EXE运行时加载它们。

而这个工作,除了两件事情:

  1. 每个DLL项目实际上构建两个DLL,一个当配置为“调试”,一个当配置为“释放”。将适当的构建包含在适当的构建中会很好。并且
  2. 如果DLL尚不存在,则构建失败。

这是第二个是真正的问题。如果DLL已经存在,构建运行良好。但是如果缺少DLL,构建失败。因此,如果我先建立没有依赖关系的解决方案,然后将它们添加进去,那么只需添加这些依赖关系即可。

当然,这不起作用。我需要一个从干净检查中建立的解决方案。

那么,有什么想法?

+0

右键单击你的EXE项目,选择“Project dependencies”。 –

回答

1

OK,这里的问题。每个DLL项目都会在其自己的项目文件夹./bin/Release/或./bin/Debug/中创建其DLL的副本。

您不能将它们作为嵌入式资源包含在EXE项目中,因为它们不在EXE项目文件夹中。

当EXE项目完成构建时,它将项目DLL复制到它自己的./bin/Release/或.bin/Debug /中。因为这些复制的文件位于EXE项目文件夹中,所以您可以将它们作为嵌入式资源包含在内,除非您不想这样做,因为它们在构建完成之前不存在,并且构建将在它们不是完成时完成在那里。

解决方法是将DLL的副本放在EXE项目文件夹的其他位置,并将这些副本作为嵌入资源包含在程序集中。我把它们放在./DLLs/中。

然后,以消除手工复制它们的必要性,我添加了一个预生成事件:

COPY $(SolutionDir)\myDLL\bin\$(ConfigurationName)\myDLL.dll $(ProjectDir)\DLLs 

注意这将如何复制Debug或DLL的发行版本,这取决于我正在建设什么。

0

我从来没有使用它,但ILMerge应该能够处理这个问题。在您构建项目之后,将您的可执行文件和DLL传递给ILMerge,并让它为您创建一个主程序集。

http://research.microsoft.com/en-us/people/mbarnett/ilmerge.aspx

+0

ILMerge根本不处理它。 ILMerge所做的是打破许多程序集的内容,并构建一个包含它们的新程序集。这只适用于部分时间。 –

+0

@Jeff:ILMerge确实做了**标题**所说的问题,并且比问题文本讨论的要好。但是,是的,它有一些限制(例如混合模式程序集) –

2

我在某个地方的博客文章中发现了这个解决方案,但是它在一段时间之前就已经失去了链接。

您可以通过手动编辑您的项目文件来添加自定义目标,如下所示。这种方式会自动嵌入所有引用,因此您不必在添加/删除引用后手动执行任何操作。它也允许你为不同的项目有不同的$(ConfigurationName)值。

<Project> 

    ... 

    <!-- Custom target - this includes all dll references as embedded resources during build. --> 
    <Target Name="AfterResolveReferences"> 
    <ItemGroup> 
     <EmbeddedResource Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.dll'"> 
     <LogicalName>%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension)</LogicalName> 
     </EmbeddedResource> 
    </ItemGroup> 
    </Target> 
</Project> 

对于每个嵌入式程序集,嵌入式资源名称将为AssemblyName.dll。如果你想在运行时加载这些DLL,你可以做类似这样的事情:

private void LoadAssemblyFromResource(string assemblyName) 
{ 
    if (!assemblyName.EndsWith(".dll")) 
     assemblyName += ".dll"; 
    Assembly executingAssembly = Assembly.GetExecutingAssembly(); 
    using (Stream stream = executingAssembly.GetManifestResourceStream(assemblyName)) 
    { 
     if (stream == null) 
      throw new ArgumentException("Embedded assembly not found: " + assemblyName, "assemblyName"); 
     byte[] assemblyRawBytes = new byte[stream.Length]; 
     stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length); 
     Assembly.Load(assemblyRawBytes); 
    } 
} 
+0

可能是因为这篇博文有扩展解决方案 - https://habrahabr.ru/post/126790/(俄语) – resnyanskiy