在没有DoEvents的情况下在VB6.0中取消长时间运行的进程?

Stu*_*wig 21 vb6

是否可以在不使用DoEvents的情况下取消VB6.0中长时间运行的进程?

例如:

for i = 1 to someVeryHighNumber
    ' Do some work here '
    ...

    if cancel then
        exit for
    end if
next

Sub btnCancel_Click()
    cancel = true
End Sub
Run Code Online (Sandbox Code Playgroud)

我假设我需要一个"DoEvents"才能"如果取消那么......"还有更好的方法吗?有一阵子了...

Joe*_*sky 29

不,你做对了,你肯定想要循环中的DoEvents.

如果您将DoEvents主循环放入并发现减慢处理过多,请尝试调用Windows API函数GetQueueStatus(比DoEvents快得多)以快速确定是否甚至需要调用DoEvents.GetQueueStatus告诉您是否有任何要处理的事件.

' at the top:
Declare Function GetQueueStatus Lib "user32" (ByVal qsFlags As Long) As Long

' then call this instead of DoEvents:
Sub DoEventsIfNecessary()
    If GetQueueStatus(255) <> 0 Then DoEvents
End Sub
Run Code Online (Sandbox Code Playgroud)


GSe*_*erg 8

不,您必须使用DoEvents,否则所有UI,键盘和Timer事件将在队列中等待.

您唯一能做的就是每1000次迭代调用一次DoEvents等.


The*_*edi 7

"for"循环是否在GUI线程中运行?如果是,是的,你需要一个DoEvents.您可能希望使用单独的Thread,在这种情况下不需要DoEvents.您可以在VB6中完成这个(不简单).


Mar*_*rkJ 5

这是 VB6 中异步后台处理的一个非常标准的方案。(例如,在 Dan Appleman 的书中和 Microsoft 的 VB6示例中。)您创建一个单独的 ActiveX EXE 来完成这项工作:这样,工作就会在单独的进程中自动在另一个线程上进行(这意味着您不必担心变量被践踏)。

  • VB6 ActiveX EXE 对象应公开事件 CheckQuitDoStuff()。这需要一个名为 Quit 的 ByRef 布尔值。
  • 客户端在 ActiveX EXE 对象中调用 StartDoStuff。该例程在隐藏窗体上启动一个计时器并立即返回。这会解除调用线程的阻塞。定时器间隔非常短,因此定时器事件触发得很快。
  • Timer 事件处理程序禁用 Timer,然后回调 ActiveX 对象的 DoStuff 方法。这开始了漫长的处理。
  • DoStuff 方法定期引发 CheckQuitDoStuff 事件。客户端的事件处理程序检查特殊标志,并在需要中止时设置 Quit True。然后,如果 Quit 为 True,DoStuff 将中止计算并提前返回。

此方案意味着客户端实际上不需要多线程,因为调用线程在“DoStuff”发生时不会阻塞。棘手的部分是确保 DoStuff 以适当的间隔引发事件 - 太长,您无法在想要退出时退出:太短,您会不必要地减慢 DoStuff 的速度。另外,当 DoStuff 退出时,它必须卸载隐藏的表单。

如果 DoStuff 实际上在中止之前成功完成了所有工作,您可以引发一个不同的事件来告诉客户端作业已完成。