2014-09-13 22 views
3

我正在尝试使用python的ctypes与this DLL对话。许多功能采取或返回HGRABBER类型:我正确使用ctypes来pythonify这个结构?

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

(完整的头文件可以被看作here)。这里有一个函数原型,返回HGRABBER类型的例子:

HGRABBER __stdcall IC_CreateGrabber(); 

这是我尝试在实施这一结构在Python中,并用它来调用从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() 

这似乎去工作,但我担心我做错了。我对C没有经验,我不认为我理解定义HGRABBER类型的语句typedef#define我正确拨打IC_CreateGrabber吗?我是否应该将GrabberHandle定义为一个指向结构体的指针,而不是结构体?

感谢您的阅读,请让我知道,如果我能澄清我的问题莫名其妙。

回答

2

你是对的,你实际上想要一个POINTERStructure,而不是Structure本身。

翻译的C成英文,是非常宽松(在某种程度上,这将是危险的,如果你想学习C,但也够用了使用​​):

  • struct定义了一个名为struct HGRABBER_t__类型,作为其中一个int的结构。
  • typedef定义了一种名为HGRABBER_t的类型,作为struct HGRABBER_t__的同义词。
  • #define定义了一个名为HGRABBER的类型作为指向HGRABBER_t的指针。

因此,您的GrabberHandle相当于HGRABBER_t;的HGRABBER相当于是:

GrabberHandlePtr = C.POINTER(GrabberHandle) 

所以,你要这样:

dll.create_grabber.restype = GrabberHandlePtr 

这可能很难调试的差异。一个只有int的C结构看起来与内存中的int完全相同。而在Win32上,一个int和一个指针都是32位值。而一个名为unused的int可能会被无意义的垃圾填充,使得很难将它与您意外处理为int的指针区分开来。因此,一切都会看起来很好,直到你在代码中稍后分段30行,并且不知道什么是错的。:)

+0

你的回答对我来说似乎是正确的,但另一个答案与你相矛盾。通常我可以通过运行代码来判断谁是正确的,但是这次看起来不是这样,因为你提到的原因(以后不会崩溃)。有没有办法证明哪个答案是正确的,还是我应该在这里和我一起去? – Andrew 2014-09-14 22:30:31

+1

@Andrew,未使用的'int'是不必要的。重要的是指针中的地址,这可能是一个C++对象。将结果设置为4字节结构在64位系统上是错误的;截断指针地址。你可以使用'c_void_p',但为了更好的类型安全性,使用指向结构体的指针。你不需要定义'_fields_'。你可以使用'HGRABBER = POINTER(type('HGRABBER',(Structure,),{}))'。 – eryksun 2014-09-15 05:47:58

+0

@eryksun:关于使用指向空结构的指针来表示Win32 API中经常使用的“不透明句柄”的好建议。 – abarnert 2014-09-15 17:39:54

1

该库做了什么你正在尝试做的:https://github.com/morefigs/py-ic-imaging-control :)

但是,为了回答你的问题,库使用代码:

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() 

编辑:改变的代码使用指针根据abarnert的回答,为GrabberHandle,因为这是正确的。但是,在这种特殊情况下,我发现没有实际区别(使用32位DLL),可能是因为GrabberHandle结构非常简单。

+0

我同意代码的作品,但是当我对代码进行微小的修改时会遇到访问冲突,我认为这可能是相关的。另外我使用64位,我认为你使用的是32. – Andrew 2014-09-14 22:32:27

+1

不相关,但是当你在这里时:set_format方法是怎么回事?如果调用它会崩溃,但是没有文档说在获取图像之前设置sink格式是强制性的? – Andrew 2014-09-14 22:34:58

+0

你需要使用64位DLL吗?你在使用64位的Python吗?他们必须匹配。我正在使用32位Python和DLL(在64位Windows 7上)。 – 101 2014-09-14 23:50:03