Skip to content
Advertisement

How to set arbitrary size array in ctypes?

So I have a function imported from a .dll library that takes in a pointer to a struct of the form:

struct D {
    DWORD A;
    BYTE * B;
};

The idea of function is that if A is NULL, then function(D*) will update A with the size of the required buffer. Hence, if on the other hand B is an array of size A, then function(D*) will return the filled array with the A bytes.

In trying to import the C function with ctypes, I mimic the code:

class D(Structure):
     _fields_ = [("A",DWORD),("B",POINTER(BYTE))]

#function is imported from .dll
function.argtypes = [POINTER(D)]
function.restype  = BOOL

But when I attempt in python to run the function twice, I get a type error that LP_c_byte_p_250 doesn’t work with LP_c_byte (sorry, I am on mobile and may not have the names quite right).

data   = D()
function(pointer(data))
size   = data.A #returns 250
buf    = ARRAY(BYTE,size)
data.B = pointer(buf)
function(pointer(data))

How do I set struct up so that ctypes doesn’t prevent any sized array from occupying variable B?

Just to point out, if I skip the first function call and redefine my struct and argtypes explicitly, then I do get it to work.

class D(Structure):
     _fields_ = [("A",DWORD),("B",POINTER(ARRAY(BYTE,250)))]

#function is imported from .dll
function.argtypes = [POINTER(D)]
function.restype  = BOOL

data   = D()
data.A = 250
function(pointer(data)) #returns 250 bytes to B

So clearly I can recreate my struct and reimport my function every time I have a different size, but that doesn’t seem right. What am I doing wrong?

Advertisement

Answer

It appears the missing ingredient was to use the function cast in ctypes. It seems as though ctypes does some generic casting itself automatically in simple cases, but when presented something more difficult (like a struct built of two other stucts), it doesn’t seem to automatically cast.

data   = D()
function(pointer(data))
size   = data.A #returns 250
buf    = ARRAY(BYTE,size)
data.B = pointer(buf)
buf    = cast(buf,POINTER(D))
function(pointer(data))

This method even appears to work through a c_void_p; in which case you can forcibly use C functions without needing to explicitly define the exact structure they need in ctypes.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement