ctypes回调在调试时工作(或多或少),但不是独立的

时间:2018-03-01 12:55:55

标签: python callback ctypes

pycanon包不适用于佳能目前的ED SDK,因此我从头开始制作一个新的。进步是一步一步的,但现在我不得不抓住相机的事件,它会调用一个回调机制。它至少有两个问题,它们可能是相互关联的。

首先,这是我调用的回调函数:

def propertyChanged(*args):
    print(args)
    return window.propertyChanged(*args)

在头文件中,定义为:

#if defined( BUILD_EDSDK_DLL )
    #define EDSAPI  EDSEXPORT EDSSTDCALL
#else
    #define EDSAPI  EDSIMPORT EDSSTDCALL
#endif
/*-----------------------------------------------------------------------------
//
//  Function:   EdsSetPropertyEventHandler
//              
//  Description:
//       Registers a callback function for receiving status 
//          change notification events for property states on a camera.
//
//  Parameters:
//       In:    inCameraRef - Designate the camera object. 
//              inEvent - Designate one or all events to be supplemented.
//              inPropertyEventHandler - Designate the pointer to the callback
//                      function for receiving property-related camera events.
//              inContext - Designate application information to be passed by 
//                      means of the callback function. Any data needed for
//                      your application can be passed. 
//      Out:    None
//
//  Returns:    Any of the sdk errors.
-----------------------------------------------------------------------------*/
EdsError EDSAPI EdsSetPropertyEventHandler(
            EdsCameraRef                    inCameraRef, 
            EdsPropertyEvent                inEvnet,           
            EdsPropertyEventHandler         inPropertyEventHandler,
            EdsVoid*                        inContext );

它或多或少地起作用,因为它被(有时)适当的参数调用。错误的是,当我不在调试器中时,参数似乎被两个longInts抵消了。

查看下面列出的完整测试程序,尤其是run() - 方法。 我期望的是camera.setAEMode(5)会触发回调。它没有,但camera.getBodyID()它上面的两行是这样做的,而我不希望这样。我想这只是我对API工作的理解而不是我遇到的问题。

当执行camera.getBodyID()testCallback为真)和propertyChanged中的断点时,我看到我用参数(257,3,0,129568680)调用,这是有意义的:

  • 257是枚举EdsPropertyEvents.PropertyChanged的整数值;
  • 3枚举EdsPropID.bodyID;
  • 的整数值
  • 0是我不使用的可选参数,并指定为零
  • 我假设的最后一个参数是上下文指针,我不会使用,而我不知道如何将其转换回Python中有意义的内容。

但是,如果在未调试时运行完全相同,则传递给propertyChanged的参数为(107020331,106511131,257,3)。

还有第二个问题:当我不指定回调函数时,程序运行正常。但是当我将True分配给testCallback时,程序在从回调返回后崩溃(异常:访问冲突在未调试时读取0x0000002B,或者为了响应getBodyID()而触发PROPERTIES_UNAVAILABLE)。当程序运行时没有触发回调函数(# camera.getBodyID()),但仍然分配它,然后python.exe在离开run() - 方法后崩溃,并且认为告诉微软有一个好主意。< / p>

我该怎么做才能使这项工作?

from PyQt5.Qt import *  # @UnusedWildImport
from canonSDK import edSDK
from canonSDK.edSDK import EDSDK
import traceback
from canonSDK.EDSDKtypes import *  # @UnusedWildImport
from ctypes import py_object


# copy of self of the main-window object; 
# necessary since it is exceedingly hard to pass self thru the callback
window = None


def propertyChanged(*args):
    print(args)
    return window.propertyChanged(*args)


class RCmain(QWidget):

    def __init__(self):
        super().__init__()
        global window
        window = self

        QVBoxLayout(self)        
        self.console = QTextBrowser()
        self.layout().addWidget(self.console)
        pnl = QFrame(); self.layout().addWidget(pnl)
        pnl.setFixedHeight(30)
        btn = QPushButton("run", parent = pnl)
        btn.clicked.connect(self.run)
        sys.excepthook = self.exceptionHook


    def show(self):
        super().show()

        # initialize dll connection:
        self.edsdk = EDSDK()
        self.edsdk.initializeSDK()
        self.camera = None

        # show success by listing the connected cameras:
        l = self.edsdk.getCameraList()
        n = self.edsdk.getChildCount(l)

        self.print(n, "cameras:")
        for c in self.edsdk.cameras:
            self.print(c.index, ":", c.name)


    def close(self):
        self.edsdk.terminateSDK()
        if self.camera is not None:
            self.camera.close()
        super().close()


    def exceptionHook(self, type, value, tback):
        traceback.print_exception(type, value, tback)


    def print(self, *args):
        print(*args)
        self.console.append(" ".join([str(a) for a in args]))


    #WINFUNCTYPE (EdsError,  EdsPropertyEvent, EdsPropertyID, EdsUInt32, EdsVoid)        
    def propertyChanged(self, inEvent, inPropertyID, inParam, inContext):
        self.print(inEvent, inPropertyID, inParam, inContext)                  
        self.print(EdsPropID(inPropertyID).name, "has changed") # EdsPropID is an IntEnum
        return 0


    def run(self):
        # test sequence

        camera       = self.edsdk.getCamera(0)
        testCallback = True

        if testCallback:
            self.edsdk.setPropertyEventHandler(camera.reference, 
                                               EdsPropertyEvents.All, 
                                               EdsPropertyEventHandler(propertyChanged))

        self.print(camera.getProductName())
        self.print(camera.getBodyID())
        self.print(camera.getAEMode())
        camera.setAEMode(5)
        self.print(camera.getAEMode())

        camera.startLiveView()        
#       camera.downloadEvfData() # 2b impl'd
        camera.endLiveView()

        self.camera  = camera



if __name__ == '__main__':
    import sys

    edSDK.setDllPath('D:/python3/remote shooting/EDSDKv2.7/EDSDK/Dll')
    app = QApplication(sys.argv)

    w = RCmain()
    w.show()


    app.exec_() 

0 个答案:

没有答案