To suspend or delay execution of statements in a script, you can use the Sleep method, which we already used in previous chapters.
Sometimes you must synchronize a script with another process. For example, in Chapter 11 you saw a situation in which a Windows 98 domain logon script tries to read the UserName property. When this property returns a blank value, the script must wait until the property is nonblank. The following code solves this problem:
Set WshNetwork = WScript.CreateObject("WScript.Network") User = WshNetwork.UserName ' Initialize value. Do While User = "" ' Loop until user name is returned. WScript.Sleep 200 ' Suspend to lower CPU load. User = WshNetwork.UserName ' Read property. Loop |
The script uses a loop to poll the WshNetwork.UserName property until the returned value is nonblank. You saw a similar technique in Chapter 9, in which a script needed to wait until the user confirmed a Microsoft Internet Explorer form's input by clicking the OK button. We used the following code sequence to poll the state of the form:
Do ' Wait until the OK button is clicked. WScript.Sleep 200 ' Suspend the script for 200 milliseconds. Loop While (oIE.Document.Script.CheckVal() = 0) |
The third VBScript statement calls the CheckVal method to determine the Internet Explorer form's internal state. If the user clicks the form's OK button, CheckVal returns 1 and the loop terminates. Polling has one big disadvantage: it can spike the CPU load to 100 percent. Therefore, I added this statement to the loop:
WScript.Sleep 200 ' Suspend the script for 200 milliseconds. |
The statement calls the Sleep method of the WScript object. The parameter submitted to the method specifies how long the script's execution will be suspended, in milliseconds. Each time the loop is executed, Sleep suspends script execution for 200 milliseconds. During this period, the script incurs no CPU usage.
The consequences of using the Sleep method within polling are shown in Figure 13-1. On the Performance tab of the Windows 2000 Task Manager, the CPU Usage History diagram shows the CPU load incurred by two script programs (obtained from the Form sample). Execution of the Do While loop without the WScript.Sleep statement spikes the CPU load to 100 percent until the user clicks the OK button (Figure 13-1, left). The figure also shows the CPU load incurred by the script if it uses the WScript.Sleep statement (Figure 13-1, right). The improved script doesn't incur a heavy CPU load. The small spike visible at the beginning of this time period is caused by mouse clicks that launch the script and load the form in Internet Explorer and by the loop in the script that polls oIE.Busy until the browser finishes loading the form.
Figure 13-1 Processor usage during polling
NOTE
You can monitor the CPU usage history in Microsoft Windows NT and Windows 2000 using Task Manager. In Windows 95 and Windows 98, you can use System Monitor (which is also available in Windows NT and Windows 2000).
Now let's look at how the Sleep method can help solve another problem with asynchronous processes. I came across this problem while using the SendKeys method (introduced later in this chapter). Let's say that a script launches two external applications, Calculator and Notepad, and shows a dialog box that allows user interaction:
oShell.Run "Calc.exe",1 ' Launch Calculator. oShell.Run "Notepad.exe", 1 ' Launch Notepad. WScript.Echo "Have applications been launched?" |
Which window do you think will be shown first, and which one will remain in the foreground? At first glance, you might say that Calculator will be shown first and then the Notepad window will overlap the Calculator window and the Echo dialog box will remain in the foreground. However, on my systems, the Calculator window and the Echo dialog box are hidden by the Notepad window. The user can recognize the Echo dialog box only by its button on the taskbar.
This behavior is the result of how Windows processes these applications. The script shells out two Run calls and continues to execute the next instruction. As a result, the Echo dialog box is shown before Windows can launch the external applications. Also, the order of the application windows depends on the amount of time that each application needs for launching.
NOTE
In MsgBox or Popup, you can use the constant vbSystemModal to force Windows to show the dialog box in the foreground. However, this constant doesn't work with the Echo method.
To specify which application window is shown in the foreground, you can simply open application windows in sequential order and write the script in such a way that it waits until the window is visible. In most cases, you can do this by using a simple delay after executing the Run method:
oShell.Run "Calc.exe", 1 ' Launch Calculator. WScript.Sleep 500 ' Wait 0.5 second. oShell.Run "NotePad.exe", 1 ' Launch Notepad. WScript.Sleep 500 ' Wait 0.5 second. WScript.Echo "Please close all application windows" |
Calling the Sleep method with a parameter of 500 causes the script to pause 0.5 seconds until the next instruction is processed. As a result, the application windows and the Echo dialog box are shown in the appropriate order. This behavior is shown in the short VBScript program in Listing 13-1. This program launches Calculator and Notepad and displays a dialog box. In a second step, both applications and an additional dialog box are launched, with a short delay between each statement.
Listing 13-1 RunApps.vbs
'************************************************ ' File: RunApps.vbs (WSH sample in VBScript) ' Author: (c) G. Born ' ' Launching Calculator and Notepad by using the ' Run method '************************************************ Option Explicit Dim oShell ' Create the WshShell object. Set oShell = WScript.CreateObject("WScript.Shell") oShell.Run "Calc.exe", 1 ' Launch Calculator. oShell.Run "NotePad.exe", 1 ' Launch Notepad. ' Now delay script after launching an application. WScript.Echo "Second Attempt: Launch Notepad and Calculator" oShell.Run "Calc.exe", 1 ' Launch Calculator. WScript.Sleep 500 ' Wait 0.5 second. oShell.Run "NotePad.exe", 1 ' Launch Notepad. WScript.Sleep 500 ' Wait 0.5 second. WScript.Echo "Please close all application windows" '*** End |