Python Ctypes problema en diferentes sistemas operativos
python-3.x windows (3)
Debe mostrar sus intentos de .argtypes y .restype, pero intente esto:
from ctypes import wintypes as w
class FTRSCAN_IMAGE_SIZE(ctypes.Structure):
_fields_ = [(''nWidth'', ctypes.c_int),
(''nHeight'', ctypes.c_int),
(''nImageSize'', ctypes.c_int)]
FTRHANDLE = ctypes.c_void_p
lib = ctypes.WinDLL(''ftrScanAPI.dll'')
lib.ftrScanOpenDevice.argtypes = None
lib.ftrScanOpenDevice.restype = FTRHANDLE
lib.ftrScanGetImageSize.argtypes = FTRHANDLE,ctypes.POINTER(FTRSCAN_IMAGE_SIZE)
lib.ftrScanGetImageSize.restype = w.BOOL
Compruebe el uso de
WinDLL
vs.
CDLL
.
No importará si su
Python
es de 64 bits, pero hace una diferencia en Python de 32 bits.
Use
CDLL
si las funciones usan la convención de llamadas C (__cdecl) y
WinDLL
si las funciones usan la convención de llamadas __stdcall.
Si el archivo de encabezado no está claro, el valor predeterminado suele ser __cdecl.
Editar:
desde el enlace de la API en otra respuesta, es
__stdcall
y se debe usar
WinDLL
.
Estoy tratando de convertir la función C para Python 3.6 uso.
código como abajo:
lib = ctypes.WinDLL(''ftrScanAPI.dll'') # provided by fingerprint scanner
class FTRSCAN_IMAGE_SIZE(ctypes.Structure):
_fields_ = [
("nWidth", ctypes.c_int),
("nHeight", ctypes.c_int),
("nImageSize", ctypes.c_int)
]
print(''Open device and get device handle...'')
hDevice = lib.ftrScanOpenDevice()
print(''handle is'', hDevice)
print(''Get image size...'')
Image_size = FTRSCAN_IMAGE_SIZE(0, 0, 0)
if lib.ftrScanGetImageSize(hDevice, ctypes.byref(Image_size)):
print(''Get image size succeed...'')
print('' W'', Image_size.nWidth)
print('' H'', Image_size.nHeight)
print('' Size'', Image_size.nImageSize)
else:
print(''Get image size failed...'')
definición de la función:
typedef struct FTR_PACKED __FTRSCAN_IMAGE_SIZE {
int nWidth;
int nHeight;
int nImageSize;
} FTRSCAN_IMAGE_SIZE, *PFTRSCAN_IMAGE_SIZE;
FTRHANDLE ftrScanOpenDevice(); # typedef void * FTRHANDLE;
BOOL ftrScanGetImageSize(FTRHANDLE ftrHandle,
PFTR_SCAN_IMAGE_SIZE pImageSize);
Pero
diferentes sistemas operativos con el mismo código
parecen tener un resultado diferente:
No imprimo "la manija está aquí"
Lo que he intentado:
De acuerdo con algunas respuestas en el desbordamiento de pila, esto puede deberse a que no se asignan los tipos de función y se vuelven a escribir explícitamente, así que lo intenté y fracasé.
El problema parece ser simplemente que el identificador del dispositivo es una entidad de 64 bits (un puntero de tipo typedef''d para anular). El hecho de que funcione en su Windows 7 fue solo una casualidad, ya que los 33 bits superiores del identificador eran correctamente cero.
El tipo de retorno de todas las funciones en ctypes tiene como valor predeterminado
int
32 bits
Ahora, en Windows 10, parece que el bit 32 (bit de signo) se configuró, lo que provoca una extensión de signo en algún lugar cuando el identificador forzado a ingresar se empuja en la pila de 64 bits para la llamada a la función.
La dirección resultante tiene todos los bits superiores establecidos (0xFFFFFFFFA ...) que apunta al espacio del kernel y no en el espacio del usuario.
Por lo tanto, tal vez pueda obtener su código "trabajando" con solo
lib.ftrScanOpenDevice.restype = c_void_p
Esto no quiere decir que no deba definir los tipos de argumento y retorno para
todas las
funciones; debería hacerlo; de lo contrario, seguirán solo las reglas de promoción de argumentos predeterminadas del lenguaje C, y el trabajo ... o no funcionará, dependiendo de sobre si el prototipo de la función es compatible con las promociones de argumentos predeterminados.
Por ejemplo, cualquier función que acepte
float
s
como argumentos no se puede llamar correctamente sin definir el prototipo.
En el 99% de los casos, las inconsistencias entre argumentos (y / o retorno) son inconsistencias de tipo ( .com/questions/52268294/… es un ejemplo de ello).
Siempre tenga [Python 3.Docs]: ctypes - Una biblioteca de funciones extrañas para Python abierta cuando se trabaja con ctypes .
Encontré [GitHub]: erikssm / futronics-fingerprint-reader - (master) futronics-fingerprint-reader / ftrScanAPI.h (No sé qué tan diferente es de lo que tienes actualmente, pero las cosas que publicaste parecen coincidir ), e hice algunos cambios a su código:
- Definir argtypes y reescribir para funciones.
- Definir los tipos que faltan (solo por claridad)
- Algunos otros cambios insignificantes (nombres)
-
Otra cosa que noté en el archivo anterior, es una macro
#pragma pack(push, 1)
(verifique [MS.Docs]: pack para más detalles). Para esta estructura no hace ninguna diferencia (gracias a @AnttiHaapala por la sugerencia), ya que la alineación de los 3 int ( 4 bytes) no cambia, pero para otras estructuras (con tipos de miembros "más pequeños" (por ejemplo, char , short )) Es posible que desee agregar:_pack_ = 1
Su código modificado (no hace falta decirlo, no lo ejecuté porque no tengo el .dll ):
from ctypes import wintypes
# ...
lib = ctypes.WinDLL(''ftrScanAPI.dll'') # provided by fingerprint scanner
class FTRSCAN_IMAGE_SIZE(ctypes.Structure):
# _pack_ = 1
_fields_ = [
("nWidth", ctypes.c_int),
("nHeight", ctypes.c_int),
("nImageSize", ctypes.c_int),
]
PFTRSCAN_IMAGE_SIZE = ctypes.POINTER(FTRSCAN_IMAGE_SIZE)
FTRHANDLE = ctypes.c_void_p
print(''Open device and get device handle...'')
lib.ftrScanOpenDevice.argtypes = []
lib.ftrScanOpenDevice.restype = FTRHANDLE
h_device = lib.ftrScanOpenDevice()
print(''handle is'', h_device)
print(''Get image size...'')
image_size = FTRSCAN_IMAGE_SIZE(0, 0, 0)
lib.ftrScanGetImageSize.argtypes = [FTRHANDLE, PFTRSCAN_IMAGE_SIZE]
lib.ftrScanGetImageSize.restype = wintypes.BOOL
if lib.ftrScanGetImageSize(h_device, ctypes.byref(image_size)):
print(''Get image size succeed...'')
print('' W'', image_size.nWidth)
print('' H'', image_size.nHeight)
print('' Size'', image_size.nImageSize)
else:
print(''Get image size failed...'')