2010-06-05 14 views
19

Tengo un módulo de Python, wrapper.py, que envuelve una DLL de C. La DLL se encuentra en la misma carpeta que el módulo. Por lo tanto, yo uso el siguiente código para cargarlo:Python ctypes: cargando DLL desde una ruta relativa

myDll = ctypes.CDLL("MyCDLL.dll") 

Esto funciona si ejecuto wrapper.py de su propia carpeta. Sin embargo, si lo ejecuto desde otro lugar, falla. Eso es porque ctypes calcula la ruta relativa al directorio de trabajo actual.

Mi pregunta es, ¿hay alguna manera de que pueda especificar la ruta de la DLL en relación con el contenedor en lugar del directorio de trabajo actual? Eso me permitirá enviar los dos juntos y permitir al usuario ejecutar/importar el contenedor desde cualquier lugar.

+1

Utilizo el enfoque en [respuesta seleccionada] (http://stackoverflow.com/a/2980501/1020470) pero en un caso tuve un dll que importó una exportación de otro dll y no se cargaba . La solución fue cargar el otro dll primero, EG: '_DIRNAME = os.path.dirname (__ file__); required_dll = ctypes.cdll.LoadLibrary (os.path.join (_DIRNAME, required.dll)); main_dll = ctypes.cdll.LoadLibrary (os.path.join (_DIRNAME, main.dll)) 'voila que funciona! –

Respuesta

20

Puede usar os.path.dirname(__file__) para obtener el directorio donde se encuentra el archivo fuente de Python.

+0

Muchas gracias. Eso es exactamente lo que estaba buscando. –

+0

La ruta relativa funciona bien, no es necesario 'os.path.abspath()' ni agrega esta ruta a '$ PATH' ('% PATH% '). Una advertencia, si su dll requiere otro dll, entonces tendrá que cargar eso también, antes de cargar este, vea mi comentario bajo la pregunta de OP. –

6

Siempre agrego el directorio donde está mi DLL a la ruta. Eso funciona:

os.environ['PATH'] = os.path.dirname(__file__) + ';' + os.environ['PATH'] 
windll.LoadLibrary('mydll.dll') 

Tenga en cuenta que si utiliza py2exe, esto no funciona (porque __file__ no esta determinado). En ese caso, es necesario confiar en los sys.executable atributo (instrucciones completas en http://www.py2exe.org/index.cgi/WhereAmI)

+0

['os.pathsep'] (http://docs.python.org/2/library/os.html#os.pathsep) es una forma segura de plataforma para indicar el separador utilizado entre las entradas de ruta en el sistema' $ PATH' o la variable de entorno '% PATH%'. Sin embargo, no abogaría ** ** por esta respuesta porque IMO es antipático para editar variables ambientales en tiempo de ejecución; IMO deben ser configurados durante la instalación por 'setup.py'. En cambio, creo que la [respuesta seleccionada] (http://stackoverflow.com/a/2980501/1020470) ¡funciona! –

+2

@MarkMikofski Eso es tonto. Cualquier aplicación que edite variables de entorno es la única aplicación que ve el cambio. Ellos no persisten. Sería una pesadilla de seguridad si lo hicieran. setup.py no puede cambiar las variables de entorno para la aplicación en ejecución de todos modos. Edite su entorno al contenido de su corazón. – Tritium21

+0

@ tritium21 esa no fue la razón de mi comentario, aunque creo que estaba confundiendo el establecimiento de 'PATH' y' sys.path'. En general, creo que todo lo que es robusto, simple y ampliamente practicado es lo mejor. IMO agregar la ubicación de la DLL a 'PATH' no es tan robusto como simplemente usar la ruta completa de DLL. –

10

Ampliando la respuesta de Mateo:

import os.path 
dll_name = "MyCDLL.dll" 
dllabspath = os.path.dirname(os.path.abspath(__file__)) + os.path.sep + dll_name 
myDll = ctypes.CDLL(dllabspath) 

esto sólo funcionará a partir de un guión, no la consola ni de py2exe.

+0

Me gusta el uso de os.path.sep en general, pero hay instalaciones de Windows que no usan ';' para un separador de ruta? –

+1

Este separador de ruta es un separador de directorio, es decir, '\' en Windows.Esto toma un enfoque diferente al suyo, carga el dll a través de su ruta de archivo absoluta en lugar de modificar la variable de entorno PATH. Creo que me gusta más el suyo, ya que tiene una alternativa para cargar el dll del sistema predeterminado si no se proporciona uno. – fmark

+5

['os.path.join'] (http://docs.python.org/2/library/os.path.html#os.path.join) es mucho más fácil para los dedos y los ojos. EG: 'os.path.abspath (os.path.join (os.path.dirname (__ file__), dll_name))' –