Аргументы Ctypes вызываются с недостаточным количеством аргументов

#python #dll #ctypes

#python #dll #ctypes

Вопрос:

Я пытаюсь импортировать и использовать функцию c dll с ctypes. Функция успешно вызывается с помощью windll, но продолжает показывать ошибку ValueError: вероятно, процедура вызывается с недостаточным количеством аргументов (пропущено 4 байта) при передаче аргументов. Я исключил все возможности и уверен, что использую правильное соглашение о вызовах. Изменение на oledll или cdll также не поможет. Ниже приведен код, а также руководство пользователя для вызова функции dll. Спасибо.

руководство пользователя dll

Код:

 from ctypes import *

biometric = windll.LoadLibrary(r"G:softwaredataliteOnLineInterface.dll")

i = c_long(1)
biometric.OnLineGetData.argtypes = [c_long,c_long,POINTER(c_long)]
b = pointer(i)
biometric.OnLineGetData(c_long(1),c_long(1),b)
  

Ответ №1:

Итак, это из API DataLINK от Biometrics , который также задокументирован на [NI.Forums]: Manual1.pdf . В соответствии с этим (а также с изображением в вопросе) прототип функции:

 int __stdcall OnLineGetData(long channel, long sizeMsToRead, SAFEARRAY **DataArray, long *pActualSamples); 
  

Итак, вам не хватает 3-го аргумента (двойной указатель: SAFEARRAY **DataArray ). К сожалению, это «немного» сложнее (одна из возможных причин, по которой вы пропускаете это :)).
Я подготовил небольшой (и фиктивный) пример (я также включил создание SAFEARRAY, но есть части (sample_rate), которые необходимо уточнить, чтобы он работал должным образом, а также я не тестировал его).

code00.py:

 #!/usr/bin/env python

import sys
import ctypes as ct
from ctypes import wintypes as wt


class SAFEARRAYBOUND(ct.Structure):
    _fields_ = [
        ("cElements", wt.ULONG),
        ("LONG", wt.LONG),
    ]


class SAFEARRAY(ct.Structure):
    _fields_ = [
        ("cDims", wt.USHORT),
        ("fFeatures", wt.USHORT),
        ("cbElements", wt.ULONG),
        ("cLocks", wt.ULONG),
        ("pvData", ct.c_void_p),
        ("rgsabound", SAFEARRAYBOUND * 1),
    ]

PSAFEARRAY = ct.POINTER(SAFEARRAY)
PPSAFEARRAY = ct.POINTER(PSAFEARRAY)


def main(*argv):
    mod_name = r"G:softwaredataliteOnLineInterface.dll"
    #mod_name = "kernel32"
    OnLineInterfaceDll = ct.WinDLL(mod_name)
    OnLineGetData = OnLineInterfaceDll.OnLineGetData
    OnLineGetData.argtypes = (ct.c_long, ct.c_long, PPSAFEARRAY, ct.POINTER(ct.c_long))
    OnLineGetData.restype = ct.c_int

    OleAut32Dll = ct.WinDLL("OleAut32.dll")
    SafeArrayDestroy = OleAut32Dll.SafeArrayDestroy
    SafeArrayDestroy.argtypes = (PSAFEARRAY,)
    SafeArrayDestroy.restype = ct.c_long
    # Not quite sure how to initialize the SAFEARRAY, you'll have to search for C examples doing that.
    # There is SafeArrayCreate function, but given the double pointer, I think that's called from within OnLineGetData
    # However, I assume that freing the pointer is your responsibility (hence SafeArrayDestroy).

    channel = 1
    millis = 1
    samples = ct.c_long(-1)

    create_array = 1
    if create_array:
        # Create the array according to (available) docs. Needless to say that I didn't test it
        print("Creating array")
        SafeArrayCreateVector = OleAut32Dll.SafeArrayCreateVector
        SafeArrayCreateVector.argtypes = (ct.c_ushort, wt.LONG, wt.ULONG)
        SafeArrayCreateVector.restype = PSAFEARRAY

        VT_I2 = 2
        sample_rate = 5  # !!! PLACE AN APPROPRIATE VALUE (GOT FROM THE DEVICE) HERE !!!
        psa = SafeArrayCreateVector(VT_I2, 0, millis * sample_rate)
        #print(psa)
        ppsa = ct.pointer(psa)
        #print(ppsa)
    else:
        print("Using dummy array")
        ppsa = PPSAFEARRAY()  # Dummy double pointer

    res = OnLineGetData(channel, millis, ppsa, ct.byref(samples))
    print("n{0:s} returned: {1:d}".format(OnLineGetData.__name__, res))
    if ppsa:
        print("Doing smth with the data:", ppsa.contents)
        SafeArrayDestroy(ppsa.contents)


if __name__ == "__main__":
    print("Python {0:s} {1:d}bit on {2:s}n".format(" ".join(elem.strip() for elem in sys.version.split("n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    main(*sys.argv[1:])
    print("nDone.")
  

Комментарии:

1. Я получил коды, которые работают так, как вы предоставили. Тем не менее, я сейчас затрудняюсь с SAFEARRAY, поскольку я прочитал документы о SAFEARRAY, действительно, для этого потребуется объявление strcuture в вашем коде, но, по-видимому, в C функция SafeArrayCreate для инициализации safearray. Эта функция не поддерживается ни в ctypes, ни в Python, возможно ли инициализировать SAFEARRAY для ctypes в Python? В Интернете есть только несколько обсуждений.

2. Это можно вызвать, это в oleaut32.dll . Но, как я уже сказал, я думаю, что функция вызывается внутренне OnLineGetData . Но вызов SafeArrayCreate из CTypes может быть темой другого вопроса.

3. Обновление: двойной указатель, проходящий через функцию, возвращает логическое значение false . Поэтому я предполагаю, что функция не создает safearray для адреса указателя.

4. Другими словами, могу ли я понять, как сама функция создаст safearray при передаче нулевого указателя?