puede excepción error ensamblado cargar archivo 0x8007000b c# .net 64bit

c# - excepción - Uso de ensamblados uno al lado del otro para cargar la versión x64 o x32 de una DLL



excepción de hresult 0x8007000b)'' (5)

Eche un vistazo a SetDllDirectory. Lo usé para cargar dinámicamente un ensamblaje spss de IBM para x64 y x86. También resolvió rutas para soporte no ensamblado dll''s cargadas por ensamblajes en mi caso era el caso con spss dll''s.

http://msdn.microsoft.com/en-us/library/ms686203%28VS.85%29.aspx

Tenemos dos versiones de un ensamblaje C ++ administrado, uno para x86 y otro para x64. Este ensamblado es llamado por una aplicación .net cumplida para AnyCPU. Estamos implementando nuestro código a través de una instalación de copia de archivo, y nos gustaría continuar haciéndolo.

¿Es posible utilizar un manifiesto de ensamblaje Side-by-Side para cargar un ensamblaje x86 o x64 respectivamente cuando una aplicación está seleccionando dinámicamente su arquitectura de procesador? ¿O hay otra forma de hacer esto en una implementación de copia de archivo (por ejemplo, no usar el GAC)?


Esta solución también puede funcionar para ensamblajes no gestionados. He creado un ejemplo simple similar al gran ejemplo de Milan Gardian. El ejemplo que creé dinámicamente carga un dll Managed C ++ en un dll C # compilado para la plataforma Any CPU. La solución utiliza el paquete nuget InjectModuleInitializer para suscribirse al evento AssemblyResolve antes de que se carguen las dependencias del ensamblado.

https://github.com/kevin-marshall/Managed.AnyCPU.git


Mi versión, similar a @Milan, pero con varios cambios importantes:

  • Funciona para TODOS los archivos DLL que no se encontraron
  • Se puede encender y apagar
  • AppDomain.CurrentDomain.SetupInformation.ApplicationBase se utiliza en lugar de Path.GetFullPath() porque el directorio actual puede ser diferente, por ejemplo, en escenarios de alojamiento, Excel puede cargar su complemento pero el directorio actual no se establecerá en su archivo DLL.

  • Environment.Is64BitProcess se utiliza en lugar de PROCESSOR_ARCHITECTURE , ya que no debemos depender de qué es el sistema operativo, sino de cómo se inició este proceso: podría haber sido un proceso x86 en un sistema operativo x64. Antes de .NET 4, use IntPtr.Size == 8 lugar.

Llame a este código en un constructor estático de alguna clase principal que se carga antes que todo.

public static class MultiplatformDllLoader { private static bool _isEnabled; public static bool Enable { get { return _isEnabled; } set { lock (typeof (MultiplatformDllLoader)) { if (_isEnabled != value) { if (value) AppDomain.CurrentDomain.AssemblyResolve += Resolver; else AppDomain.CurrentDomain.AssemblyResolve -= Resolver; _isEnabled = value; } } } } /// Will attempt to load missing assembly from either x86 or x64 subdir private static Assembly Resolver(object sender, ResolveEventArgs args) { string assemblyName = args.Name.Split(new[] {'',''}, 2)[0] + ".dll"; string archSpecificPath = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, Environment.Is64BitProcess ? "x64" : "x86", assemblyName); return File.Exists(archSpecificPath) ? Assembly.LoadFile(archSpecificPath) : null; } }


Puede usar la utilidad corflags para forzar a un exe AnyCPU a cargarse como un ejecutable x86 o x64, pero eso no cumple totalmente con el requisito de implementación de copia de archivo a menos que elija qué exe copiar según el objetivo.


Creé una solución simple que puede cargar el ensamblaje específico de la plataforma desde un ejecutable compilado como AnyCPU. La técnica utilizada se puede resumir de la siguiente manera:

