¿Cómo puedo usar un archivo DLL de Python?

186

¿Cuál es la forma más fácil de usar un DLLarchivo desde dentro Python?

Específicamente, ¿cómo se puede hacer esto sin escribir ningún C++código contenedor adicional para exponer la funcionalidad Python?

PythonSe prefiere la funcionalidad nativa sobre el uso de una biblioteca de terceros.

Tom Hennen
fuente
@Remuze ¿etiquetó la pregunta incorrecta o la etiqueta con la respuesta incorrecta? Ambos son python, pero no veo ninguna razón por la que los encuentres similares (y verifiqué el historial de revisiones para asegurarme de que no estuvieran más cerca en algún momento del pasado)
Foon
@foon hmmm sí lo siento, quise marcar otra pregunta como duplicada y poner esta :) ¡Supongo que eso muestra cuán similares son!
Trev Davies

Respuestas:

154

Para facilitar su uso, ctypes es el camino a seguir.

El siguiente ejemplo de ctypes es del código real que he escrito (en Python 2.5). Esta ha sido, con mucho, la forma más fácil que he encontrado para hacer lo que pides.

import ctypes

# Load DLL into memory.

hllDll = ctypes.WinDLL ("c:\\PComm\\ehlapi32.dll")

# Set up prototype and parameters for the desired function call.
# HLLAPI

hllApiProto = ctypes.WINFUNCTYPE (
    ctypes.c_int,      # Return type.
    ctypes.c_void_p,   # Parameters 1 ...
    ctypes.c_void_p,
    ctypes.c_void_p,
    ctypes.c_void_p)   # ... thru 4.
hllApiParams = (1, "p1", 0), (1, "p2", 0), (1, "p3",0), (1, "p4",0),

# Actually map the call ("HLLAPI(...)") to a Python name.

hllApi = hllApiProto (("HLLAPI", hllDll), hllApiParams)

# This is how you can actually call the DLL function.
# Set up the variables and call the Python name with them.

p1 = ctypes.c_int (1)
p2 = ctypes.c_char_p (sessionVar)
p3 = ctypes.c_int (1)
p4 = ctypes.c_int (0)
hllApi (ctypes.byref (p1), p2, ctypes.byref (p3), ctypes.byref (p4))

El ctypesmaterial tiene todos los tipos de tipo C de datos ( int, char, short, void*, y así sucesivamente) y puede pasar por valor o referencia. También puede devolver tipos de datos específicos, aunque mi ejemplo no lo hace (la API HLL devuelve valores modificando una variable pasada por referencia).


En términos del ejemplo específico que se muestra arriba, EHLLAPI de IBM es una interfaz bastante consistente.

Todas las llamadas pasan cuatro punteros vacíos (EHLLAPI envía el código de retorno de regreso a través del cuarto parámetro, un puntero a un intpunto, mientras que especifico intcomo tipo de retorno, puedo ignorarlo de manera segura) según la documentación de IBM aquí . En otras palabras, la variante C de la función sería:

int hllApi (void *p1, void *p2, void *p3, void *p4)

Esto hace que una función única y simple ctypespueda hacer cualquier cosa que la biblioteca EHLLAPI proporcione, pero es probable que otras bibliotecas necesiten una ctypesfunción separada configurada por función de biblioteca.

El valor de retorno de WINFUNCTYPEes un prototipo de función, pero aún debe configurar más información de parámetros (además de los tipos). Cada tupla hllApiParamstiene un parámetro "dirección" (1 = entrada, 2 = salida, etc.), un nombre de parámetro y un valor predeterminado; consulte el documento ctypespara obtener más información.

Una vez que tenga la información del prototipo y los parámetros, puede crear un Python "invocable" hllApicon el que llamar a la función. Sólo tiene que crear la variable sea necesario ( p1a través p4en mi caso) y llama a la función con ellos.

paxdiablo
fuente
1
Hola, puede haber pasado mucho tiempo desde que alguien respondió aquí, pero quería saber algo para que esto funcione exactamente para mi programa. ¿Podría decirme qué es "HLLAPI" en esto? Además, si deseo acceder a mi dll con una función "void BoxProperties (double L, double H, double W, double & A, double & V);" ¿podría sugerirme qué cambios debo hacer en el código anterior para que funcione? Salud.
Neófilo
44
¿Qué hace exactamente hllApiParams? ¿Cuál es el punto de esas tuplas? Es difícil hacer coincidir algunas de las cosas en este ejemplo con la documentación.
Jonathon Reinhart
1
@JonathonReinhart, he desarrollado un poco el ejemplo específico con algo de texto en la parte inferior. Con suerte, eso lo explica un poco mejor. Si no es así, avíseme y volveré a intentarlo :-)
paxdiablo
1
excelente respuesta, ayuda mucho 6 años después :) ¡Hubiera puesto un +100 si hubiera podido hacerlo!
Coronel Beauvel
1
Esto es muy confuso desde la perspectiva de los recién llegados de ctypes. No estoy seguro de lo que está sucediendo, incluso con la explicación.
DuckPuncher
69

