carregamento DLL de 32 ou 64 bits de código Net gestão
Pergunta
Eu tenho uma DLL não gerenciada (o scilexer.dll de editor de código Scintilla, usado por Scintilla.Net de CodePlex ) que é carregado a partir de uma aplicação de gestão calha do componente Scintilla.Net. As janelas conseguiu aplicativo é executado sem problemas em ambos os ambientes de 32 e 64 bits, mas eu preciso para criar instalações diferentes que usa o 64 ou o 32 scilexer.dll.
Existe uma maneira de distribuir os dois DLLs em 32 e formato de 64 bit para que o carregador DLL das cargas do .NET Framework a DLL não gerenciada no formato de 32 ou 64 bits, dependendo alguma opção config ou algum "nome mágico caminho "coisas?
Solução
P / Invoke usa LoadLibrary para DLLs de carga, e se já existe uma biblioteca carregado com um determinado nome, LoadLibrary irá devolvê-lo. Então, se você pode dar a ambas as versões da DLL o mesmo nome, mas colocá-los em diretórios diferentes, você pode fazer algo como isto apenas uma vez antes de sua primeira chamada para uma função de scilexer.dll, sem a necessidade de duplicar os seus declarações extern:
string platform = IntPtr.Size == 4 ? "x86" : "x64";
string dll = installDir + @"\lib-" + platform + @"\scilexer.dll";
if (LoadLibrary(dll) == IntPtr.Zero)
throw new IOException("Unable to load " + dll + ".");
Outras dicas
Infelizmente, eu não sei nada sobre esse DLL particular. No entanto, quando você faz o P / Invoke si mesmo, e você pode lidar com um pouco de duplicação, é possível criar um proxy para cada plataforma.
Por exemplo, suponha que você tenha o seguinte interface, que deve ser executada até uma DLL de 32 ou 64 bits:
public interface ICodec {
int Decode(IntPtr input, IntPtr output, long inputLength);
}
Você cria os proxies:
public class CodecX86 : ICodec {
private const string dllFileName = @"Codec.x86.dll";
[DllImport(dllFileName)]
static extern int decode(IntPtr input, IntPtr output, long inputLength);
public int Decode(IntPtr input, IntPtr output, long inputLength) {
return decode(input, output, inputLength);
}
}
e
public class CodecX64 : ICodec {
private const string dllFileName = @"Codec.x64.dll";
[DllImport(dllFileName)]
static extern int decode(IntPtr input, IntPtr output, long inputLength);
public int Decode(IntPtr input, IntPtr output, long inputLength) {
return decode(input, output, inputLength);
}
}
E, finalmente, fazer uma fábrica que escolhe o caminho certo para você:
public class CodecFactory {
ICodec instance = null;
public ICodec GetCodec() {
if (instance == null) {
if (IntPtr.Size == 4) {
instance = new CodecX86();
} else if (IntPtr.Size == 8) {
instance = new CodecX64();
} else {
throw new NotSupportedException("Unknown platform");
}
}
return instance;
}
}
Como as DLLs são carregados preguiçosamente a primeira vez que eles estão sendo invocado, isso realmente funciona, apesar de cada plataforma apenas ser capaz de carregar a versão que é nativo a ele. Consulte este artigo para uma explicação mais detalhada.
O melhor que eu vim acima com é o seguinte:
- Distribuir a minha candidatura com duas DLLs nomeados 64 ou 32
- No código de inicialização principal incluem o seguinte:
File.Delete(Application.StartupPath + @"\scilexer.dll"); { // Check for 64 bit and copy the proper scilexer dll if (IntPtr.Size == 4) { File.Copy(Application.StartupPath + @"\scilexer32.dll", Application.StartupPath + @"\scilexer.dll"); } else { File.Copy(Application.StartupPath + @"\scilexer64.dll", Application.StartupPath + @"\scilexer.dll"); } }
Você pode colocar a dll no system32. A 32 bit em syswow64 e 64 bits no system32 real. Para 32 aplicativo bit, quando thay acesso System32 eles são redirecionados para Syswow64.
Você pode criar uma entrada no registro. A chave software tem uma subchave denominada Wow6432Node que a aplicação de 32 bits ver como a chave de software.
Aqui está o que instalador PowerShell faz .
DLLs não gerenciados podem ser instalados no GAC lado-a-lado com os seus homólogos gerenciados. Este artigo deve explicar como ele funciona.