Incorporando uma dll dentro de outro como um recurso incorporado e, em seguida, chamá-lo de meu código

StackOverflow https://stackoverflow.com/questions/96732

  •  01-07-2019
  •  | 
  •  

Pergunta

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

Este é com C # e .NET 3.5.

A maneira que eu gostaria de fazer isso é armazenar a terceira DLL partido como um recurso incorporado que eu então lugar no local apropriado durante a execução da primeira DLL.

A maneira que eu originalmente planejado para fazer isso é escrever código para colocar o terceiro DLL festa no local especificado pelo System.Reflection.Assembly.GetExecutingAssembly().Location.ToString() menos a última /nameOfMyAssembly.dll. Eu posso com sucesso salvar o terceiro .DLL festa neste local (o que acaba sendo

C: \ Documents and Settings \ myusername \ Local Settings \ Application Data \ assembly \ DL3 \ KXPPAX6Y.ZCY \ A1MZ1499.1TR \ e0115d44 \ 91bb86eb_fe18c901

), mas quando eu chegar à parte do meu código que requer esta DLL, ele não pode encontrá-lo.

Alguém tem alguma idéia sobre o que eu preciso fazer diferente?

Foi útil?

Solução

Uma vez que você tiver incorporado o terceiro conjunto como um recurso, código add subscrever a AppDomain.AssemblyResolve evento do atual domínio durante a aplicação de arranque. Este evento é accionado sempre que o sub-sistema de fusão da CLR não consegue localizar uma montagem de acordo com as políticas de sondagem () em efeito. No manipulador de eventos para AppDomain.AssemblyResolve, carregar o recurso usando Assembly.GetManifestResourceStream e alimentar o seu conteúdo como uma matriz de bytes no correspondente Assembly.Load sobrecarga. Abaixo é como um tal implementação poderia ser semelhante 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 poderia 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á mencionado, ILMerge pode ser outra opção a considerar, embora um pouco mais envolvidos.

Outras dicas

No final, eu fiz isso quase exatamente a maneira Raboof sugeriu (e semelhante ao que dgvid sugerido), exceto com algumas pequenas mudanças e algumas omissões fixos. Eu escolhi este método porque ele era mais próximo do que eu estava procurando, em primeiro lugar e não requerem o uso de quaisquer executáveis ??de terceiros e tal. Ele funciona muito bem!

Este é o meu código acabou parecendo:

EDIT: eu decidi mudar esta função para outra montagem para que eu pudesse reutilizá-lo em vários arquivos (eu só passar em Assembly.GetExecutingAssembly ()).

Esta é a versão actualizada que lhe permite passar na montagem com as DLLs embutidos.

embeddedResourcePrefix é o caminho string para o recurso incorporado, que geralmente será o nome do conjunto seguido de qualquer estrutura da pasta que contém o recurso (por exemplo, "MyComapny.MyProduct.MyAssembly.Resources" se a dll está 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();
        }
    }

Há uma ferramenta chamada ILMerge que pode fazer isso: http://research.microsoft.com /~mbarnett/ILMerge.aspx

Em seguida, você pode apenas fazer um evento de compilação semelhante à seguinte.

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 \ Release \ LevelLibrary.dll

Eu tive sucesso fazendo o que você está descrevendo, mas porque a DLL de terceiros também é uma .NET assembly, eu nunca escrevê-lo para o disco, eu só carregá-lo da memória.

Eu recebo o recurso incorporado montagem como uma matriz de bytes como assim:

        Assembly resAssembly = Assembly.LoadFile(assemblyPathName);

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

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

Finalmente, adicione um manipulador para AppDomain.CurrentDomain.AssemblyResolve para voltar meu carregado montagem quando os olhares Tipo de carregador de TI.

Veja a .NET Fusão Oficina para obter detalhes adicionais.

Você pode conseguir isto notavelmente facilmente usando Netz , um .net NET executáveis ??Compressor & Packer.

Em vez de escrever o conjunto de disco que você pode tentar fazer Assembly.Load (byte [] rawAssembly) onde você cria rawAssembly do recurso incorporado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top