Reputation: 2892
I'm trying to talk to this DLL using python's ctypes. Many of the functions take or return an HGRABBER
type:
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 an HGRABBER
type:
HGRABBER __stdcall IC_CreateGrabber();
Here's my attempt at implementing this struct in python, and using it to call that function from the 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'm worried that I'm doing this wrong. I'm not experienced with C, and I don't think I understand the typedef
and #define
statements which define the HGRABBER
type. Am I calling IC_CreateGrabber
correctly? Should I have defined GrabberHandle to be a pointer to a struct, instead of a struct?
Thanks for reading, please let me know if I can clarify my question somehow.
Upvotes: 3
Views: 306
Reputation: 8969
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 code to use a pointer to GrabberHandle
as per abarnert's answer as this is correct. However, in this particular case I have found no practical difference (with the 32-bit DLL), probably because the GrabberHandle
structure is so simple.
Upvotes: 1
Reputation: 365577
You're right that you actually want a POINTER
to the Structure
, not the Structure
itself.
Translating the C into English, being very loose (in a way that would be dangerous if you were trying to learn C but is good enough for using ctypes
):
struct
defines a type named struct HGRABBER_t__
, as a structure with one int
in it.typedef
defines a type named HGRABBER_t
, as a synonym for struct HGRABBER_t__
.#define
defines a type named HGRABBER
as a pointer to HGRABBER_t
.So, your GrabberHandle
is the equivalent of HGRABBER_t
; the equivalent of HGRABBER
is:
GrabberHandlePtr = C.POINTER(GrabberHandle)
So you want this:
dll.create_grabber.restype = GrabberHandlePtr
It may be hard to debug the difference. A C struct with nothing but an int
in it looks identical to an int
in memory. And on Win32, an int
and a pointer are both 32-bit values. And an int named unused
is likely to be filled with meaningless garbage, making it hard to distinguish it from a pointer you've accidentally treated as an int. So everything will look fine, until you segfault 30 lines later in your code and have no idea what's wrong. :)
Upvotes: 2