0

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

I've gotten to the point where I can get the DLL function's data (written into a buffer I supply) into a Python bytearray.

How do I convert the bytes in the bytearray into Python integers, strings, etc? I know how to brute-force it - for example (array[0] * 256 + array[1]) but that's dependent on machine endianness and crude.

What's the right way to do this?

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

int GetData(int handle, unsigned short id, unsigned char* data, int dataLength, int &actualLength)

data points to a buffer I supply, dataLength is the length of the buffer in bytes.

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

It returns an error code as an int (0 means OK).

Here's my code so far - it seems to work as far as it goes:

import ctypes

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

def GetData(handle, option_id):

    BUFSIZE = 6

    buffer = bytearray(BUFSIZE)

    argument = (ctypes.c_char*len(buffer)).from_buffer(buffer)

    actualLength = ctypes.c_int()

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

    r = dll.GetData(hCam, option_id, argument, BUFSIZE, ctypes.byref(actualLength))

    if r:
        raise MyError(ERROR_CODES[r])

    return (buffer, actualLength)

That returns a buffer that looks like (for example):

bytearray(b'\x01\x01\x00\x12\x00\x00')

I'm aware that the first two bytes represent a uint16 with the value 257. But how to read that out of the bytesarray in a Pythonic way?

Also, I'm not sure if I'm setting up .argtypes correctly - when should I be using c_char_p, c_void_p, .pointer, and .byref? (Altho, this does seem to work.) I did read the ctype docs, I know they say .byref is faster, but I'm not clear on when .pointer is preferred.

nerdfever.com
  • 1,652
  • 1
  • 20
  • 41

1 Answers1

1

Just use int.from_bytes:

>>> buffer = bytearray(b'\x01\x01\x00\x12\x00\x00')
>>> int.from_bytes(buffer, 'big')
1103807774720
>>> int.from_bytes(buffer, 'little')
301990145

EDIT:

reading over your question carefully, you actually may want to use struct to interpret bytes as binary packed data. In this case, if you need to read an unsigned, 16 bit interger,

>>> import struct
>>> struct.unpack_from('H', buffer)
(257,)

Note, it returns a tuple to handle more complex, compound formats. Here are the docs

juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172