将一个dll作为embedded式资源embedded到另一个dll中,然后从我的代码中调用它

我有一个情况,我有一个DLL我创build使用另一个第三方DLL,但我宁愿能够build立第三方DLL到我的DLL,而不是必须保持在一起,如果可能的话。

这与C#和.NET 3.5。

我想这样做的方式是将第三方DLL作为embedded式资源存储,然后在执行第一个DLL期间放置在适当的位置。

我原本计划这样做的方法是编写代码将第三方DLL放在由System.Reflection.Assembly.GetExecutingAssembly()。Location.ToString()减去最后一个/nameOfMyAssembly.dll指定的位置。 我可以成功地将第三方.DLL保存在此位置(最终(C:\ Documents and Settings \ myUserName \ Local Settings \ Application Data \ assembly \ dl3 \ KXPPAX6Y.ZCY \ A1MZ1499.1TR \ e0115d44 \ 91bb86eb_fe18c901)),但是当我到达需要这个DLL的代码部分时,它找不到它。

有没有人有任何想法,我需要做什么不同?

将第三方程序集作为资源embedded后,请添加代码以在应用程序启动期间订阅当前域的AppDomain.AssemblyResolve事件。 只要CLR的Fusion子系统根据有效的探测(策略)未能find组件,此事件就会触发。 在AppDomain.AssemblyResolve的事件处理程序中,使用Assembly.GetManifestResourceStream加载资源,并将其内容作为字节数组提供给相应的Assembly.Load重载。 下面是一个这样的实现在C#中的样子:

 AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { var resName = args.Name + ".dll"; var thisAssembly = Assembly.GetExecutingAssembly(); using (var input = thisAssembly.GetManifestResourceStream(resName)) { return input != null ? Assembly.Load(StreamToBytes(input)) : null; } }; 

StreamToBytes可以被定义为:

 static byte[] StreamToBytes(Stream input) { var capacity = input.CanSeek ? (int) input.Length : 0; using (var output = new MemoryStream(capacity)) { int readLength; var buffer = new byte[4096]; do { readLength = input.Read(buffer, 0, buffer.Length); output.Write(buffer, 0, readLength); } while (readLength != 0); return output.ToArray(); } } 

最后,正如less数人已经提到的那样, ILMerge可能是另外一个可以考虑的select,虽然涉及更多。

最后,我几乎完全按照raboof的build议(和dgvid的build议类似),除了一些小的修改和一些遗漏修正之外。 我select这种方法是因为它最接近于我最初寻找的内容,并且不需要使用任何第三方可执行文件等。 这很好用!

这是我的代码最终看起来像这样:

编辑:我决定把这个function移到另一个程序集,所以我可以重复使用它在多个文件(我只是通过Assembly.GetExecutingAssembly())。

这是更新的版本,它允许你通过embedded式DLL的程序集。

embeddedResourcePrefix是embedded式资源的stringpath,它通常是程序集的名称,后面是包含资源的任何文件夹结构(例如,如果dll位于项目中名为Resources的文件夹中,则为“MyComapny.MyProduct.MyAssembly.Resources” )。 它还假定该dll具有.dll.resource扩展名。

  public static void EnableDynamicLoadingForDlls(Assembly assemblyToLoadFrom, string embeddedResourcePrefix) { AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { // had to add => try { string resName = embeddedResourcePrefix + "." + args.Name.Split(',')[0] + ".dll.resource"; using (Stream input = assemblyToLoadFrom.GetManifestResourceStream(resName)) { return input != null ? Assembly.Load(StreamToBytes(input)) : null; } } catch (Exception ex) { _log.Error("Error dynamically loading dll: " + args.Name, ex); return null; } }; // Had to add colon } private static byte[] StreamToBytes(Stream input) { int capacity = input.CanSeek ? (int)input.Length : 0; using (MemoryStream output = new MemoryStream(capacity)) { int readLength; byte[] buffer = new byte[4096]; do { readLength = input.Read(buffer, 0, buffer.Length); // had to change to buffer.Length output.Write(buffer, 0, readLength); } while (readLength != 0); return output.ToArray(); } } 

有一个名为IlMerge的工具可以完成这个工作: http ://research.microsoft.com/~mbarnett/ILMerge.aspx

然后你可以做一个类似于下面的构build事件。

Set Path =“C:\ Program Files \ Microsoft \ ILMerge”

ilmerge /out:$(ProjectDir)\Deploy\LevelEditor.exe $(ProjectDir)\ bin \ Release \ release.exe $(ProjectDir)\ bin \ Release \ InteractLib.dll $(ProjectDir)\ bin \ Release \ SpriteLib.dll $(PROJECTDIR)\ BIN \发布\ LevelLibrary.dll

您可以使用Netz ,.net NET Executables Compressor&Packer非常容易地实现这一点。

我已经成功地完成了你正在描述的内容,但是因为第三方DLL也是一个.NET程序集,所以我从来没有把它写到磁盘上,只是从内存中加载它。

我得到的embedded式资源程序集像一个字节数组,如下所示:

  Assembly resAssembly = Assembly.LoadFile(assemblyPathName); byte[] assemblyData; using (Stream stream = resAssembly.GetManifestResourceStream(resourceName)) { assemblyData = ReadBytesFromStream(stream); stream.Close(); } 

然后我用Assembly.Load()加载数据。

最后,我向AppDomain.CurrentDomain.AssemblyResolve添加一个处理程序,以在types加载器查找时返回我加载的程序集。

有关更多详细信息,请参见.NET Fusion Workshop 。

您可以尝试执行Assembly.Load(byte [] rawAssembly),从embedded式资源创buildrawAssembly,而不是将程序集写入磁盘。