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.
source to share
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 namestruct HGRABBER_t__
as a structure with oneint
in it. -
typedef
defines a type with a nameHGRABBER_t
as a synonymstruct HGRABBER_t__
. -
#define
defines a type namedHGRABBER
as a pointer toHGRABBER_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. :)
source to share
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.
source to share