Home
Search
 
What's New
Index
Books
Links
Q & A
Newsletter
Banners
 
Feedback
Tip Jar
 
C# Helper...
 
XML RSS Feed
Follow VBHelper on Twitter
 
 
 
MSDN Visual Basic Community
 
 
 
 
 
TitleStart another process and disable a button while that process is running in VBA
DescriptionThis example shows how to start another process and disable a button while that process is running in VBA.
KeywordsVBA, shell, shell and disable, SetTimer, GetExitCodeProcess
CategoriesAPI, Office
 
When the user clicks the Word document's "Shell and Disable" button, VBA executes the following code. The program uses Shell to launch another program. It then disables the button and saves a reference to it in a global variable. This routine finishes by using the SetTimer API function to create a timer that executes every 1000 milliseconds (every 1 second).

After the subroutine exits, the calling application (in this case Word) can continue working so, for example, the user can type more text while the other process is running. The button remains disabled so the user cannot click it again.

 
' Shell a program, set a timer to see when the program is
' done,
' and disable the button.
Private Sub cmdShellAndDisable_Click()
Const PROG_NAME As String = "C:\Documents and " & _
    "Settings\04838402\Desktop\SayHi\bin\SayHi.exe"
Dim process_id As Long

    ' Shell the command.
    On Error GoTo ShellError
    process_id = Shell(PROG_NAME, vbNormalFocus)
    g_ProcessHandle = _
        OpenProcess(PROCESS_QUERY_INFORMATION, 0, _
        process_id)

    On Error GoTo 0

    ' Disable the button.
    cmdShellAndDisable.Enabled = False
    Set g_ReEnableCmd = cmdShellAndDisable

    ' Start a 1 second timer.
    g_TimerID = SetTimer(0, 0, 1000, AddressOf MyTimer)
    Exit Sub

ShellError:
    MsgBox "Error starting task" & vbCrLf & _
        Err.Description, vbOKOnly Or vbExclamation, _
        "Error"
End Sub
 
The following code shows the timer function. It calls GetExitCodeProcess to see what the other process's exit status is. GetExitCodeProcess returns STATUS_PENDING as long as the other process is still running. When GetExitCodeProcess returns something else, the code kills the timer so it doesn't run again and re-enables the button.
 
' The timer event handler.
Public Sub MyTimer(hwnd As Long, msg As Long, idTimer As _
    Long, dwTime As Long)
Dim exit_code As Long

    ' See if the shelled process is still there.
    GetExitCodeProcess g_ProcessHandle, exit_code
    If exit_code <> STATUS_PENDING Then
        ' The process is gone.
        On Error GoTo 0
    
        ' Kill the timer.
        KillTimer 0, g_TimerID

        ' Re-enable the button.
        g_ReEnableCmd.Enabled = True
        Set g_ReEnableCmd = Nothing
    End If
End Sub
 
(I have not tested this code when the user deletes the button before the other process finishes. Presumably the timer will crash when it tries to re-enable the button. You should be able to stop that with an On Error statement.)

NOTE: You will need to edit the code to tell the program where to find the executable that you want to run. This example includes a simple SayHi.exe program written in Visual Basic 2003 (you can easily write your own program in other versions of Visual Basic). It just displays a messagebox so you can easily control when it ends. After you observe that the Word application is waiting, click the OK button.

IMPORTANT NOTE: Working with API functions can be tricky in VBA. If something goes wrong while the API call is in progress, the entire host application (in this example Word) often crashes. To avoid losing a lot of work, SAVE YOUR WORK OFTEN!

 
 
Copyright © 1997-2006 Rocky Mountain Computer Consulting, Inc.   All rights reserved.
  Updated