#python #dll #ctypes
#python #dll #ctypes
Вопрос:
Я пытаюсь импортировать и использовать функцию c dll с ctypes. Функция успешно вызывается с помощью windll, но продолжает показывать ошибку ValueError: вероятно, процедура вызывается с недостаточным количеством аргументов (пропущено 4 байта) при передаче аргументов. Я исключил все возможности и уверен, что использую правильное соглашение о вызовах. Изменение на oledll или cdll также не поможет. Ниже приведен код, а также руководство пользователя для вызова функции 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 при передаче нулевого указателя?