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

时间:2008-09-30 23:05:08

标签: 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

我认为在“if cancel then then”之前我需要一个“DoEvents”有更好的方法吗?已经有一段时间......

8 个答案:

答案 0 :(得分: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

答案 1 :(得分:8)

不,你必须使用DoEvents,否则所有UI,键盘和Timer事件都会在队列中等待。

你唯一能做的就是每1000次迭代调用一次DoEvents。

答案 2 :(得分:7)

“for”循环是否在GUI线程中运行?如果是,是的,你需要一个DoEvents。您可能希望使用单独的Thread,在这种情况下不需要DoEvents。你can do this in VB6(不简单)。

答案 3 :(得分:4)

你可以在一个单独的线程上启动它,但在VB6中它是一个皇家的痛苦。 DoEvents应该工作。这是一个黑客攻击,但VB6也是如此(这位10年的VB老将在这里说话,所以不要让我失望)。

答案 4 :(得分:4)

将长期运行的任务划分为quanta。这些任务通常由简单的循环驱动,因此将其分成10,100,1000等迭代。使用Timer控件,每次触发时都会执行部分任务并保存其状态。首先,设置初始状态并启用Timer。完成后,禁用Timer并处理结果。

你可以通过改变每个量子的工作量来“调整”这一点。在Timer事件处理程序中,您可以检查“取消”并根据需要提前停止。您可以通过将工作负载和Timer捆绑到带有已完成事件的UserControl来使其更加整洁。

答案 5 :(得分:4)

当我需要它时,这对我很有用。它检查用户是否按下了退出键以退出循环。

请注意,它有一个非常大的缺点:它会检测用户是否在任何应用程序上点击了转义键 - 而不仅仅是你的。但是当你想给自己一个中断长时间运行循环的方法,或者按住shift键以绕过一些代码时,这是开发中的一个很好的技巧。

Option Explicit

Private Declare Function GetAsyncKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer

Private Sub Command1_Click()
    Do
        Label1.Caption = Now()
        Label1.Refresh
        If WasKeyPressed(vbKeyEscape) Then Exit Do
    Loop

    Label1.Caption = "Exited loop successfully"

End Sub

Function WasKeyPressed(ByVal plVirtualKey As Long) As Boolean
    If (GetAsyncKeyState(plVirtualKey) And &H8000) Then WasKeyPressed = True
End Function

GetAsyncKeyState的文档在这里:

http://msdn.microsoft.com/en-us/library/ms646301(VS.85).aspx

答案 6 :(得分:4)

编辑 turns out MSDN文章存在缺陷且技术DOESN'T WORK :(

这是一篇关于使用.NET BackgroundWorker组件在VB6中的另一个线程上运行任务的文章。

答案 7 :(得分:4)

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

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

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

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

相关问题