Link to home
Start Free TrialLog in
Avatar of shawnlehner
shawnlehnerFlag for United States of America

asked on

Best way to wait for a launched program to exit

What is the best way to use SHELL to launch a program and pause going to the next action in your launcher program until the program you launched has finished and exited?
Avatar of wertyk
wertyk
Flag of United States of America image

use this:
Shell("programname.exe", 1, true)

the third argument (true) makes it wait until its over before continuing

heres more info on the Shell command:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vblr7/html/vafctshell.asp
Avatar of Rubyn
Rubyn

werk, You are talking about VB.NET.
Try the code below:

Const SYNCHRONIZE = &H100000
Const INFINITE = &HFFFF
 'Wait forever
Const WAIT_OBJECT_0 = 0
 'The state of the specified object is signaled
Const WAIT_TIMEOUT = &H102
 'The time-out interval elapsed & the object’s state
'is nonsignaled.

Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, _
            ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long

Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, _
            ByVal dwMilliseconds As Long) As Long

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


Private Function ShellWait(txtApp As String, Optional Wait As Long = INFINITE) As Boolean
Dim lPid As Long, lHnd As Long, lRet As Long

If Trim$(txtApp) = "" Then Exit Function

Let lPid = Shell(txtApp, vbNormalFocus)
If lPid <> 0 Then
        'Get a handle to the shelled process.
        Let lHnd = OpenProcess(SYNCHRONIZE, 0, lPid)
        'If successful, wait for the application to end and close the handle.
        If lHnd <> 0 Then
                lRet = WaitForSingleObject(lHnd, Wait)
                Call CloseHandle(lHnd)
                Let ShellWait = True
        End If
End If
End Function

Private Sub Command1_Click()
Call ShellWait("notepad.exe")
End Sub
Avatar of Mike Tomlinson
A variation of Rubyn's post which keeps the app from freezing up while it is waiting for the Shelled app to exit:

Option Explicit

Private Const SYNCHRONIZE = &H100000
Private Const WAIT_TIMEOUT = &H102

Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, _
            ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, _
            ByVal dwMilliseconds As Long) As Long
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

Private Sub Command1_Click()
    ShellAndWait "calc.exe"
    MsgBox "Done"
End Sub

Private Sub ShellAndWait(ByVal cmd As String)
    Dim lPid As Long
    Dim lHnd As Long

    lPid = Shell(cmd, vbNormalFocus)
    If lPid <> 0 Then
        lHnd = OpenProcess(SYNCHRONIZE, 0, lPid)
        If lHnd <> 0 Then
            Do
                DoEvents ' keep application responsive
                Sleep 50 ' keep CPU usage from ramping to 100%
            Loop Until WaitForSingleObject(lHnd, 0) <> WAIT_TIMEOUT
            CloseHandle (lHnd)
        End If
    End If
End Sub
A different way to do it.  Also gives you back the exit code:

Option Explicit

Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Private Function ShellAndWait(ByVal fileName As String) As Long
    If Dir(fileName) <> "" Then
        Dim WShell As Object
        Dim oProcess As Object
       
        Set WShell = CreateObject("WScript.Shell")
        Set oProcess = WShell.Exec(fileName)

        Do While oProcess.Status = 0
            Sleep 50 ' keep CPU usage from ramping to 100%
            DoEvents ' keep app responsive
        Loop

        ShellAndWait = oProcess.ExitCode

        Set WShell = Nothing
        Set oProcess = Nothing
    Else
        MsgBox fileName, vbCritical, "File Not Found"
        ShellAndWait = 1 ' a non-zero value usually means something went wrong
    End If
End Function
Beware since using DoEvents, Timer Controls will still trigger their methods.
ASKER CERTIFIED SOLUTION
Avatar of Robberbaron (robr)
Robberbaron (robr)
Flag of Australia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Something to keep in mind... I've found that add-on apps like "Window Blinds" can mess around with process ids.  That means if the method you are using relies on a process id to track if the shelled application is still running then you may get false results if something like "Window Blinds" is loaded.