To launch another application from a WSH script, you must use the Run method provided by the WshShell object. The Run method creates a new process and executes the command contained in the strCommand parameter. You can use a second parameter, intWindowStyle, to specify the window style. The method has the following syntax:
WshShell.Run(strCommand[, [intWindowStyle][, bWaitOnReturn]]) |
The parameter strCommand is required because it contains the path and the name of the application or the command to be executed.
NOTE
At this point, I should mention two things. First, remember that a path containing blanks must be enclosed in double quotes, such as "C:\Test Folder\MyApp.exe". Otherwise, the Run method raises a run-time error, "The system cannot find the file specified." I described this behavior in Chapter 1, and a little later in this chapter, you'll also see a VBScript sample that demonstrates how to enclose a path with double quotes. Second, keep in mind that the Run method automatically expands environment variable names contained in the parameter strCommand.
The following sequence causes the script to expand the environment variable %WINDIR% contained in Command and launches the Windows program Calc.exe:
Set WshShell = WScript.CreateObject("WScript.Shell") Command = "%WINDIR%\Calc.exe" WshShell.Run Command |
NOTE
Here I need to caution you about using the %WINDIR% environment variable: %WINDIR% returns the right path to the Windows folder, but not all applications are located in this folder. The preceding command works just fine for Windows 95 and Windows 98, but it fails in Windows NT and Windows 2000 because Calc.exe is located in the subfolder \System32. Therefore, it's better to omit the %WINDIR% environment variable in all commands launching Windows system applications (such as Calc) that locate the executable in either the Windows folder or the Windows system folder, depending on the Windows platform. In this case, Windows searches the Windows folder and the default system folder (which is \System for Windows 95 and Windows 98 and \System32 for Windows NT and Windows 2000).
The other two optional parameters control how the application window is displayed and whether the script should wait until the executed process terminates. The parameter intWindowStyle is an optional parameter that specifies the window style of the new process. The parameter can contain an integer between 0 and 10. If the parameter intWindowStyle is omitted, the window gets the focus and is shown in normal mode. Table 7-5 shows the values of intWindowStyle.
Table 7-5 Values of the intWindowStyle Parameter
Value | Visual Basic Constant | Description |
---|---|---|
0 | vbHide | Hides the window. Another window is activated (is shown and gets the focus). |
1 | vbNormalFocus | Activates the window and shows it. If the process is already active and the window is minimized or maximized, the previous size and position are restored. |
2 | vbMinimizedFocus | Activates the window and minimizes it. The button on the taskbar receives the focus. |
3 | vbMaximizedFocus | Activates the window, maximizes it, and gives it the focus. |
4 | vbNormalNoFocus | Displays a window in its most recent size and position. The active window remains active. |
5 | Activates the window in its current size and position. | |
6 | vbMinimizedNoFocus | Minimizes the window and activates the next top-level window in the z-order. |
7 | Displays the window as an icon (minimized). The active window remains active. | |
8 | Displays the window in its current state. The active window remains active. | |
9 | Activates and displays the window. If a window is minimized or maximized, Windows restores the original size and position. An application should specify this flag when restoring a minimized window. (This parameter can't be used with the Run method.) | |
10 | Sets the show state based on the state of the program that started the application. |
The values in Table 7-5 imply that you can use the Run method either to call up an instance of an application or to switch an already running application in the foreground. Unfortunately, the Run method always creates a new instance of the process. You can't reactivate a window of a running application or minimize or maximize it. Therefore, you can't use all the values shown in the table. I also found that the window styles work only with applications that support those styles. Notepad accepts the styles, but Calculator causes trouble because the window can't be maximized. Keep in mind that Table 7-5 shows the named constants defined by Visual Basic for the window styles. In WSH scripts, you must use the numeric constants because the named constants aren't defined in VBScript or JScript.
The optional Run parameter bWaitOnReturn is of subtype Boolean. (It can contain the values True and False.) The parameter controls whether the script waits for the termination of the executed process. If bWaitOnReturn is missing or is set to False, the Run method executes the command and returns immediately. If bWaitOnReturn is set to True, the Run method creates a new process, executes the command, and waits until the process terminates. In this case, the Run method returns the error code obtained from the terminated process. If bWaitOnReturn is missing or is set to False, Run returns the error code 0.
NOTE
You can set the error code in a script by using the Quit method (as explained shortly).
Let's create a few small scripts. Notepad supports the window styles listed in Table 7-5. The script in Listing 7-15 launches Notepad from VBScript. In a second step, the script launches Notepad again and minimizes Notepad's window (to a button on the taskbar). As part of the command, Notepad should load the source code of the currently executing script.
Listing 7-15 Run.vbs
'************************************************ ' File: Run.vbs (WSH sample in VBScript) ' Author: (c) G. Born ' ' Launching Notepad using the Run method '************************************************ Option Explicit Dim WshShell Set WshShell = WScript.CreateObject("WScript.Shell") WshShell.Run "Notepad.exe", 1 WScript.Echo "Load source code in a minimized window" WshShell.Run "Notepad.exe " & WScript.ScriptFullName, 6 '*** End |
The JScript sample in Listing 7-16 launches the Calculator program. The script needs some named constants, which I've declared as variables in the program's header. But Calculator doesn't support all window styles, so the style to minimize the window is ignored. Note also that the location of Calc.exe depends on the operating system, so using the environment variable %WINDIR% isn't a good idea. If you port a VBScript sample to JScript, you must be careful about the different syntax—you must put the parameters for the Run method in parentheses, and you must use \\ within paths to separate folder names because JScript interprets \ as an escape sequence.
Listing 7-16 Run.js
//************************************************ // File: Run.js (WSH sample in JScript) // Author: (c) G. Born // // Launching Calculator using Run. // Attention: The Run method doesn't support // all window styles! //************************************************ var SW_SHOWNORMAL = 1; var SW_MINIMIZE = 6; // Define command to invoke Calc.exe. // Attention: Don't use %WINDIR%\\Calc.exe because Windows NT // and Windows 2000 store Calc.exe in %WINDIR%\\System32, // and Windows 95 and Windows 98 keep the program in the // Windows folder. var command = "Calc.exe" var WshShell = WScript.CreateObject("WScript.Shell"); // First try WshShell.Run(command, SW_SHOWNORMAL); WScript.Echo("Launching Calculator minimized"); // Shouldn't work. Calculator is still maximized! WshShell.Run(command, SW_MINIMIZE); //*** End |
Earlier in this chapter, I mentioned that the Run method fails to call an application located in a folder that has blanks in its path. If a path contains blanks, you need to enclose it in double quotes. Let's do a small experiment. Copy an existing script program (for example, Run.vbs from Listing 7-15) into a folder named C:\Test Folder, and rename the file to Test.vbs. Then try to execute the VBScript program in Listing 7-17. The program uses the Run method to launch a file with the name Test.vbs.
Listing 7-17 RunTest.vbs
'**************************************************** ' File: RunTest.vbs (WSH sample in VBScript) ' Author: (c) G. Born ' ' Using the Run method with a path containing blanks '**************************************************** Option Explicit ' Define a path containing a blank. Const command = "C:\Test Folder\Test.vbs" Dim WshShell ' Create WshShell object. Set WshShell = WScript.CreateObject("WScript.Shell") ' Enable run-time error handling in Script. On Error Resume Next ' First try the test without double quotes. WshShell.Run command, 1, True ' A run-time error occurs. If Err <> 0 Then _ If Err = -2147024894 Then _ WScript.Echo "Calling '" & command, vbCrLf & _ "Error: The system cannot find the file specified" On Error Goto 0 ' No more run-time error handling ' For the second test, enclose pathname in double quotes. WshShell.Run """" & command & """", 1, True WScript.Echo "Ready" '*** End |
The parent script tries to execute Test.vbs twice. The first call fails, prompting a dialog box showing a message that the file couldn't be located (because the path isn't enclosed in double quotes). The second attempt to call the child script succeeds. The line demonstrates how to enclose a variable value in VBScript in double quotes. You need something like """" & name & """" to set the double quotes. The outer double quotes "…" in the expression """" define a valid string. The two inner double quote characters "" force VBScript to insert one " into the string.
The Quit method terminates the WScript object (and thus terminates the script). In a JScript script, you can call this method by using the following statement:
WScript.Quit(); |
In VBScript, this is the equivalent statement:
WScript.Quit |
The object name is followed by a dot and then the name of the method. Both statements use the WScript object, which causes the script to terminate.
Quit accepts an optional parameter, which in JScript must be set in parentheses following the method's name. The JScript sample shown doesn't pass parameters to the Quit method; the parentheses in the statement are empty.
The parameter used in the Quit method defines the process exit code. If no value is passed, WSH returns the value 0 to the operating system. Alternatively, you can insert an integer value (such as 0 or 1) as a parameter to indicate to the operating system whether the process terminates with an error. The value 0 indicates that the process terminates regularly. All positive values indicate an error that causes the process to terminate. Windows doesn't check this code, but you can check the termination code yourself—for example, by using the host CScript.exe to execute the script in the Command Prompt window. You can check the error code by using the ERRORLEVEL function in a batch program. Or you can use the Run method as described in the next section to get the exit code.
NOTE
You don't have to insert the Quit statement before the script's end. When the language engine reaches the last line of a script, the process terminates automatically. You can use the Quit method to terminate a script at a specified point, however.
The sample code in Listing 7-18 launches an external application and waits until the process terminates. If the process returns an error code as it terminates, the parent script examines the process exit code (which is shown in a dialog box).
Listing 7-18 Test.vbs
'************************************************ ' File: Test.vbs (WSH sample in VBScript) ' Author: (c) G. Born ' ' Returning an error code '************************************************ Option Explicit WScript.Echo "Test script", vbCrLf, _ "We return error code 2" WScript.Quit 2 '*** End |
We still need the parent script to execute Test.vbs. Listing 7-19 does this. The script waits until the child process terminates, and then it reads the termination code and displays it in a dialog box.
Before we look at Run1.vbs, I'd like to make a few remarks about the GetPath function. The parent script must know the path in order to execute the child script Test.vbs. We'll assume that Test.vbs is stored in the same folder as Run1.vbs, so we can use the WScript.ScriptFullName property to determine its path. The function GetPath reads the ScriptFullName property, removes the filename from the path, and returns the path. The filename of the second script, Test.vbs, is appended to the path, and the resulting command string is used to execute the script.
The Run1.vbs sample also demonstrates how you can call up a script from a second script and how to exchange simple information such as an error code (a value between 0 and 255) between a child and a parent script.
NOTE
You can pass information from the parent script to the child script by using script arguments. You insert the arguments into the command to be executed. The child script must read the script arguments to obtain the information.
Setting the third parameter in the Run method to True creates a new process and executes the command given in the first parameter in the address space of the new process. The script then waits until the new process terminates. The Run method returns the process exit code of the new process:
ErrCode = WshShell.Run(name, 1, True) |
You can then use the content of ErrCode to check the error code.
Listing 7-19 Run1.vbs
'********************************************************* ' File: Run1.vbs (WSH sample in VBScript) ' Author: (c) G. Born ' ' Launching a script as a second process, waiting for the ' return code, and showing the value in a dialog box '********************************************************* Option Explicit Dim WshShell, name, ErrCode ' We need this object for the Run method. Set WshShell = WScript.CreateObject("WScript.Shell") ' Now we get the path to the executable program. ' The second script must be in the same folder ' as Run1.vbs. name = """" & GetPath & "Test.vbs" & """" ErrCode = WshShell.Run(name, 1, True) ' Just wait! WScript.Echo "Error code received: ", ErrCode ' Show error code. Function GetPath ' This function determines the path of the current script. ' Read the path and remove the script filename, and then return ' the result of the requested path. Dim path path = WScript.ScriptFullName ' Script name GetPath = Left(path, InStrRev(path, "\")) End Function '*** End |
You can set bWaitOnReturn to True to pause your script until the launched process terminates. This feature fails, however, if you try to use it with the program Explorer.exe. Listing 7-20 demonstrates this behavior.
Listing 7-20 Run2.vbs
'************************************************ ' File: Run2.vbs (WSH sample in VBScript) ' Author: (c) G. Born ' ' Launching Calculator using the Run method, ' waiting until the Calculator is closed, and then ' trying to do the same with Windows Explorer '************************************************ Option Explicit Const command1 = "Calc.exe" Const command2 = "Explorer.exe" Dim WshShell Set WshShell = WScript.CreateObject("WScript.Shell") WScript.Echo "Launch Calculator and pause script", vbCrLf & _ "until Calculator terminates" WshShell.Run command1, 1, True ' Wait until app is closed. WScript.Echo command1, "closed", vbCrLf, vbCrLf & _ "Launch Explorer and try to pause the script", _ vbCrLf & "until the Explorer window terminates" WshShell.Run command2, 1, True ' Won't work WScript.Echo "The Explorer window is still open, " & _ "so bWaitOnReturn doesn't work" '*** End |
The script in Listing 7-20 shows an introductory dialog box that must be closed. It then launches Calculator and pauses until the user closes the Calculator window. Obviously, the bWaitOnReturn parameter works. The script then tries to do the same with Windows Explorer. The following command launches Explorer, but the script doesn't pause:
WshShell.Run command2, 1, True |
Instead, the next dialog box appears. At first glance, this behavior looks like a bug, but in fact it is by design. Explorer.exe is part of the Windows shell, and the shell is already running (as the desktop folder, for example). Therefore, only a new instance of the shell is used to show the Explorer window. And in this case, no new process is executed using Run, so bWaitOnReturn fails.
You can execute an MS-DOS command from a script by using the Run method, just as you execute Windows applications. For example, in Windows 95 and Windows 98, you can use the following JScript command:
WshShell.Run("Edit.com"); |
This statement opens the window of the MS-DOS Editor. If you append the name of a document file to the command, the document is loaded in the editor window.
Because the path is missing, Windows searches the directories in the PATH environment variable for the program file.
TIP
To set the properties of an MS-DOS program in Windows 95 and Windows 98, you create a .pif file. Right-click on the program file, choose Properties from the shortcut menu, select the Program property page, and set the properties on this page. After you close the page by clicking the OK button, Windows creates a .pif file containing the program's MS-DOS properties. The file has the same name as the program and the (hidden) filename extension .pif, and it's stored in the program's folder. When the application starts, Windows loads the .pif file and sets the new properties for the MS-DOS session in the Command Prompt window.
Let's get back to executing an MS-DOS command from a script. Can you use the Run method, as shown here?
WshShell.Run "Dir C:\" |
This statement won't work because there's no program file named Dir.com or Dir.exe. The Run method requests an executable file (a file with an .exe, .com, .bat, or .pif extension). In Windows 95 and Windows 98, internal MS-DOS commands such as Dir, Copy, and Rename are stored in the MS-DOS command processor Command.com (unlike external commands such as Edit.com). Command.com is in the Windows folder. Windows NT uses cmd.exe as the command processor for MS-DOS commands. To execute an internal MS-DOS command, you execute the command processor and pass the internal MS-DOS command to the command processor. (The command is executed in the Command Prompt window.)
In Windows 95 and Windows 98, you can write a command to display the folder as follows:
C:\Windows\Command.com /k dir *.* |
This statement assumes that Windows is installed in the C:\Windows folder. The switch /k is important because it tells the command processor not to close the MS-DOS window. If you want to close the MS-DOS window automatically after termination, you must use the switch /c instead.
TIP
If you type the command Command.com /? on the command line, you get a list of all options supported in Command.com.
The command shown above causes two problems, however. First, you should make the statement independent of the Windows installation folder, which you could do by using the environment variable %WINDIR% instead of C:\Windows. But there's a second issue as well. Windows 95 and Windows 98 use Command.com as the command processor, and Windows NT and Windows 2000 use Cmd.exe. These command processors are also in different locations. To ensure that the script runs on all platforms, you can insert the environment variable %COMSPEC% into the command, as shown below. This environment variable contains the command processor and its location. It therefore ensures that the command string always contains the correct command processor.
command = "%COMSPEC% /k "; |
The variable dos_command is used to store the MS-DOS command, and you can use the variable option to append options to the MS-DOS command. In the sample code in Listing 7-21, I inserted the | character and the more command into option to use the MS-DOS filter. This combination causes the MS-DOS command processor to redirect the Dir output to the more filter. This filter shows the results page by page.
TIP
You can use the > character in a similar way as | to redirect the output of the Dir command to a printer (to print the content of a directory, for example) or into a file.
Listing 7-21 RunDOS.js
//************************************************** // File: RunDOS.js (WSH sample in JScript) // Author: (c) G. Born // // Executing an MS-DOS command using the Run method //************************************************** var command, dos_command, option // Get WshShell object. var WshShell = WScript.CreateObject("WScript.Shell"); // Create a command to show the contents of // the Windows folder. // Subcommand to call the command processor // Tip: Using the environment variable %COMSPEC% ensures that // the script runs in Windows 95 and Windows 98 and in Windows NT // and Windows 2000 because %COMSPEC% contains the name and path // of the command processor. command = "%COMSPEC% /k "; // Here comes the MS-DOS command. dos_command = "dir " + "%WINDIR%"; // You can append other options: // | more forces a page-oriented display // > PRN: redirection to printer // > Dir.txt redirection into file // option = "| more"; // Use page-oriented display. // Execute command. WshShell.Run(command + dos_command + option); //*** End |