Python COM 事件处理被阻塞

0 投票
1 回答
3941 浏览
提问于 2025-04-18 06:46

我正在用Python实现COM,因为我需要在两个不同的软件之间进行交互,一个是dSPACE HIL环境,另一个是Vector CANOE环境。我的想法是,当我在CANOE的CAPL脚本中更改环境变量时,希望在dSPACE HIL上执行一些操作。目前我还没有实现任何线程。

(1) 第一个问题是,当我尝试使用简单的睡眠(sleep)来确保CANOE中的测试执行完成时,执行并没有发生,因为Python的睡眠会阻塞CANOE的执行。而且每当环境变量变化时,我都会收到pythoncom错误:调用COM方法时出现Python错误。所以CANOE的执行只能在Python的睡眠结束后才开始,并且我在CANOE中会看到一个弹窗提示“服务器忙”。

当我使用消息框时,用户需要在测试执行完成后按一下按钮,这样执行就能正常工作。我想用其他机制,比如睡眠,来替代这个消息框。请告诉我如何解决这个问题。我把我的脚本粘贴在下面。

class EnvironmentEvents:
    def __init__ ( self ) :
        print "Initializing Environment Event Class"
 
    def OnChange ( self , value ) :
        StopTestExecution = Value
        print '% 3.2f' % StopTestExecution
        print ( 'Environment Variable Value Changed' )
 
# # # # # # # # # # # # # # # # # # # INITIALIZE CONTROL DESK # # # # # # # # # # # 
MyControlDeskHandler = Controldesk_Handler. CONTROLDESK_HANDLER ()
 
# # # # # # # # # # # # # # # # # # # INITIALIZE CANOE # # # # # # # # # # # # # #  
MyCAN                = Dispatch ( 'CANoe.Application' )
MyCANMeasurement     = MyCAN. Measurement
MyCANEnvironment     = MyCAN. Environment . GetVariable ( "env_COM_BatteryVoltage" )
My events            = Dispatch WithEvents ( MyCANEnvironment , EnvironmentEvents )
 
Test Setup = MyCAN. Configuration . Test Setup
    TestEnvs = test setup. Test Environments
Testenv = TestEnvs. Item ( 1 )
Testenv. ExecuteAll ( )            
 
    ## Msgbox (0, "Test Completed", "info", 16) ## with a message box everything is working fine

    while ( StopTestExecution > 0 ):
            print '% 3.2f' % StopTestExecution
            Sleep ( 500 )    

           

我的想法是从CAPL发送事件变量值为0,以停止执行。在此之前,循环必须继续进行。但这并没有奏效。

(2) 第二个问题是,当发生OnChange事件时,我想在dSPACE HIL控制桌面中更改一些东西。为此,我需要使用dSPACE提供的一个库。但问题是我该如何在Events类中访问这个库及其方法。我尝试将dSPACE库对象和参数作为参数传递给EnvironmentEvents类,如下所示。但Python给了我以下错误。目前我只是将它作为全局变量使用,这样可以正常工作。但如果有更好的替代方案,我希望能避免这样做。

class EnvironmentEvents:
    def __init__ ( self , ControlDeskhandler , Path ) :
        print "Initializing Environment Event Class"
        self . MyHandler = ControlDeskhandler
        self . MyPath = Path
 
    def OnChange ( self , value ) :
        StopTestExecution = Value
        print '% 3.2f' % StopTestExecution
        self . MyHandler . Write_Variable ( self . MyPath , Value )
        print ( 'Environment Variable Value Changed' )

    My events             = Dispatch WithEvents(MyCANEnvironment , Environment Events ( MyControlDeskHandler ,'Model Root/VOLTAGEOUT/ Value'))
 
Traceback ( most recent call load ) :
    .     File "C: \ P rogram Files (x86) \ C ommon Files \ d SPACE \ P ython25 \ l ib \ s ite-packages \ w in32com \ c lient \ __init__.py     " , line 304 , in Dispatch WithEvents
 result_class = new . classObj ( "COMEventClass" , ( disp_class , events_class , user_event_class ) , { "__setattr__": _event_setattr_ } )
TypeError : instance ( ) takes at most 2 arguments ( 3 givenName )
[ dbg ] >>>

请帮我解决这些问题。如果需要其他信息,请告诉我。

1 个回答

0

使用Sleep的一个问题是,它在休眠时不会处理消息,而COM需要处理消息才能正常工作。(MessageBox会处理消息,所以它可以正常工作。)

通常的解决办法是使用MsgWaitForMultipleObjectsEx和一个消息泵。显然,pythoncomwin32event有合适的封装。

win32Event.MsgWaitForMultipleObjectsEx需要一个句柄来等待;如果你需要等待特定的时间,最好创建一个可等待的定时器。奇怪的是,根据文档,win32eventOpenWaitableTimer,但没有CreateWaitableTimer。希望这是文档的错误。

不过,如果你不需要特定的时间,可以使用win32event.CreateEvent创建一个win32事件。这个事件可以是匿名的;你只需要它来等待。在你的OnChange处理函数中,你可以设置这个事件。

一旦你有了一个事件,就可以开始等待了。抱歉我的Python写得很糟糕;这段代码是从C语言转过来的。

def WaitAndPumpMessagesWithTimeout(hWaitHandle, dwMilliseconds) :
{
    fContinue = TRUE;

    while (fContinue)
        dwWaitId = win32event.MsgWaitForMultipleObjectsEx(1, hWaitHandle, dwMilliseconds, win32event.QS_ALLINPUT, win32event.MWMO_INPUTAVAILABLE);
        if (dwWaitId == win32event.WAIT_OBJECT_0)
             return TRUE;
        elif (dwWaitId ==  WAIT_OBJECT_0 + 1)
            pythoncom.PumpWaitingMessages();
        elif (dwWaitId  == WAIT_TIMEOUT)
           return FALSE;
    return TRUE;
}

撰写回答