Incorporando uma dll dentro de outro como um recurso incorporado e, em seguida, chamá-lo de meu código
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?
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.