2008-09-30 19 views
20

¿Es posible cancelar un proceso largo en VB6.0 sin utilizar DoEvents?¿Cancela un proceso de larga ejecución en VB6.0 sin DoEvents?

Por ejemplo:

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

    if cancel then 
     exit for 
    end if 
next 

Sub btnCancel_Click() 
    cancel = true 
End Sub 

Asumo que necesita una "DoEvents" antes de que el "si cancelar entonces ..." ¿hay una manera mejor? Ha pasado un tiempo ...

Respuesta

28

No, lo tienes bien, definitivamente quieres DoEvents en tu circuito.

Si coloca DoEvents en su bucle principal y descubre que ralentiza demasiado el procesamiento, intente llamar a la función API de Windows GetQueueStatus (que es mucho más rápido que DoEvents) para determinar rápidamente si es necesario llamar a DoEvents. GetQueueStatus le informa si hay algún evento para procesar.

' 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 
7

¿Se está ejecutando el bucle "for" en el hilo de la GUI? Si es así, sí, necesitarás un DoEvents. Es posible que desee utilizar un subproceso separado, en cuyo caso un DoEvents no sería necesario. Usted can do this in VB6 (no es simple).

+0

Eso es VB6, no vb.net. – GSerg

+0

Creo que estabas desanimado porque dijiste que estaría "mejor usando un hilo separado". – MusiGenesis

+0

de acuerdo, y corregido. – TheSoftwareJedi

8

No, tiene que utilizar DoEvents, de lo contrario, todos los eventos de IU, teclado y temporizador seguirán esperando en la cola.

Lo único que puede hacer es llamar a DoEvents una vez por cada 1000 iteraciones o similares.

+0

Si desea cancelar rápidamente, querrá llamar a DoEvents en cada iteración. – MusiGenesis

4

Puede iniciarlo en un hilo separado, pero en VB6 es un dolor real. DoEvents debería funcionar. Es un truco, pero también lo es VB6 (veterano de VB de 10 años hablando aquí, así que no me modifiques).

+0

hmm, lo mismo dije, pero me votaron ... bueno ... – TheSoftwareJedi

+0

Usar CreateThread en VB6 tiene algunas implicaciones que en algunos casos son demasiado fatales de considerar. Pone el tiempo de ejecución de VB en un estado en el que puede bloquearse cuando no lo esperas. Entonces no lo estoy usando. Bueno, lo estoy, pero solo para ejecutar pequeños PCs generados sobre la marcha que no llaman a ningún func de tiempo de ejecución. – GSerg

+0

Debería haber dicho "... pero en VB6 es lo más loco que podrías hacer". – MusiGenesis

4

Divida la tarea de larga ejecución en cuantos. Tales tareas a menudo son impulsadas por un simple bucle, así que córtalo en iteraciones de 10, 100, 1000, etc. Use un control de temporizador y cada vez que dispare haga parte de la tarea y guarde su estado sobre la marcha. Para comenzar, configure el estado inicial y active el temporizador. Cuando termine, desactive el temporizador y procese los resultados.

Puede "ajustar" esto cambiando la cantidad de trabajo que se realiza por quantum. En el controlador de eventos Timer puede verificar si se "cancela" y detenerse antes de lo necesario. Puede hacerlo todo más ordenado agrupando la carga de trabajo y el temporizador en un control de usuario con un evento completado.

+0

El único problema aquí es que también tiene que desactivar todo lo demás excepto el botón "Cancelar". +1 porque responde la pregunta directamente, mostrando una forma de permitir la cancelación sin DoEvents, y sin sugerir (¡horrores!) Enhebrar en VB6 ... – JeffK

4

Esto funciona bien para mí cuando lo necesito. Verifica si el usuario ha presionado la tecla de escape para salir del ciclo.

Tenga en cuenta que tiene un gran inconveniente: detectará si el usuario pulsa la tecla Escape en CUALQUIER aplicación, no solo la suya. Pero es un gran truco en el desarrollo cuando quieres darte una manera de interrumpir un bucle de ejecución larga, o una forma de mantener presionada la tecla Mayús para eludir un poco de código.

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 

Documentación para GetAsyncKeyState está aquí:

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

+1

Control-PauseBreak también funciona de maravilla durante el desarrollo – rpetrich

3

Aquí hay un esquema bastante estándar para el procesamiento de fondo asincrónico en VB6. (Por ejemplo, está en Dan Appleman's book y Microsoft VB6 samples). Usted crea un EXE de ActiveX separado para hacer el trabajo: de esa manera el trabajo se realiza automáticamente en otro hilo, en un proceso separado (lo que significa que no tiene que preocuparse por variables pisoteadas).

  • El objeto EXE ActiveX VB6 debe exponer un evento CheckQuitDoStuff(). Esto toma un booleano ByRef llamado Salir.
  • El cliente llama a StartDoStuff en el objeto EXE de ActiveX. Esta rutina inicia un temporizador en un formulario oculto y devuelve inmediatamente. Esto desbloquea el hilo de llamada. El intervalo del temporizador es muy corto, por lo que el evento del temporizador se dispara rápidamente.
  • El controlador de eventos Timer desactiva el temporizador y luego vuelve a llamar al método DoStuff del objeto ActiveX. Esto comienza el procesamiento largo.
  • Periódicamente, el método DoStuff plantea el evento CheckQuitDoStuff. El controlador de eventos del cliente verifica la bandera especial y establece Salir verdadero si es necesario abortar. Entonces DoStuff aborta el cálculo y regresa temprano si Quit es verdadero.

Este esquema significa que el cliente no necesita ser multiproceso, ya que el hilo de llamada no se bloquea mientras está ocurriendo "DoStuff". La parte difícil es asegurarse de que DoStuff plantea los eventos a intervalos apropiados, demasiado tiempo, y no se puede abandonar cuando se quiere: demasiado corto, y se está desacelerando DoStuff innecesariamente. Además, cuando DoStuff se cierra, debe descargar el formulario oculto.

Si DoStuff realmente logra hacer todo esto antes de ser cancelado, puede plantear un evento diferente para decirle al cliente que el trabajo ha finalizado.

Cuestiones relacionadas