USUÁRIO:      SENHA:        SALVAR LOGIN ?    Adicione o VBWEB na sua lista de favoritos   Fale conosco 

 

  Dicas

  Visual Basic    (Windows)

Título da Dica:  Como executar outro processo sincronamente "com elegância"
Postada em 9/9/2003 por Ð@®l@n            
Muitos de vocês já devem conhecer o exemplo clássico de como rodar um outro programa (processo) de dentro de seu programa de forma síncrona, isto é, de modo que o seu programa só continue a execução quando o programa que você inicializou termine (artigo Q129796 da Microsoft).

Porém, vocés também devem ter notado um pequeno problema "estético" quando usamos essa abordagem: o programa "pai" (o que inicializou o outro programa) realmente pára. Pára de tal forma que nem as mensagens de pintura são processadas... O que acontece, então? Se o usuário mexer a janela do programa "filho", as janelas do programa "pai" vão, pouco a pouco, ficando horrivelmente mal pintadas.


Bem, aqui está uma solução para esse problema. Essa parte do código pode ir em um módulo .bas:


Option Explicit

Private Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA" ( _
   ByVal lpApplicationName As String, ByVal lpCommandLine As String, _
   ByVal lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, _
   ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _
   ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As String, _
   lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long

Private Declare Function GetExitCodeProcess Lib "kernel32" ( _
   ByVal hProcess As Long, lpExitCode As Long) As Long

Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

Private Declare Function MsgWaitForMultipleObjects Lib "user32" (ByVal nCount As Long, _
   pHandles As Long, ByVal fWaitAll As Long, ByVal dwMilliseconds As Long, _
   ByVal dwWakeMask As Long) As Long

Private Declare Function PeekMessage Lib "user32" Alias "PeekMessageA" (lpMsg As MSG, _
   ByVal hwnd As Long, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long, _
   ByVal wRemoveMsg As Long) As Long

Private Declare Function DispatchMessage Lib "user32" Alias "DispatchMessageA" ( _
   lpMsg As MSG) As Long

Private Const NORMAL_PRIORITY_CLASS As Long = &H20&
Private Const INFINITE As Long = &HFFFF&
Private Const WAIT_OBJECT_0 As Long = &H0&
Private Const QS_PAINT As Long = &H20&
Private Const WM_PAINT As Long = &HF&
Private Const PM_REMOVE As Long = &H1&
Private Const STILL_ACTIVE As Long = &H103&

Private Type STARTUPINFO
   cb As Long
   lpReserved As String
   lpDesktop As String
   lpTitle As String
   dwX As Long
   dwY As Long
   dwXSize As Long
   dwYSize As Long
   dwXCountChars As Long
   dwYCountChars As Long
   dwFillAttribute As Long
   dwFlags As Long
   wShowWindow As Integer
   cbReserved2 As Integer
   lpReserved2 As Byte
   hStdInput As Long
   hStdOutput As Long
   hStdError As Long
End Type

Private Type PROCESS_INFORMATION
   hProcess As Long
   hThread As Long
   dwProcessId As Long
   dwThreadId As Long
End Type

Private Type POINTAPI
   x As Long
   y As Long
End Type

Private Type MSG
   hwnd As Long
   message As Long
   wParam As Long
   lParam As Long
   time As Long
   pt As POINTAPI
End Type


Public Sub RodarProcessoSincrono( _
      ByVal vstrExecutavel As String, _
      Optional ByVal vstrParametros As String, _
      Optional ByVal vstrDirCorrente As String)

   Dim lngRetorno As Long
   Dim udtSUI As STARTUPINFO
   Dim udtPI As PROCESS_INFORMATION

   udtSUI.cb = Len(udtSUI)
   lngRetorno = CreateProcess(vstrExecutavel, vstrParametros, _
      0&, 0&, 0&, NORMAL_PRIORITY_CLASS, 0&, _
      vstrDirCorrente, udtSUI, udtPI)

   ' Verifica se ocorreu algum erro.
   If lngRetorno = 0 Then
      If Err.LastDllError = 2 Then
         ' The system cannot find the file specified.
         MsgBox "Não foi possível encontrar o arquivo '" & _
            vstrExecutavel & "'.", vbInformation
      End If
      Exit Sub
   End If

   ' O handle do thread principal do processo já
   ' pode ser fechado, já que não vamos usá-lo.
   lngRetorno = CloseHandle(udtPI.hThread)

   Dim lngExitCode As Long
   Dim udtMsg As MSG

   Do
      ' A função 'MsgWaitForMultipleObjects' pára a execução da
      ' aplicação até que o objeto indicado (no caso, um outro
      ' processo) sinalize (no caso do processo, até que ele seja
      ' finalizado), ou, que a aplicação receba alguma mensagem
      ' de pintura de janelas ('WM_PAINT'). Se o processo finalizar,
      ' a função retornará 'WAIT_OBJECT_0 + 1'.
      Do Until MsgWaitForMultipleObjects(1&, udtPI.hProcess, _
         0&, INFINITE, QS_PAINT) <> WAIT_OBJECT_0 + 1
         ' A aplicação recebeu uma mensagem de pintura, então, aqui é
         ' feita uma simulação do loop de mensagens da aplicação,
         ' tratando apenas da mensagem 'WM_PAINT', para evitar que a
         ' tela fique toda "zuada".
         Do While PeekMessage(udtMsg, 0&, WM_PAINT, WM_PAINT, PM_REMOVE)
            Call DispatchMessage(udtMsg)
         Loop
      Loop
      ' Pra se certificar de que o processo realmente
      ' já foi finalizado.
      Call GetExitCodeProcess(udtPI.hProcess, lngExitCode)
   Loop While lngExitCode = STILL_ACTIVE

   lngRetorno = CloseHandle(udtPI.hProcess)
End Sub

Você pode, então, utilizar a rotina dessa forma:

Private Sub Form_Click()
   Call RodarProcessoSincrono("C:\Windows\Notepad.exe", _
      " Tips.txt", "C:\Windows")
End Sub

Autor: Lobo
 


CyberWEB Network Ltda.    © Copyright 2000-2024   -   Todos os direitos reservados.
Powered by HostingZone - A melhor hospedagem para seu site
Topo da página