4

DLL から呼び出されるコールバック関数を Python で定義する必要があります。

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

このコードを試してみました.Python 2.5では動作するようですが、Python 2.7ではクラッシュし、何か間違ったことをしたと思います.

import ctypes, ctypes.wintypes
from ctypes.wintypes import DWORD

def cbFunc(port, user_data):
        print "Hurrah!"

CB_Func = ctypes.WINFUNCTYPE(None, DWORD, DWORD)

mydll.setCallback(ctypes.c_long(0), CB_Func(cbFunc), DWORD(0))

間違いはどこですか?

注: プラットフォームは 32 ビットのみで実行されます (Windows と Python の両方)。DLL は正常にロードされ、内部の他の関数も Python から呼び出されたときに正常に動作します。

これを再現する完全なサンプル コードは、https://github.com/ssbarnea/pyHikvisionで入手できます。py25 および py27 で Video.py を実行するだけです。

4

2 に答える 2

3

入れ子関数を使用するVideoクラスのコンテキストでは、次のようになります。

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で失敗します:

#XXX this won't work
@WINFUNCTYPE(None, DWORD, DWORD)
def cbFileRefDone(self, port, user_data):
    print "File indexed."

これを修正するには、特別な関数記述子を作成できます。

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関数への参照を保存して、ガベージコレクションが行われないようにします。

于 2011-10-27T21:17:16.277 に答える