Ctypes arguments called with not enough arguments

Viewed 118

I'm trying to import and use the function of a c++ dll with ctypes. The function is called successfully with windll, but keep showing ValueError: Procedure probably called with not enough arguments (4 bytes missing) when passing arguments. I ruled out all the possibility and pretty sure I'm using the correct calling convention. Change to oledll or cdll won't help either. Below is the code, and also the user manual for the dll function calling. Thanks.

dll user manual

Code:

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)
1 Answers

So, it's from Biometrics' DataLINK API which is also documented at [NI.Forums]: Manual1.pdf. According to that (and the image in the question as well), the function prototype is:

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

So, you're missing the 3rd argument (the double pointer: SAFEARRAY **DataArray). Unfortunately, that's "a bit" more complicated (one possible reason for you skipping it :) ).
I prepared a small (and dummy) example (I also included the SAFEARRAY creation, but there are parts (sample_rate) that need to be clarified for it to work properly, and also, I didn't test it).

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.")
Related