  1. Asegúrese de que el mecanismo de carga de ensamblaje .NET predeterminado (motor "Fusion") no pueda encontrar la versión x86 o x64 del ensamblaje específico de la plataforma.
  2. Antes de que la aplicación principal intente cargar el ensamblaje específico de la plataforma, instale un programa de resolución de ensamblaje personalizado en el dominio de la aplicación actual.
  3. Ahora, cuando la aplicación principal necesita el ensamblaje específico de la plataforma, el motor de Fusion se rendirá (debido al paso 1) y llamará a nuestro solucionador personalizado (debido al paso 2); en la resolución personalizada determinamos la plataforma actual y usamos la búsqueda basada en directorio para cargar la DLL apropiada.

Para demostrar esta técnica, adjunto un breve tutorial basado en línea de comandos. Probé los binarios resultantes en Windows XP x86 y luego Vista SP1 x64 (copiando los binarios, al igual que su implementación).

Nota 1 : "csc.exe" es un compilador C-sharp. Este tutorial asume que está en su camino (mis pruebas usaban "C: / WINDOWS / Microsoft.NET / Framework / v3.5 / csc.exe")

Nota 2 : le recomiendo que cree una carpeta temporal para las pruebas y ejecute la línea de comandos (o powershell) cuyo directorio de trabajo actual se establece en esta ubicación, por ejemplo

(cmd.exe) C: mkdir /TEMP/CrossPlatformTest cd /TEMP/CrossPlatformTest

Paso 1 : el ensamblaje específico de la plataforma está representado por una biblioteca de clase C # simple:

// file ''library.cs'' in C:/TEMP/CrossPlatformTest namespace Cross.Platform.Library { public static class Worker { public static void Run() { System.Console.WriteLine("Worker is running"); System.Console.WriteLine("(Enter to continue)"); System.Console.ReadLine(); } } }

Paso 2 : compilamos ensamblajes específicos de plataforma usando comandos simples de línea de comandos:

(cmd.exe from Note 2) mkdir platform/x86 csc /out:platform/x86/library.dll /target:library /platform:x86 library.cs mkdir platform/amd64 csc /out:platform/amd64/library.dll /target:library /platform:x64 library.cs

Paso 3 : El programa principal se divide en dos partes. "Bootstrapper" contiene el punto de entrada principal para el ejecutable y registra una resolución de ensamblado personalizada en el dominio de aplicación actual:

// file ''bootstrapper.cs'' in C:/TEMP/CrossPlatformTest namespace Cross.Platform.Program { public static class Bootstrapper { public static void Main() { System.AppDomain.CurrentDomain.AssemblyResolve += CustomResolve; App.Run(); } private static System.Reflection.Assembly CustomResolve( object sender, System.ResolveEventArgs args) { if (args.Name.StartsWith("library")) { string fileName = System.IO.Path.GetFullPath( "platform//" + System.Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE") + "//library.dll"); System.Console.WriteLine(fileName); if (System.IO.File.Exists(fileName)) { return System.Reflection.Assembly.LoadFile(fileName); } } return null; } } }

"Programa" es la implementación "real" de la aplicación (tenga en cuenta que App.Run fue invocado al final de Bootstrapper.Main):

// file ''program.cs'' in C:/TEMP/CrossPlatformTest namespace Cross.Platform.Program { public static class App { public static void Run() { Cross.Platform.Library.Worker.Run(); } } }

Paso 4 : compila la aplicación principal en la línea de comando:

(cmd.exe from Note 2) csc /reference:platform/x86/library.dll /out:program.exe program.cs bootstrapper.cs

Paso 5 : ahora hemos terminado. La estructura del directorio que creamos debe ser la siguiente:

(C:/TEMP/CrossPlatformTest, root dir) platform (dir) amd64 (dir) library.dll x86 (dir) library.dll program.exe *.cs (source files)

Si ahora ejecuta program.exe en una plataforma de 32 bits, se cargará platform / x86 / library.dll; si ejecuta program.exe en una plataforma de 64 bits, se cargará la plataforma / amd64 / library.dll. Tenga en cuenta que agregué Console.ReadLine () al final del método Worker.Run para que pueda usar el administrador de tareas / explorador de procesos para investigar archivos DLL cargados, o puede usar Visual Studio / Windows Debugger para adjuntarlo al proceso y ver el pila de llamadas, etc.

Cuando se ejecuta program.exe, nuestro resolvedor de ensamblado personalizado se adjunta al dominio de aplicación actual. Tan pronto como .NET comienza a cargar la clase Program, ve una dependencia en el ensamblado ''library'', por lo que intenta cargarlo. Sin embargo, no se encuentra dicho ensamblaje (porque lo hemos ocultado en la plataforma / * subdirectorios). Afortunadamente, nuestro solucionador personalizado conoce nuestro truco y, en base a la plataforma actual, intenta cargar el ensamblado desde el subdirectorio platform / * apropiado.