需要做某耗时较长的操作,所以无私地用DoEvents转让控制权,可是这时间用户又来操作本程序,结果弹出了一个模式窗体,而用户当时并没有及时将该模式窗体关闭,结果程序运行了两天两夜,发现还停留在原地!!!呜呼~~偶是这样理解这个问题的,因为DoEvents转让了控制权,所以在后台程序运行的同时,消息队列里的消息就可能插个队,优先处理一下下。结果处理的过程当中弹出了模式窗体,在模式窗体未关闭之前,都在这个消息的处理范围,所以这个消息并没有被处理完毕。所以程序的焦点就一直挂在模式窗体那里,除非人为操作去释放请问有办法解决这样的问题吗?偶现在的难处是:对于偶的程序而言,模式窗体弹出后没有人来关闭很正常,因为偶的程序经常在没有人看着的情况下运行好几天。偶也不能弹出非模式窗体,因为偶的客户一旦在程序前,就老喜欢乱点乱按,把程序弄乱。偶跟客户商量,要不然不弹窗体,偶给个别的提示好不好?比如进程外的消息,他们还不同意。哎被这个问题折磨的头痛,所以请大家帮帮忙啦~~

解决方案 »

  1.   

    转让控制权,以便让操作系统处理其它的事件。DoEvents 函数会返回一个 Integer,以代表 Visual Basic 独立版本中打开的窗体数目,例如,Visual Basic,专业版,在其它的应用程序中,DoEvents 返回 0。DoEvents 会将控制权传给操作系统。当操作系统处理完队列中的事件,并且在 SendKeys 队列中的所有键也都已送出之后,返回控制权。DoEvents 对于简化诸如允许用户取消一个已启动的过程 — 例如搜寻一个文件 — 特别有用。对于长时间过程,放弃控制权最好使用定时器或通过委派任务给 ActiveX EXE 部件来完成。以后,任务还是完全独立于应用程序,多任务及时间片由操作系统来处理。小心 确保以 DoEvents 放弃控制权的过程,在第一次 DoEvents 返回之前,不能再次被其他部分的代码调用;否则会产生不可预料的结果。此外,如果其它的应用程序可能会和本过程以不可预知的方式进行交互操作,那么也不要使用 DoEvents,因为此时不能放弃控制权。使用 DoEvents尽管 Timer 事件是后台处理的最好工具,对耗时极多的任务,情况更是如此,但是,DoEvents 函数还是提供了一种取消任务的简便方法。例如,下列代码将显示一个 "Process" 按钮,单击这个按钮时,它将变成 "Cancel" 按钮。再次单击按钮又将中断正在执行的任务。'此按钮标题是 "Process"
    Private Sub Command1_Click()
    '过程的所有实例都共享静态变量。
      Static blnProcessing As Boolean
      Dim lngCt As Long
      Dim intYieldCt As Integer
      Dim dblDummy As Double
      '按下按钮时,检测是否在处理
      If blnProcessing Then
       '如果正在处理,则取消
          blnProcessing = False
      Else
          Command1.Caption = "Cancel"
          blnProcessing = True
          lngCt = 0
       '执行一百万次浮点乘法计算。每一千次后,检测是否要取消。
          Do While blnProcessing And (lngCt < 1000000)
            For intYieldCt = 1 To 1000
                lngCt = lngCt + 1
                dblDummy = lngCt * 3.14159
            Next intYieldCt
          'DoEvents 语句允许其它事件发生,包括第二次按此按钮。
            DoEvents
          Loop
          blnProcessing = False
          Command1.Caption = "Process"
          MsgBox lngCt & " multiplications were performed"
      End If
    End SubDoEvents 将控制切换到操作环境内核。只要此环境中的所有应用程序都有机会响应待处理事件,应用程序就又恢复控制。这不会使应用程序放弃焦点,但会使后台事件能够得到处理。这种妥协的结果可能并不总是达到预期目标。例如,下述 Click 事件代码在单击按钮后要一直等候十秒钟,而后才显示一条信息。如果在按钮正在等待期间单击它,则将以相反顺序完成单击操作。Private Sub Command2_Click()
      Static intClick As Integer
      Dim intClickNumber As Integer
      Dim dblEndTime As Double
          '每次单击按钮时
          '赋予唯一数值。
      intClick = intClick + 1
      intClickNumber = intClick
          '等待十秒。
      dblEndTime = Timer + 10#
      Do While dblEndTime > Timer
          '不做任何事情,仅仅允许
          '其它应用程序处理
          '它们的事件。
          DoEvents
      Loop
      MsgBox "Click " & intClickNumber & " is finished"
    End Sub对于通过 DoEvents 放弃控制的事件过程,有时可能希望防止在 DoEvents 返回之前重新调用这一过程。否则将无穷无尽地调用该过程,直到系统资源消耗殆尽。可暂时禁止控件,或象上例一样,使用一个静态的“标志”变量防止此事发生。在使用全局数据时避免 DoEvents
    当一个函数已通过 DoEvents 放弃控制时,可相当安全地再次调用函数。例如,下一过程将检测质数并用 DoEvents 语句周期地启动其它应用程序处理事件:Function PrimeStatus (TestVal As Long) As Integer
      Dim Lim As Integer
      PrimeStatus = True
      Lim = Sqr(TestVal)
      For I = 2 To Lim
          If TestVal Mod I = 0 Then
            PrimeStatus = False
            Exit For
          End If
          If I Mod 200 = 0 Then DoEvents
      Next I
    End Function该代码中每重复 200 次就调用一次 DoEvents 语句。这样一来,当该环境的其余部分对事件作出响应时,只要有必要,PrimeStatus 过程就可继续计算。考虑在调用 DoEvents 期间发生的事情。在其它窗体和应用程序处理事件时将暂停执行应用程序代码。这些事件之一有可能是一个按钮单击操作,它将再次启动 PrimeStatus 过程。这将导致重新进入 PrimeStatus 过程的,但是,因为在函数每次出现时,堆栈都为其参数和局部变量分配了空间,所以重入不会引发冲突。当然,如果过多调用 PrimeStatus,则可能出现“溢出堆栈空间”错误。如果 PrimeStatus 使用或改变模块级变量或全局数据,情况就会完全不同。此时,在 DoEvents 能够返回之前执行 PrimeStatus 的另一个实例,这将导致模块数据或全局数据的值完全不同于它们在调用 DoEvents 之前的值。于是,PrimeStatus 的结果将会难以预料。
      

  2.   

    很简单阿,一是不要用模式窗体,用普通窗体。
    二是在这个非常耗时的操作进行的时候不允许其他耗时操作进行或不允许本次过程再调用。
    比如你要做一个数据库的合并,需要一个小时,在你这个执行合并的按钮被按下后,就将这个按钮设为不可用,把它DISABLE掉,等此操作完成后再恢复可用状态。这样就避免了逻辑上的混乱。
      

  3.   

    To WallesCai(第一周上班,没有双休,只有工作) :
    谢谢解答,偶的问题是这样的,现系统提供操作A和操作B。操作A可能耗时1小时,用户在操作已经执行的过程中,看看操作A的执行情况(系统会将这一个小时的进展情况及时通知),可能随时要进行B操作。所以我只好用DoEvents来放开控制权模式窗体是进行操作B时弹出的,但是这个模式窗体却挂住了操作A。不能用非模式窗体,因为用户可能乱操作。我跟客户建议弹出一个txt文件,里面显示想要的信息,但是客户不同意。项目验收在即,只剩这一个问题了,请大家来帮帮忙阿!~
      

  4.   

    将 A 操作独立编成一个 exe,用户点了 A 操作按钮后就用 Shell 执行该 exe
    参考下面代码判断 exe 是否执行结束
    http://www.zjol.com.cn/vbbible/software/program/vb/tips2/windows.htm#6
      

  5.   

    To Tiger_Zhao(VB老鸟) :谢谢你帮我支招,可是客户不同意这样做,还有什么别的办法吗?