Incorporando uma dll dentro de outro como um recurso incorporado e, em seguida, chamando-o do meu código

Eu tenho uma situação onde eu tenho uma DLL que estou criando que usa outra DLL de terceiros, mas eu preferiria ser capaz de construir a DLL de terceiros em minha DLL em vez de ter que manter os dois juntos, se possível.

Isso com C # e .NET 3.5.

A maneira que eu gostaria de fazer isso é armazenar a DLL de terceiros como um recurso incorporado que, em seguida, coloque no local apropriado durante a execução da primeira DLL.

A maneira que eu originalmente planejei fazer isso é escrevendo código para colocar a DLL de terceiros no local especificado por System.Reflection.Assembly.GetExecutingAssembly().Location.ToString() menos o último /nameOfMyAssembly.dll . Eu posso salvar com sucesso o terceiro .DLL neste local (que acaba sendo

C: \ Documents and Settings \ meuNome_Usuário \ Configurações locais \ Dados de aplicativos \ assembly \ dl3 \ KXPPAX6Y.ZCY \ A1MZ1499.1TR \ e0115d44 \ 91bb86eb_fe18c901

), mas quando eu chego à parte do meu código que exige essa DLL, ela não consegue encontrá-lo.

Alguém tem alguma idéia do que eu preciso fazer de diferente?

Depois de incorporar o assembly de terceiros como um recurso, adicione o código para assinar o evento AppDomain.AssemblyResolve do domínio atual durante a boot do aplicativo. Esse evento é acionado sempre que o subsistema Fusion do CLR não consegue localizar um assembly de acordo com as probing (políticas) em vigor. No manipulador de events para AppDomain.AssemblyResolve , carregue o recurso usando Assembly.GetManifestResourceStream e alimente seu conteúdo como uma matriz de bytes na sobrecarga Assembly.Load correspondente. Abaixo está como uma tal implementação poderia parecer em 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; } }; 

onde StreamToBytes pode ser definido como:

 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(); } } 

Finalmente, como alguns já mencionaram, o ILMerge pode ser outra opção a ser considerada, embora um pouco mais envolvida.

No final, fiz isso quase exatamente da maneira sugerida pelo raboof (e semelhante ao que o dgvid sugeriu), exceto com algumas pequenas alterações e algumas omissões corrigidas. Eu escolhi esse método porque ele estava mais próximo do que eu estava procurando e não exigia o uso de qualquer executável de terceiros e tal. Isso funciona muito bem!

Isto é o que meu código acabou parecendo:

EDIT: Eu decidi mover essa function para outro assembly para que eu pudesse reutilizá-lo em vários arquivos (eu só passo em Assembly.GetExecutingAssembly ()).

Esta é a versão atualizada que permite que você passe na assembly com as dlls incorporadas.

embeddedResourcePrefix é o caminho da string para o recurso incorporado, geralmente será o nome do assembly seguido por qualquer estrutura de pasta que contenha o recurso (por exemplo, “MyComapny.MyProduct.MyAssembly.Resources” se a dll estiver em uma pasta chamada Resources no projeto ). Ele também assume que a dll tem uma extensão .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(); } } 

Existe uma ferramenta chamada IlMerge que pode realizar isso: http://research.microsoft.com/~mbarnett/ILMerge.aspx

Então você pode apenas criar um evento de compilation semelhante ao seguinte.

Set Path = “C: \ Arquivos de Programas \ 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 \ Release \ LevelLibrary.dll

Eu tive sucesso fazendo o que você está descrevendo, mas como a DLL de terceiros também é um assembly .NET, eu nunca a escrevo em disco, apenas carrego da memory.

Eu recebo o assembly de recurso incorporado como uma matriz de bytes da seguinte forma:

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

Então eu carrego os dados com Assembly.Load ().

Por fim, adiciono um manipulador a AppDomain.CurrentDomain.AssemblyResolve para retornar meu assembly carregado quando o carregador de tipos o procura.

Veja o .NET Fusion Workshop para detalhes adicionais.

Você pode conseguir isso facilmente usando o Netz , um .NET Executables Compressor & Packer.

Em vez de gravar o assembly no disco, você pode tentar fazer o Assembly.Load (byte [] rawAssembly) onde você cria rawAssembly a partir do recurso incorporado.