Am I using ctypes correctly to pythonify this structure?

I am trying to talk to this DLL using python types. Many of the functions take or return a type HGRABBER

:

typedef struct HGRABBER_t__ { int unused; } HGRABBER_t;
#define HGRABBER HGRABBER_t* 

      

(the full header file can be viewed here ). Here's an example of a function prototype that returns a type HGRABBER

:

HGRABBER __stdcall IC_CreateGrabber();

      

Here's my attempt at implementing this structure in python and using it to call this function from a DLL:

import ctypes as C
class GrabberHandle(C.Structure):
    _fields_ = [('unused', C.c_int)]

dll = C.windll.LoadLibrary('tisgrabber_x64.dll')
dll.create_grabber = dll.IC_CreateGrabber
dll.create_grabber.argtypes = []
dll.create_grabber.restype = GrabberHandle
my_handle = dll.create_grabber()

      

This seems to work, but I am worried that I am doing it wrong. I'm not familiar with C and I don't think I understand the instructions typedef

and #define

that define the type HGRABBER

. Am I calling correctly IC_CreateGrabber

?
Should I define the GrabberHandle as a pointer to a struct and not a struct?

Thanks for reading, please let me know if I can somehow clarify my question.

+3


source to share


2 answers


You are right what you really want POINTER

for Structure

, not yourself Structure

.

Translating C to English, being very fluent (in a way that would be dangerous if you were trying to learn C, but good enough to use ctypes

):

  • struct

    defines a type with a name struct HGRABBER_t__

    as a structure with one int

    in it.
  • typedef

    defines a type with a name HGRABBER_t

    as a synonym struct HGRABBER_t__

    .
  • #define

    defines a type named HGRABBER

    as a pointer to HGRABBER_t

    .

So yours is GrabberHandle

equivalent HGRABBER_t

; the equivalent HGRABBER

is:



GrabberHandlePtr = C.POINTER(GrabberHandle)

      

So you want this:

dll.create_grabber.restype = GrabberHandlePtr

      

It can be tricky to debug the difference. A C-only structure int

is like an int

in-memory structure . And on Win32, int

and a pointer are 32-bit values. And a named int is unused

likely to be filled with meaningless garbage, making it difficult to distinguish it from a pointer that you accidentally viewed as an int. This way, everything will look fine until you split 30 lines in your code and understand what happened. :)

+2


source


This library does what you are trying to do: https://github.com/morefigs/py-ic-imaging-control :)

But to answer your question, the library uses the code:



from ctypes import *
import os

class GrabberHandle(Structure):
    pass
GrabberHandle._fields_ = [('unused', c_int)]

# set and check path
dll_path = os.path.join(os.path.expanduser('~'),
                        'Documents\\The Imaging Source Europe GmbH\\TIS Grabber DLL\\bin\\win32\\tisgrabber.dll')
with open(dll_path) as thefile:
    pass

# open DLL
_ic_grabber_dll = windll.LoadLibrary(dll_path)

# create grabber
create_grabber = _ic_grabber_dll.IC_CreateGrabber
create_grabber.restype = POINTER(GrabberHandle)
create_grabber.argtypes = None

# get handle
handle = create_grabber()

      

Edit: Changed the code to use a pointer to GrabberHandle

as per abarnert's answer as it is correct. However, in this particular case, I found no practical difference (with a 32-bit DLL), possibly because the structure is GrabberHandle

so simple.

+1


source







All Articles