windll - python use c dll




edição ctypes python em diferentes sistemas operacionais (2)

Em 99% dos casos, inconsistências entre argumentos (e / ou retorno) tipo inconsistências são a causa ( stackoverflow.com/questions/52268294/… é um desses exemplos).

Sempre tem [Python 3.Docs]: ctypes - Uma biblioteca de funções externas para Python aberta ao trabalhar com ctypes .

Eu encontrei [GitHub]: erikssm / futronics-fingerprint-reader - (mestre) futronics-fingerprint-reader / ftrScanAPI.h (Eu não sei o quão diferente é do que você tem atualmente, mas as coisas que você postou até agora parecem combinar ), e fiz algumas alterações no seu código:

  • Definir tipos de argumento e restype para funções
  • Definir tipos ausentes (somente para clareza)
  • Algumas outras alterações insignificantes (renomeia)
  • Uma outra coisa que notei no arquivo acima, é uma macro #pragma pack(push, 1) (marque [MS.Docs]: pack para mais detalhes). Para esta estrutura não faz diferença (obrigado @AnttiHaapala pela dica), já que o alinhamento dos membros int 3 ( 4 bytes) não muda, mas para outras estruturas (com tipos de membros "menores" (por exemplo, char , short )) você pode querer adicionar: _pack_ = 1

Seu código modificado (escusado será dizer que não o rodei porque não tenho o .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...')

Eu estou tentando converter a função C para uso do python 3.6.

código como abaixo:

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...')

definição de função:

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);

Mas diferentes sistemas operacionais com o mesmo código parecem ter resultados diferentes:

  • No Windows 7 de 64 bits

  • No Windows 10 de 64 bits
    Eu não imprimo "manuseio está aqui"

    O que eu tentei:
    De acordo com algumas respostas no estouro de pilha, isso pode ser causado por não atribuir os tipos de função e digitar explicitamente, então eu tentei e falhei.


  • O problema parece ser simplesmente que o identificador de dispositivo é uma entidade de 64 bits (um ponteiro typedef'd para anular). Que funciona no seu Windows 7 foi apenas um acaso, como os 33 bits superiores do identificador foram corretamente zero.

    O tipo de retorno de todas as funções em ctypes é padronizado para int 32 bits. Agora, no Windows 10, parece que o 32º bit (bit de sinal) foi definido, o que causa uma extensão de sinalização em algum lugar quando o comando-coerced-to-handle é pressionado na pilha de 64 bits para a chamada de função. O endereço resultante tem todos os bits superiores configurados (0xFFFFFFFFA ...) que apontam para o espaço do kernel e não no espaço do usuário.

    Assim, talvez você possa obter o seu código "trabalhando" com apenas

    lib.ftrScanOpenDevice.restype = c_void_p

    Isso não quer dizer que você não deve definir o argumento e retornar tipos para todas as funções - você deve, caso contrário, eles seguirão apenas as regras padrão de promoção de argumentos da linguagem C, e funcionarão ... ou falharão totalmente no trabalho, dependendo se o próprio protótipo da função é compatível com as promoções de argumentos padrão. Por exemplo, qualquer função que aceita float s como argumentos não pode ser chamada corretamente sem definir o protótipo.





    ctypes