在python回调函数中调用ctypes的正确方法是什么?

2024-10-01 15:33:23 发布

您现在位置:Python中文网/ 问答频道 /正文

我必须用Python定义一个回调函数,它将从DLL中调用。在

BOOL setCallback (LONG nPort, void ( _stdcall *pFileRefDone) (DWORD nPort, DWORD nUser), DWORD nUser);

我尝试了这段代码,它在python2.5中似乎可以工作,但是在python2.7中它崩溃了,我认为我做错了什么。在

^{pr2}$

哪里出错了?在

注意:该平台仅在32位(Windows和Python)上运行。DLL加载成功,从Python调用时,内部的其他函数也能正常工作。在

可以在https://github.com/ssbarnea/pyHikvision上找到一个完整的示例代码,只需运行视频.py在py25和py27下。在


Tags: 函数代码定义平台longbooldllvoid
2条回答

在使用嵌套函数的Video class上下文中:

class Video(object):

    def __init__(self, ...):
        self.__cbFileRefDone = []

    def open(self, filename):
        @WINFUNCTYPE(None, DWORD, DWORD)
        def cbFileRefDone(port, user_data):
            print "File indexed.", filename
        self.__cbFileRefDone.append(cbFileRefDone) # save reference

        if not self.hsdk.PlayM4_SetFileRefCallBack(
            c_long(self.port), cbFileRefDone, DWORD(0)):
            logging.error("Unable to set callback for indexing")
            return False

它有点难看,但在回调期间,一个更自然的变体因TypeError而失败:

^{2}$

要修复是否可以创建特殊函数描述符:

def method(prototype):
    class MethodDescriptor(object):
        def __init__(self, func):
            self.func = func
            self.bound_funcs = {} # hold on to references to prevent gc
        def __get__(self, obj, type=None):
            assert obj is not None # always require an instance
            try: return self.bound_funcs[obj,type]
            except KeyError:
                ret = self.bound_funcs[obj,type] = prototype(
                    self.func.__get__(obj, type))
                return ret
    return MethodDescriptor

用法:

class Video(object):

    @method(WINFUNCTYPE(None, DWORD, DWORD))
    def cbFileRefDone(self, port, user_data):
        print "File indexed."

    def open(self, filename):
        # ...
        self.hsdk.PlayM4_SetFileRefCallBack(
            c_long(self.port), self.cbFileRefDone, DWORD(0))

另外,MethodDescriptor保存对C函数的引用,以防止它们被垃圾回收。在

CB_chfunc(cbFunc)参数在setCallback函数之后立即进行垃圾回收。只要可以调用回调(15.17.1.17. Callback functions,最后一段),该对象就必须保持不变。把它赋给一个变量,并保持不变。以下是我的工作示例:

动态链接库

typedef unsigned int DWORD;
typedef long LONG;
typedef int BOOL;
#define TRUE  1
#define FALSE 0

typedef void (__stdcall *CALLBACK)(DWORD,DWORD);

CALLBACK g_callback = 0;
DWORD g_port = 0;
DWORD g_user = 0;

BOOL __declspec(dllexport) setCallback (LONG nPort, CALLBACK callback, DWORD nUser)
{
    g_callback = callback;
    g_port = nPort;
    g_user = nUser;
    return TRUE;
}

void __declspec(dllexport) Fire()
{
    if(g_callback)
        g_callback(g_port,g_user);
}

失败脚本

^{2}$

传递脚本

from ctypes import *

def cb_func(port,user):
    print port,user

x = CDLL('x')
CALLBACK = WINFUNCTYPE(None,c_uint,c_uint)
cbfunc = CALLBACK(cb_func)
x.setCallback(1,cbfunc,2)
x.Fire()

编辑:另外,由于CALLBACK是一个返回函数的函数,它可以用作Python回调的修饰符,从而消除回调超出范围的问题:

from ctypes import * 

CALLBACK = WINFUNCTYPE(None,c_uint,c_uint) 

@CALLBACK
def cb_func(port,user): 
    print port,user 

x = CDLL('x') 
x.setCallback(1,cb_func,2) 
x.Fire() 

相关问题 更多 >

    热门问题