Cancelamento de um processo de longa duração em VB6.0 sem DoEvents?

StackOverflow https://stackoverflow.com/questions/155517

  •  03-07-2019
  •  | 
  •  

Pergunta

É possível cancelar a partir de um processo de longa duração em VB6.0 sem usar DoEvents?

Por exemplo:

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

    if cancel then
        exit for
    end if
next

Sub btnCancel_Click()
    cancel = true
End Sub

Eu suponho eu preciso um "DoEvents" antes do "se cancelar então ..." há uma maneira melhor? Tem sido um tempo ...

Foi útil?

Solução

Não, você tem razão, você quer definitivamente DoEvents em seu loop.

Se você colocar o DoEvents em seu loop principal e encontrar que retarda o processamento muito, tentar chamar a função API GetQueueStatus do Windows (que é muito mais rápido do que DoEvents) para determinar rapidamente se é mesmo necessário chamar DoEvents. GetQueueStatus diz-lhe se existem eventos para processo.

' 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

Outras dicas

Não, você tem que usar DoEvents caso contrário, todos UI, teclado e eventos de timer vai ficar esperando na fila.

A única coisa que você pode fazer é chamar DoEvents uma vez para cada 1000 iterações ou tal.

É o laço "for" em execução no thread de GUI? Se assim for, sim, você vai precisar de um DoEvents. Você pode querer usar um segmento separado, caso em que não seria necessária uma DoEvents. Você pode fazer isso em VB6 (não simples).

Você pode iniciá-lo em um segmento separado, mas em VB6 é uma dor real. DoEvents deve funcionar. É um truque, mas então é VB6 (10 anos veterano VB falando aqui, por isso não me down-mod).

Dividir a tarefa de longa duração em quanta. Tais tarefas são muitas vezes conduzido por um circuito simples, de modo a cortar em 10, 100, 1000, etc. iterações. Use um controle Timer e cada vez que incêndios fazem parte da tarefa e salvar seu estado como você vai. Para iniciar, configurar estado inicial e permitir que o temporizador. Quando concluído, desativar o temporizador e processar os resultados.

Você pode "afinar" isso alterando o quanto o trabalho é feito por quântica. No manipulador de evento Timer você pode verificar para "cancelar" e parar mais cedo, conforme necessário. Você pode fazer tudo mais puro ao integrar a carga de trabalho e temporizador em um UserControl com um evento concluído.

Isso funciona bem para mim quando eu precisar dele. Ele verifica se o usuário pressionou a tecla Esc para sair do loop.

Note que ele tem realmente uma grande desvantagem: ele irá detectar se o usuário pressione a tecla de escape em qualquer aplicação - e não apenas o seu. Mas é um grande truque em desenvolvimento quando você quer dar-se uma forma de interromper um ciclo de longa duração, ou uma maneira de manter pressionada a tecla SHIFT para ignorar um pouco 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

Documentação para GetAsyncKeyState está aqui:

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

Aqui é um esquema bastante normal para assíncrono processamento em segundo plano em VB6. (Por exemplo, é no de Dan Appleman livro e Microsoft do VB6 amostras .) Você cria um separar ActiveX EXE para fazer o trabalho: de que forma o trabalho é automaticamente em outro segmento, em um processo separado (o que significa que você não precisa se preocupar com variáveis ??ser pisoteado).

  • O objeto VB6 ActiveX EXE deve expor um evento CheckQuitDoStuff (). Isso leva um ByRef booleana chamada Quit.
  • O cliente chama StartDoStuff no objeto ActiveX EXE. Esta rotina inicia um timer em um formulário oculto e retorna imediatamente . Este desbloqueia o segmento chamado. O intervalo Timer é muito curto para que os incêndios evento Timer rapidamente.
  • O manipulador de evento Timer desativa o Timer, e então chama de volta para o método DoStuff objeto ActiveX. Isto começa o processamento longo.
  • Periodicamente o método DoStuff gera o evento CheckQuitDoStuff. verificações de manipulador de eventos do cliente a bandeira especial e conjuntos Sair True se é necessário abortar. Então DoStuff aborta o cálculo e retorna cedo se Quit é True.

Isto significa esquema que o cliente realmente não precisam ser multi-threaded, uma vez que o segmento de chamada não bloqueia enquanto "DoStuff" está acontecendo. A parte complicada é garantir que DoStuff levanta os eventos em intervalos apropriados - por muito tempo, e você não pode sair quando quiser: muito curto, e você está a abrandar DoStuff unecessarily. Além disso, quando sai DoStuff, deve descarregar o formulário oculto.

Se DoStuff que realmente conseguem obter todas as coisas feito antes de ser abortado, você pode levantar um evento diferente para dizer ao cliente que o trabalho for concluído.

Editar que Acontece o artigo MSDN é falho ea técnica de não funciona : (

Aqui está um artigo sobre o uso do .NET BackgroundWorker componente para executar a tarefa em outro segmento de dentro VB6.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top