Esta página tiene un ejemplo muy simple de llamar a funciones desde un archivo DLL.

Parafraseando los detalles aquí para completar:

Es muy fácil llamar a una función DLL en Python. Tengo un archivo DLL hecho a sí mismo con dos funciones: addy subque toman dos argumentos.

add(a, b)devuelve la suma de dos números
sub(a, b)devuelve la resta de dos números

El nombre del archivo DLL será "demo.dll"

Programa:

from ctypes import*
# give location of dll
mydll = cdll.LoadLibrary("C:\\demo.dll")
result1= mydll.add(10,1)
result2= mydll.sub(10,1)
print "Addition value:"+result1
print "Substraction:"+result2

Salida:

Addition value:11
Substraction:9

atul
fuente
2
El enlace en esta respuesta está roto.
Kaliber64
10
Si el enlace no funciona para usted, no se preocupe, es una copia directa y pegada. No te falta ninguna información.
pantano
6

Quizás con Dispatch:

from win32com.client import Dispatch

zk = Dispatch("zkemkeeper.ZKEM") 

Donde zkemkeeper es un archivo DLL registrado en el sistema ... Después de eso, puede acceder a las funciones con solo llamarlas:

zk.Connect_Net(IP_address, port)
Carlos gomez
fuente
Estoy trabajando en este zkemkeeper.ZKEM, ¿sabes cómo puedo obtener eventos en tiempo real en python?
Sam Ziggler
4

Construyendo una DLL y vinculándola bajo Python usando ctypes

Presento un ejemplo completamente trabajado sobre cómo construir un shared libraryy usarlo Pythonpor medio de ctypes. Considero el Windowscaso y trato DLLs. Se necesitan dos pasos:

  1. Cree la DLL utilizando el compilador de Visual Studio desde la línea de comandos o desde el IDE;
  2. Enlace la DLL en Python usando ctypes.

La biblioteca compartida

Lo shared libraryque considero es lo siguiente y está contenido en el testDLL.cpparchivo. La única función testDLLsolo recibe un inte lo imprime.

#include <stdio.h>

extern "C" {

__declspec(dllexport)

void testDLL(const int i) {
    printf("%d\n", i);
}

} // extern "C"

Construyendo la DLL desde la línea de comando

Para construir un DLLcon Visual Studiodesde la línea de comando, ejecuta

"C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\vsdevcmd"

para establecer la ruta de inclusión y luego ejecutar

cl.exe /D_USRDLL /D_WINDLL testDLL.cpp /MT /link /DLL /OUT:testDLL.dll

para construir la DLL.

Construyendo DLLdesde el IDE

Alternativamente, DLLse puede construir usando Visual Studiolo siguiente:

  1. Archivo -> Nuevo -> Proyecto;
  2. Instalado -> Plantillas -> Visual C ++ -> Windows -> Win32 -> Win32Project;
  3. Próximo;
  4. Tipo de aplicación -> DLL;
  5. Opciones adicionales -> Proyecto vacío (seleccionar);
  6. Opciones adicionales -> Encabezado precompilado (deseleccionar);
  7. Proyecto -> Propiedades -> Administrador de configuración -> Plataforma de solución activa: x64;
  8. Proyecto -> Propiedades -> Administrador de configuración -> Configuración de solución activa: Lanzamiento.

Vinculación de la DLL en Python

En Python, haga lo siguiente

import os
import sys
from ctypes import *

lib = cdll.LoadLibrary('testDLL.dll')

lib.testDLL(3)
JackOLantern
fuente
¿Qué pasa si la DLL en un paquete de Python? ¿Cómo accedo a él?
decadenza
3

Los ctypes serán lo más fácil de usar pero (mal) usarlo hace que Python esté sujeto a fallas. Si está tratando de hacer algo rápidamente y tiene cuidado, es genial.

Te animo a que revises Boost Python . Sí, requiere que escriba un código C ++ y tenga un compilador C ++, pero en realidad no necesita aprender C ++ para usarlo, y puede obtener un compilador C ++ gratuito (como en cerveza) de Microsoft .

David Nehme
fuente
0

Si la DLL es de tipo biblioteca COM, puede usar pythonnet.

pip install pythonnet

Luego, en su código de Python, intente lo siguiente

import clr
clr.AddReference('path_to_your_dll')

luego instanciar un objeto según la clase en la DLL, y acceder a los métodos dentro de él.

sattva_venu
fuente