2011-10-07 85 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