如何使用 ctypes 和线程将内存分配给 C 回调函数

How to allocate memory to a C callback function with ctypes and threading

我目前正在为相机软件编写 python 绑定。商业 SDK 仅包含文档和 DLL。我没有 C 代码,但我会尽可能清楚,所以请多多包涵。

我可以使用所有库函数,但只有一个:获取图片的回调函数。文档仅提供函数原型:

foo: Starts image acquisition on specified port. Return error code.

int foo(HANDLE dev, char port, int queueMode, callback_type fnCallback, void * userInfo );

callback_type: Application-defined callback function that recieves information about acquired frame.

void callback_type(void * userInfo, photoStruct* photo);

这是我在加载库并包装函数和结构后的 python 代码。

callback_type = WINFUNCTYPE(None,c_void_p,POINTER(photoStruct)) 
def my_callback(userInfo, photoInfo):
    if(photoInfo.status == 0):
        #Process incoming photo
        print "I'm here" #for debugging purposes
        q.put(photoInfo.rawBuffer[:photoInfo.bufferSize])
        q.task_done()
_my_callback = callback_type(my_callback)

每当我第一次尝试调用 foo 时:

 >>>lib.foo(dev, port, c_int(0), _my_callback, None)

我收到错误代码 4:内存不足,无法执行操作(根据文档)。 当我再次(又一次)调用它时,它 returns 始终为 0,这是成功的,但队列保持为空并且它从不打印 "I'm here".

然后我尝试添加一个线程:

ty = threading.Thread(target=lib.foo, args=(dev,port, c_int(0), _my_callback, None))
>>> ty.start()   
>>> ty.run() 
line 758, in run
    del self.__target, self.__args, self.__kwargs  
AttributeError: _Thread__target

我也试过不使用 运行() 并在启动线程后直接调用该函数。它仍然不起作用。 我真的不知道这里发生了什么。我对线程和 ctypes 很陌生,但我的猜测是该库使用自己的线程来 return 照片,我应该以某种方式为此回调函数分配内存。但是怎么办? 任何 solutions/comments 将不胜感激。谢谢!

_ 编辑:文档中的示例代码 _

* \sample
* \code
* void __stdcall callback_type(void* userInfo, photoStruct* photo)
* {
*   // Process incoming photo
* }
* ...
* foo(dev, port, 0, &callback_type, NULL);
* ...
* \endcode
*/

我试图在 Python 中用

调用 foo
>>>lib.foo(dev, port, c_int(0), byref(_my_callback), None)

它停止了程序。

如果没有完整的示例,我不确定您哪里出错了。你声明了foo.argtypes吗?您确定函数 __stdcall 用于 WinDLLWINFUNCTYPE,还是 __cdecl 需要 CDLLCFUNCTYPE

这是一个使用以下 DLL 测试代码的工作示例:

typedef void* HANDLE;

typedef struct {
    int value;
} photoStruct;

typedef void (__stdcall * callback_type)(void * userInfo, photoStruct* photo);

__declspec(dllexport) int __stdcall foo(HANDLE dev, char port, int queueMode, callback_type fnCallback, void * userInfo)
{
    photoStruct p;
    p.value = 123;
    fnCallback(userInfo, &p);
    return 0;
}

Python代码:

#!python2
from ctypes import *
HANDLE = c_void_p

class photoStruct(Structure):
    _fields_ = [('value',c_int)]
    def __repr__(self):
        return 'photoStruct(value={})'.format(self.value)

callback_type = WINFUNCTYPE(None,c_void_p,POINTER(photoStruct))

@callback_type
def my_callback(userInfo, photo):
    print userInfo,photo.contents

foo = WinDLL('test').foo
foo.argtypes = (HANDLE,c_char,c_int,callback_type,c_void_p)
foo.restype = c_int

foo(1,'2',3,my_callback,None)

输出:

None photoStruct(value=123)