调用的 Ctypes 参数没有足够的参数
Ctypes arguments called with not enough arguments
我正在尝试使用 ctypes 导入和使用 c++ dll 的功能。使用 windll 成功调用该函数,但在传递参数时继续显示 ValueError: Procedure probably called with not enough arguments (4 bytes missing)。我排除了所有可能性并且非常确定我使用了正确的调用约定。更改为 oledll 或 cdll 也无济于事。下面是代码,也是dll函数调用的使用说明。谢谢
dll user manual
代码:
from ctypes import *
biometric = windll.LoadLibrary(r"G:\software\datalite\OnLineInterface.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)
所以,它来自 Biometrics' DataLINK API 这也是记录在 [NI.Forums]: Manual1.pdf。根据那个(以及问题中的图像),函数原型是:
int __stdcall OnLineGetData(long channel, long sizeMsToRead, SAFEARRAY **DataArray, long *pActualSamples);
因此,您缺少 3rd 参数(双指针: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:\software\datalite\OnLineInterface.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.")
我正在尝试使用 ctypes 导入和使用 c++ dll 的功能。使用 windll 成功调用该函数,但在传递参数时继续显示 ValueError: Procedure probably called with not enough arguments (4 bytes missing)。我排除了所有可能性并且非常确定我使用了正确的调用约定。更改为 oledll 或 cdll 也无济于事。下面是代码,也是dll函数调用的使用说明。谢谢
dll user manual
代码:
from ctypes import *
biometric = windll.LoadLibrary(r"G:\software\datalite\OnLineInterface.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)
所以,它来自 Biometrics' DataLINK API 这也是记录在 [NI.Forums]: Manual1.pdf。根据那个(以及问题中的图像),函数原型是:
int __stdcall OnLineGetData(long channel, long sizeMsToRead, SAFEARRAY **DataArray, long *pActualSamples);
因此,您缺少 3rd 参数(双指针: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:\software\datalite\OnLineInterface.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.")