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

取消VB6.0中没有DoEvents的长时间运行的进程?,vb6,Vb6,在VB6.0中,是否可以取消长时间运行的进程而不使用DoEvents 例如: for i = 1 to someVeryHighNumber ' Do some work here ' ... if cancel then exit for end if next Sub btnCancel_Click() cancel = true End Sub 我想我需要一个“DoEvents”在“if cancel then…”之前有更好的方

在VB6.0中,是否可以取消长时间运行的进程而不使用DoEvents

例如:

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

    if cancel then
        exit for
    end if
next

Sub btnCancel_Click()
    cancel = true
End Sub

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

GUI线程中是否运行“for”循环?如果是这样的话,是的,你需要一份工作。您可能希望使用单独的线程,在这种情况下,不需要DoEvents。您(不简单)。

不,您必须使用DoEvents,否则所有UI、键盘和计时器事件都将在队列中等待


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

你可以在一个单独的线程上启动它,但在VB6中这是一个巨大的难题。这些事件应该有效。这是一种黑客行为,但VB6也是如此(10年的VB老手在这里讲话,所以不要贬低我)。

将长期运行的任务划分为数量。这样的任务通常由一个简单的循环驱动,所以将其划分为10、100、1000等迭代。使用计时器控件,每次它触发时都执行部分任务,并在执行时保存其状态。要启动,请设置初始状态并启用计时器。完成后,禁用计时器并处理结果


你可以通过改变每个量子所做的功来“调整”它。在计时器事件处理程序中,您可以检查“取消”并根据需要提前停止。通过将工作负载和计时器与已完成的事件绑定到UserControl中,您可以使一切更加整洁。

不,您做对了,您肯定希望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
顶部的“
”:
将函数GetQueueStatus Lib“user32”(ByVal qsFlags为Long)声明为Long
'然后将其称为而不是DoEvents:
Sub-DoeventSifRequired()
如果GetQueueStatus(255)为0,则为DoEvents
端接头

当我需要它时,它非常适合我。它检查用户是否按了退出键退出循环

请注意,它有一个很大的缺点:它将检测用户是否在任何应用程序上按了escape键,而不仅仅是您的应用程序。但是,在开发中,当您想给自己一种方法来中断长时间运行的循环,或者一种方法来按住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的文档如下:

编辑如果MSDN文章有缺陷,则技术:(


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

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

  • VB6 ActiveX EXE对象应公开一个事件CheckQuitDoStuff()。这需要一个名为Quit的ByRef布尔值
  • 客户端在ActiveX EXE对象中调用StartTouch。此例程在隐藏窗体上启动计时器,立即返回。这将取消阻止调用线程。计时器间隔非常短,因此计时器事件会快速触发
  • 计时器事件处理程序禁用计时器,然后调用ActiveX对象DoStuff方法。这将开始冗长的处理
  • DoStuff方法定期引发CheckQuitDoStuff事件。客户端的事件处理程序检查特殊标志,并在需要中止时将Quit设置为True。然后,DoStuff中止计算,如果Quit为True,则提前返回
这个方案意味着客户端实际上不需要是多线程的,因为调用线程在“DoStuff”时不会阻塞正在发生。棘手的部分是确保DoStuff以适当的间隔引发事件-太长,并且您不能在需要时退出:太短,并且您正在不必要地减慢DoStuff。此外,当DoStuff退出时,它必须卸载隐藏的窗体


如果DoStuff真的设法在中止之前完成所有的事情,你可以提出一个不同的事件来告诉客户端这个任务已经完成了。

如果你想快速取消,你想在每次迭代中调用doEvices。VB运行时处于一种状态,当你不希望它崩溃时,它可能会崩溃。所以我没有使用它。好吧,我是,但只是在运行中动态生成的小asm程序,它不调用任何运行时函数。我应该说“…但在VB6中,这是你可能做的最疯狂的事情。”是的,VB6中关于线程的双重、三重、四重警告。你可以让一个演示应用程序工作,但仅此而已。我想你被否决了,因为你说他“最好使用单独的线程”。这里唯一的问题是,你还必须禁用除“取消”之外的所有其他功能按钮。+1,因为这直接回答了问题,显示了一种允许取消的方法,无需DoEvents,也无需在VB6中建议(恐怖!)线程。。。