2010-09-30 22 views
11

He buscado sugerencias sobre cómo puedo hacer esto, pero todo lo que encontré fue cómo redirigir una DLL SxS a la carpeta de la aplicación local. Esto es lo que quiero lograr: El (C++) Application.exe está vinculado a un archivo DLL, Plugin.DLL (proyecto dependiente). Esta DLL no se coloca dentro del directorio de la aplicación, sino en una subcarpeta llamada "complementos". Como el archivo DLL está vinculado de forma estática, la aplicación intentará cargarlo desde la carpeta de la aplicación.Alterar la ruta de búsqueda DLL para DLL estática

¿Hay alguna manera de cómo puedo cambiar la ruta de búsqueda para esta DLL en particular? ¿A través de manifiestos o configuraciones de enlazador VS2008?

Respuesta

17

Mi primer pensamiento es, si está vinculando estáticamente un dll, no es un complemento. Simplemente coloque el dll en la carpeta EXE y termine con él. Esa es la configuración de implementación admitida por Windows para archivos DLL cargados estáticamente.

Dicho esto, hay formas de lograr lo que desea. Pero son en su mayoría estúpidos o complicados sin una buena razón: Sus opciones son:

  • No se puede establecer un vínculo estático. Use LoadLibrary ("plugins/Plugin.dll") & GetProcAddress para acceder al contenido del complemento.
  • Agregue "la ruta a su carpeta de complementos" a la variable de entorno PATH del sistema.
  • Utilice el mecanismo de carga de retraso para retrasar el acceso a la funcionalidad de los complementos, establezca un custom helper function que pueda cargar el dll (s) utilizando una ruta proporcionada.
  • Convierta la carpeta de complementos en un ensamblaje (creando un archivo .manifest en él que enumere plugin.dll). Agregue "complementos" como un ensamblaje dependiente a su aplicación. Ahora se verá en la carpeta de complementos.
  • Divida su aplicación en un stub exe y una parte cargada dinámicamente. En el stub exe, llame a SetDllDirectory para que apunte a la carpeta del complemento, luego llame a LoadLibrary pasando la ruta completa a "appstub.dll".

Para activar una carpeta, con una o más de las DLL en una "asamblea", sólo tiene que añadir un archivo a la carpeta con las carpetas name.manifest.

Así, plugins.manifest: -

<assembly manifestVersion="1.0"> 
    <assemblyIdentity type="Win32" name="Plugins" version="1.0.0.0" processorArchitecture="x86" /> 
    <file name="Plugin.dll"/> 
</assembly> 

Es una muy buena idea para asegurarse de que la carpeta y el nombre del archivo DLL es diferente, como si el nombre de la DLL es las ventanas nombre de ensamblado empieza a buscar en su embebido archivo de manifiesto para obtener información sobre el conjunto.

Suponiendo que está utilizando Visual Studio 7 o posterior, agregue la siguiente directiva a .c/.cpp o.archivo h en el proyecto luego hacer su intento de aplicación para cargar archivos DLL de la asamblea en lugar de sólo el directorio local:

#pragma comment(linker, "/manifestdependency:\"name='Plugins' "\ 
         "processorArchitecture='*' version='1.0.0.0' "\ 
         "type='win32'\"") 
+0

Gracias - Ya me he ido con el enfoque GetProcAddress porque no pude entender cómo debe ser el manifiesto para hacer funcionar el enfoque de "montaje falso". Afortunadamente, esto funciona bien con la arquitectura general. – Oliver

+1

No necesita 'SetDllDirectory' para cargar el retraso; hay un gancho '__pfnDliNotifyHook2' para que pueda llamar directamente a' LoadLibrary (". \\ plugins \\ PluginX.dll") '. La idea de '% PATH%' es un poco frágil, ya que es bastante bajo en la lista de ubicaciones para verificar. – MSalters

+0

gracias. Nunca he utilizado personalmente la carga de retraso, así que solo asumí que SetDllDirectory sería la forma de ajustarlo. –

5

expansión y detailing Chris' proposal de un "montaje" subdirectorio: Nota


Side Chris también tiene dos excelentes comentarios escritos de más detalles:


documentos de MS

Esto se llama en realidad un "Private Assembly" y MS documentos explican de esta manera:

asambleas privadas se instalan en una carpeta de la estructura directorio de la aplicación. Normalmente, esta es la carpeta que contiene el archivo ejecutable de la aplicación . ensamblados privados pueden desplegarse en la misma carpeta que la aplicación, en una carpeta con el mismo nombre que el conjunto , o en una subcarpeta específica del idioma con el mismo nombre como el montaje.

Por ejemplo (...)

Appdir\Microsoft.Tools.Pop\Microsoft.Tools.Pop.MANIFEST: El manifiesto se implementa como un archivo separado en una subcarpeta con el nombre de la asamblea.

(...)

asambleas privadas se pueden instalar por cualquier método de instalación que puede copiar el archivo del conjunto en esta carpeta, como el comando xcopy.

El ejemplo

Tienes que eres fiel y vieja ejecutable en la carpeta del programa que C:\Test\Program\app.exe y quiere - at Load-Time - cargar el archivo DLL de la Plugins subcarpeta, es decir, sin C:\Test\Program\plugins\tool1.dll jugar con PATH o cualquier otra cosa.

es necesario:

  • Compilar app.exe con:

    #pragma comment(linker, "/manifestdependency:\"name='Plugins' version='1.0.0.0' type='win32'\"") 
    // name, type and version seems to be the minimum info to get away with 
    

    Nota: Compilar/Enlazar esto en lugar de utilizar un manifiesto externa (app.exe.manifest) se requiere en mi sistema de prueba, todavía no descubrí por qué.(* A)

    Lo que también funciona sin embargo se Inclusión/fusionar el archivo de manifiesto se enumeran a continuación en el ejecutable con la herramienta mt, en lugar de con el pragma enlazador. (Configuration > Manifest Tool > Additional Manifest Files)

  • puesto tool1.dll intro del plugins subcarpeta

  • añadir un archivo plugins.manifest en la subcarpeta plugins, es decir C:\Test\Program\plugins\plugins.manifest y que uno se ve así:

plugins. manifiesto:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
    <assemblyIdentity 
          type="win32" 
          name="Plugins" 
          version="1.0.0.0" 
      /> 
    <file name="tool1.dll"/> 
</assembly> 

Eso es todo. Al iniciar app.exe, se buscará automáticamente el dll en la subcarpeta en Load-Time.


(* a): La fusión de este archivo de manifiesto funciona, pero no se puede usar eso como el único archivo de manifiesto externa, y sospecho que es porque le falta toda la otra información de manifiesto el sistema de construcción ya se sitúa en ¡tu ejecutable!

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
    <dependency> 
     <dependentAssembly> 
      <!-- Note: type: The value must be win32 and all in lower case. Required. --> 
      <!-- Note: version: The value must be win32 and all in lower case. Required. --> 
      <assemblyIdentity 
            type="win32" 
            name="plugins" 
            version="1.0.0.0" 
      /> 
     </dependentAssembly> 
    </dependency> 
</assembly> 
+0

El numpy wiki @ https://github.com/numpy/numpy/wiki/windows-dll-notes también tiene una buena redacción de este –

+0

El archivo de manifiesto externo solo se usa, creo que si no hay un archivo de manifiesto incrustado. El compilador de VS ahora integra los manifiestos de forma predeterminada, por lo que la carga en tiempo de ejecución de los manifiestos solo es posible si lo elimina primero. –

Cuestiones relacionadas