2008-08-22 19 views
16

Tengo un problema similar, pero sutilmente diferente de, que describe here (cargando ensamblajes y sus dependencias).Cómo enlazar últimas libs de 32 bits/64 bits en tiempo de ejecución

Tengo una DLL C++ para representación 3D que es lo que vendemos a los clientes. Para los usuarios de .NET tendremos un contenedor CLR a su alrededor. La DLL de C++ se puede compilar en versiones de 32 y 64 bits, pero creo que esto significa que necesitamos tener dos contenedores CLR ya que CLR se une a una DLL específica.

Digamos ahora que nuestro cliente tiene una aplicación .NET que puede ser de 32 o 64 bits, y que al ser una aplicación .NET pura deja el CLR para resolverlo desde un único conjunto de ensamblajes. La pregunta es cómo puede el código de la aplicación elegir dinámicamente entre nuestras combinaciones CLR/DLL de 32 y 64 bits en tiempo de ejecución.

Aún más específicamente, ¿la respuesta sugerida a la pregunta antes mencionada también se aplica aquí (es decir, crea un controlador ResolveEvent)?

Respuesta

8

Finalmente tengo una respuesta para esto que parece funcionar.

Compilar ambos 32 & versiones de 64 bits - ambos administrados & no administrados - en carpetas separadas. Luego, haga que la aplicación .NET elija en tiempo de ejecución de qué directorio cargar los ensamblados.

El problema con el uso del ResolveEvent es que solo recibe una llamada si no se encuentran los ensamblados, por lo que es muy fácil terminar accidentalmente con las versiones de 32 bits. En su lugar, use un segundo objeto AppDomain donde podamos cambiar la propiedad ApplicationBase para que apunte a la carpeta correcta. Así que terminan con un código como:

static void Main(String[] argv) 
    { 
    // Create a new AppDomain, but with the base directory set to either the 32-bit or 64-bit 
    // sub-directories. 

    AppDomainSetup objADS = new AppDomainSetup(); 

    System.String assemblyDir = System.IO.Path.GetDirectoryName(Application.ExecutablePath); 
    switch (System.IntPtr.Size) 
    { 
     case (4): assemblyDir += "\\win32\\"; 
      break; 
     case (8): assemblyDir += "\\x64\\"; 
      break; 
    } 

    objADS.ApplicationBase = assemblyDir; 

    // We set the PrivateBinPath to the application directory, so that we can still 
    // load the platform neutral assemblies from the app directory. 
    objADS.PrivateBinPath = System.IO.Path.GetDirectoryName(Application.ExecutablePath); 

    AppDomain objAD = AppDomain.CreateDomain("", null, objADS); 
    if (argv.Length > 0) 
     objAD.ExecuteAssembly(argv[0]); 
    else 
     objAD.ExecuteAssembly("MyApplication.exe"); 

    AppDomain.Unload(objAD); 

    } 

Se termina con 2 exes - su aplicación normal, y una segunda aplicación de conmutación que elige qué bits para cargar. Nota: no me puedo atribuir el mérito de los detalles de esto. Uno de mis colegas sospechó eso dado mi puntero inicial. Si se registra en StackOverflow, le asignaré la respuesta

1

Me encontré con un escenario similar hace un tiempo. Un kit de herramientas que estaba usando no se comportó bien en un entorno de 64 bits y no pude encontrar una forma de obligar dinámicamente a los ensamblajes a vincularse como de 32 bits.

Es posible obligar a sus ensamblajes a trabajar en modo de 32 bits, pero esto requiere parchear el encabezado CLR, (hay una herramienta que hace eso en el Framework) y si sus ensamblajes son fuertemente nombrados, esto no rutina de ejercicio.

Me temo que tendrá que crear y publicar dos conjuntos de binarios para plataformas de 32 y 64 bits.

3

Pude hacer esto hace aproximadamente un año, pero ya no recuerdo todos los detalles. Básicamente, puede usar IntPtr.Size para determinar qué DLL cargar y luego realizar la LoadLibrary actual a través de p/Invoke. En ese punto, tienes el módulo en la memoria y deberías poder simplemente p/invocar funciones desde adentro; el mismo nombre del módulo no debería volver a cargarse.

Creo, sin embargo, que en mi aplicación tenía realmente la DLL C++ registrarse a sí misma como un servidor COM y luego accedí a su funcionalidad a través de un contenedor .NET generado, así que no sé si alguna vez probé p/Invocando directamente.

Cuestiones relacionadas