nerdfever.com
nerdfever.com

Reputation: 1782

How to determine Python3 ctypes .argtypes from C function signature?

I'm writing a ctypes interface to a 3rd party DLL (I have no control over the DLL).

My code seems to work, but I fear I'm setting up .argtypes wrong.

The signature of the C function I'm trying to call is:

int GetData(unsigned short option, unsigned char* buffer, int bufferLength, int &actualLength);

option indicates the kind of data requested, buffer points to a buffer I supply, bufferLength is the length of the buffer in bytes.

The DLL function writes into the buffer, and puts the number of bytes it actually wrote into actualLength.

My code:

import ctypes

dll = ctypes.CDLL("dll_name.dll")

def GetData(option):

    BUFSIZE = 6

    buf = bytearray(BUFSIZE)

    ptr_to_buf = (ctypes.c_char*len(buf)).from_buffer(buf)

    actualLength = ctypes.c_int()

    dll.GetData.argtypes = (ctypes.c_ushort, 
                            ctypes.c_char_p, 
                            ctypes.c_int, 
                            ctypes.POINTER(ctypes.c_int))

    dll.GetData.restype = int

    dll.GetData(option, 
                ptr_to_buf, 
                BUFSIZE, 
                ctypes.byref(actualLength))

    return (buf, actualLength.value)

Does the call to GetData() accurately reflect the .argtypes?

  1. Is it OK to pass ptr_to_buf as a ctypes.c_char_p as I'm doing here?
  2. Is it OK to pass a ctypes.byref into a ctypes.POINTER as I'm doing here?
  3. When would be it be necessary to use .pointer instead of .byref? I did read the ctype docs, I know they say .byref is faster, but I'm not clear on when .pointer is needed.
  4. Is there anything else I'm doing wrong here?

Upvotes: 0

Views: 557

Answers (1)

Mark Tolonen
Mark Tolonen

Reputation: 177610

.argtypes is fine. You may want POINTER(c_ubyte) to completely agree with the prototype, but often c_char_p is easier to work with.

  1. Is it OK to pass ptr_to_buf as a ctypes.c_char_p as I'm doing here?

Yes. An array is passed as a pointer of the same element type.

  1. Is it OK to pass a ctypes.byref into a ctypes.POINTER as I'm doing here?

Yes.

  1. When would be it be necessary to use .pointer instead of .byref? I did read the ctype docs, I know they say .byref is faster, but I'm not clear on when .pointer is needed.

Create a pointer when you need a concrete pointer. I've rarely used pointer. Say you had this code in C and had some reason to mimic it:

int x = 5;
int* y = &x;

The Python equivalent would be:

x = c_int(5)
y = pointer(x)
  1. Is there anything else I'm doing wrong here?

.restype should have a ctype type. .restype = c_int would be correct.

Upvotes: 1

Related Questions