在VB6中,为什么事件处理会在睡眠循环中停止?

时间:2018-11-16 23:31:53

标签: events vb6

我有一个VB6 ActiveX EXE,它具有用于它使用的OCX控件的事件处理程序。在ActiveX的Terminate函数中,我需要确保所有事件都已完成处理,然后再允许终止完成。在Terminate函数中,我在开始处添加了以下代码:

While EventsInProgressFlags <> 0
    DoEvents
    Sleep(200)
WEnd

EventsInProgressFlags是一个整数,用于设置正在进行的事件。但是,我观察到的是,当此循环运行正在进行的事件时,它永远不会完成。通过向事件和终止例程添加许多日志消息,我可以看到在调用Terminate函数时事件处理正在进行中,但是即使我正在调用DoEvents,在Terminate函数处于活动状态时,这些进行中的事件也不会执行。如果我强制Terminate函数退出循环,则事件处理将从中断处继续进行,但当然会出错,因为Terminate破坏了事件使用的组件。

我的睡眠循环中是否有办法允许正在进行的事件代码完成执行?

================更新11-20-2018 ==================

经过一些在线研究,我相信我会更好地理解原因,但是还没有解决方案。

在阅读Multithreading in VB6之后,我了解到VB6是单线程的,所以是的,我的OCX事件处理和Terminate函数都在同一线程中。因此,这就是为什么将Terminate函数置于睡眠状态无法正常工作的原因。由于它们都在同一个VB6线程中,因此我也将事件处理置于睡眠状态。我想知道在事件处理代码中间如何调用ActiveX Terminate函数。我的理论是,由于我的事件处理在进行系统调用时会系统调用该VB6,所以除了进行系统调用外,它还会调用DoEvents来服务Windows事件队列。这样做是为了使UI更具响应性。然后,调用DoEvents处理ActiveX终止调用的传入Windows事件。如果某些VB6专家可以在这里确认我的结论,我会感到感兴趣。

因此,一种可能的解决方案是在我处理OCX事件时是否存在某种方法来禁止系统调用DoEvent。有人知道这样做的方法吗?

另一种可能的解决方案是,如果有一种方法可以从Terminate函数返回,以便事件处理可以继续进行,但是直到事件处理完成之后才将Terminate函数的响应发送到主机。听起来似乎不太合理。

1 个答案:

答案 0 :(得分:0)

因此,一旦我了解了VB6是单线程的,便回到调试器中,并确认在执行Terminate函数时,VB6堆栈显示OCX事件处理在堆栈上进一步进行,直到Terminate函数返回。显然,我要完成的事件处理(在Terminate退出之前)正在同一线程中运行。 Terminate被“ VB6调用”,有效地中断了事件处理,这意味着完成事件处理的唯一方法是从Terminate命令返回。但是从“终止”返回会向主机发出通知(ActiveX EXE的主机),但实际上ActiveX对象并未终止。结果是终止函数返回后,OCX事件处理中出现错误。

我想要的是一种禁止处理ActiveX EXE传入命令的方法。在事件处理过程中,这将阻止执行Terminate函数。我找不到任何方法。

因此,我想出的不太优雅的解决方案是添加一个全局HasTerminated 由Terminate子例程设置的布尔标志。然后错误 生成错误 #91“对象变量或未设置块变量”的按钮事件例程的处理程序被修改为忽略错误#91,但前提是HasTerminated布尔标志是真的。这样做是中止任何导致错误的事件处理,但前提是ActiveX已终止。这是可以接受的解决方案,因为自组件终止以来,无需完成OCX事件。他们只需要不引起错误。这是我添加到所有事件处理例程中的示例错误处理程序。

M_SIGN_CAPTURE_FORM_CLEAR_CLICKED_ERR_HANDLER:
40  If HasTerminated And Err.Number = 91 Then
50      Resume 30 ' Resume at Exit Sub
60  End If

70  ErrBox "ERROR #" & Err.Number & " " & FILE__ _
        & ":m_SignCaptureForm_ClearClicked:" & Erl & Err.Description
80  Resume Next
End Sub