Access Cookbook - Ken Getz [231]
The sample form in 11-05.MDB, frmTestWait, allows you to try starting both a DOS application and a Windows application, and wait for either to complete. There's also a button that allows you to start a DOS application but continue the attached code. In each of these cases, the sample code attempts to load the text file C:\ACBTEST.TXT (choosing either of the first two buttons sends the output of CHKDSK to C:\ACBTEST.TXT for you) into a text box on the form once the application you've started finishes its work, as shown in Figure 11-6. (In the case where the code doesn't wait for the other application, of course, there's nothing to load.) Use frmTestWait, try each command button to test the functionality demonstrated in this solution. The first button runs CHKDSK, waits until it has written its output to C:\ACBTEST.TXT, and then loads the text file. The second button runs CHKDSK and immediately loads the text file. The final button, Run Notepad, loads a Windows application, Notepad, and waits until you've closed it before loading the text file.
Figure 11-6. frmTestWait after it has run an application
To use this functionality in your own applications, follow these steps:
Import the module basRunApp from 11-05.MDB into your application.
To run another application and wait for it to finish before going on with your code, call the acbRunAppWait subroutine, passing it two parameters: a command string telling it what to run, and an integer designating the window mode you'd like to use (see Table 11-3). These are essentially the same values you use when calling the ShellExecute Windows API function, as shown in the Solution in Recipe 11.7.
Table 11-3. Window display options using Shell
Value
VBA constant
Description
0
vbHide
Hidden
1
vbNormalFocus
Restored to its previous state (neither minimized nor maximized)
2
vbMinimizedFocus
Made visible and minimized
3
vbMaximizedFocus
Made visible and maximized
4
vbNormalNoFocus
Displayed, but doesn't gain the input focus
6
vbMinimizedNoFocus
Minimized (as an icon) when started
For example, to start the Windows calculator maximized, use a statement like this:
acbRunAppWait "CALC.EXE", vbMaximizedFocus
MsgBox "Done with the calculator."
You won't see the message box until you finish with the calculator.
Discussion
The secret to the acbRunAppWait subroutine is its use of the Windows API function GetExitCodeProcess. This function takes as a parameter the process handle of an application, which you can retrieve by calling the OpenProcess API function with the instance handle returned by the call to Shell. GetExitCodeProcess monitors a running process and retrieves that process's exit code. As long as the process continues to run, GetExitCodeProcess returns the value STILL_ACTIVE (defined in basRunApp).
Consider the following code, which checks for the existence of a running application:
Do
' Attempt to retrieve the exit code, which will
' not exist until the application has quit.
lngRetval = GetExitCodeProcess(hProcess, lngExitCode)
Loop Until lngExitCode <> STILL_ACTIVE
Though this will almost do what you need, it won't quite succeed. You've left Access running a tight loop, waiting for the new application to finish. Unfortunately, this loop grabs all of Access's clock cycles, looping and waiting for the other application to be done. While this loop is active, Access is effectively dead. All the rest of Windows continues to work perfectly, but Access's only thread of execution is completely tied up. You'll see that Access simply can't update its screen,