[Previous] [Table of Contents] [Next]

# Long Filenames, the At Command, and System Calls

In this section, we'll cover how to work with long filenames, how to use the AT command, and how to invoke system calls by using the Run method.

## Using the Windows NT Scheduler to Execute WSH Scripts

You can use the Microsoft Windows NT scheduler to execute a script at a specified time:

    AT 18:00:00 /interactive "C:\WSHDevGuide\Chapter14\RunExit.vbs"

On the AT command line, you must write the entire path to the script file. You must also set the /interactive flag if the script requests user interaction.

> NOTE

> In Windows 98 and Windows 2000, you can use the Task Scheduler to schedule script execution. (Even though the Task Scheduler provides an API for other programs, it doesn't support a scripting interface; Microsoft Site Server includes a helper DLL that provides the necessary COM interface.)

## Using Long Filenames in Scripts

If your scripts contain long filenames or if you use long filenames in the command to execute a script, you must enclose the paths in double quotes, as shown here:

    WshShell.Run _
        """C:\Programs\Microsoft Office\Office\Excel.exe""", 1, True

In VBScript, you must write a double quote in a string as """. The first double quote indicates the beginning of the string. The next two double quotes indicate that the double quote must be inserted into the string.

In JScript, you write a double quote in a string as \":

    WshShell.Run _
        ("\"C:\\Programs\\Microsoft Office\\Office\\Excel.exe\"",
        1, true);

> NOTE

> If you build the command line by fetching a pathname and then concatenating a string with the specific filename, you must add double quotes around the resulting string (because the fetched pathname might have an embedded space). An example is oWSH.Run """" & path & """", 3, True. The four double quotes are required because the two inner double quotes force the language engine to recognize one ". The outer double quotes mark the inner double quote as a string character.

## Using the Run Method to Execute System Calls

To call Windows API functions from your WSH script, you need an ActiveX control that provides the right interface. (I explain how to write such controls in Advanced Development with Microsoft Windows Script Host 2.0.) Nevertheless, Windows 95, Windows 98, Windows NT, and Windows 2000 provide a few backdoor options that allow you to access system routines from a script by using the Run method.

### Using RunDll32.exe to shut down Windows 95 or Windows 98

If you don't have an ActiveX control that provides a method to shut down Windows 95 or Windows 98, you can use the following command within the Run method:

    WshShell.Run "%WINDIR%\RunDll32.exe user,ExitWindows", 1, -1

The program RunDll32.exe activates several Windows API functions contained in library (DLL) files. The command shown here launches RunDll32.exe. This helper program accesses the library User.exe and calls the library's ExitWindows API function.

> TIP

> You can use any Windows DLL library in a RunDll32.exe command, but you must keep in mind some restrictions. The names of the functions exported from the library are case-sensitive. (For example, exitwindows is different from ExitWindows.) Also, you can't use RunDll32.exe to pass arguments to Windows API functions. But there are a few exceptions that allow you to use RunDll32.exe to call other functions and submit a string within the command line. These functions (such as SHExitWindowsEx, which is discussed later) examine the command line for arguments.

The VBScript program shown in Listing 14-1 contains the command to shut down Windows 95 or Windows 98 from a WSH script. (This sample, like the others in this chapter, is in the \WSHDevGuide\Chapter14 folder on the book's companion CD.)

Listing 14-1 RunExit.vbs

    '************************************************
    ' File:    RunExit.vbs (WSH sample in VBScript)
    ' Author:  (c) G. Born
    '
    ' Using the Run method to call the Windows 95 or
    ' Windows 98 ExitWindows API function
    '************************************************

    Option Explicit

    Dim WshShell

    Set WshShell = WScript.CreateObject("WScript.Shell")

    If (MsgBox("Shut down Windows 95 or Windows 98", vbYesNo + vbQuestion, _
        "WSH sample - by G. Born") = vbYes) Then _
        WshShell.Run _
            "%WINDIR%\RunDll32.exe user,ExitWindows", 1, -1

    '*** End

> NOTE

> This call won't work in Windows NT or Windows 2000 because the operating system doesn't support the ExitWindows function in User.exe. (A shutdown in Windows NT or Windows 2000 requires privileges for the caller.) The ActiveX control WSHExtend.ocx (discussed in Advanced Development with Microsoft Windows Script Host 2.0) provides a method for shutting down Windows 95, Windows 98, Windows NT, or Windows 2000.

### A trick for shutting down and restarting Windows 95 or Windows 98

The technique I just showed you for shutting down Windows 95 or Windows 98 can't be used to restart the system. However, these versions of Windows support MS-DOS mode (console window mode), which unloads the Windows kernel and loads only the MS-DOS core. Therefore, if you execute an MS-DOS program in MS-DOS mode, Windows terminates. After quitting the MS-DOS application, the Windows kernel is reloaded automatically. This has the same effect as a restart.

You can use this MS-DOS mode behavior to force a Windows restart in Windows 95 or Windows 98. First, you create a BAT file containing only the following command:

    @Exit

Then you right-click on the BAT file icon and choose Properties from the shortcut menu. On the Program property page, check the MS-DOS Mode option and uncheck the Warn Before Entering MS-DOS Mode option. Now, a subsequent double-click on the BAT file launches the batch program in MS-DOS mode. Because the BAT file contains the Exit command, this mode quits immediately and Windows reloads. To restart Windows from a WSH script, you simply write a script that uses the Run method to execute your BAT file.

This trick works well for Windows 95 and Windows 98 (but not for Windows Millennium Edition). If you want more control over the shutdown and restart process, you must access another Windows API function, named ExitWindowsEx. This function is available in Windows 95, Windows 98, and Windows NT. Unfortunately, you can't use the RunDll32.exe program to call this API function because the function requires two parameters: one that defines the exit mode and one that's reserved. Without an ActiveX control, you can't use this API function.

I also discovered another undocumented trick in Windows 98 (and in Windows Millennium Edition) for calling the ExitWindowsEx function from the shell with the requested parameter. This trick uses the function SHExitWindowsEx in the file Shell32.dll. This function acts as a wrapper for ExitWindowsEx and can be called from the Windows shell by using the following command:

    RunDll32.exe Shell32.dll,SHExitWindowsEx 0x0

RunDll32.exe calls the function SHExitWindowsEx in Shell32.dll. The function has one argument, which must be submitted as a string. (This is one of the exceptions I mentioned earlier: SHExitWindowsEx supports parameter passing from the command line.) The submitted argument specifies a hexadecimal number as a parameter for the exit mode. The string 0x0 specifies the value 0, 0x01 specifies the value 1, and so on. SHExitWindowsEx reads this argument, converts it to a hexadecimal number, and calls the original API function ExitWindowsEx with the requested parameters. Table 14-1 lists the values you can use for this argument.

Table 14-1 SHExitWindowsEx Argument Values

Argument | Result
--- | ---
0x0 | Log off
0x1 | Shut down
0x2 | Restart

Obviously, you can use RunDll32.exe to force Windows 98 to shut down or to restart, or to force a user to log off. Listing 14-2 is a WSH script that does all this.

Listing 14-2 RunExitEx.vbs

    '************************************************
    ' File:    RunExitEx.vbs (WSH sample in VBScript)
    ' Author:  (c) G. Born
    '
    ' Using the Run method to call the undocumented
    ' Windows 98 SHExitWindowsEx API function to
    ' shut down, restart, or log off
    '
    ' Shell32.dll,SHExitWindowsEx,0x0 Log off
    ' Shell32.dll,SHExitWindowsEx,0x1 Shut down
    ' Shell32.dll,SHExitWindowsEx,0x2 Restart
    '************************************************
    Option Explicit

    Dim Shell, Title, obj
    Title = "WSH sample - by G. Born"

    ' Create shell objects.
    Set Shell = WScript.CreateObject("Shell.Application")
    Set obj = WScript.CreateObject("WScript.Shell")

    ' Call Logoff mode.
    If (MsgBox("Log off?", _
        vbYesNo + vbQuestion, Title) = vbYes) Then
        obj.Run "RunDll32.exe Shell32.dll,SHExitWindowsEx 0x0"
    Else
        ' Call Shutdown mode.
        If (MsgBox("Shut down Windows?", _
            vbYesNo + vbQuestion, Title) = vbYes) Then
            obj.Run "RunDll32.exe Shell32.dll,SHExitWindowsEx 0x01"
        Else
            ' Call Restart mode.
            If (MsgBox("Restart Windows?", _
                vbYesNo + vbQuestion, Title) = vbYes) Then
                obj.Run "RunDll32.exe Shell32.dll,SHExitWindowsEx 0x02"
            End If
        End If
    End If

    '*** End

This call won't work in Windows 95, Windows NT, or Windows 2000 because these operating systems don't support the helper function. I'll come back to this topic a bit later when I explain how to access the Windows 98 shell to suspend your machine or invoke the Shutdown Windows dialog box.

## Locking a Windows 2000 Workstation

Although you can't use a RunDll32.exe call to exit Windows NT or Windows 2000, you can lock a Microsoft Windows 2000 Professional workstation. In Windows 2000, the module User32 provides the LockWorkStation API call. The code in Listing 14-3 uses RunDll32.exe to call this API function and lock the system.

Listing 14-3 NTLockWorkStation.vbs

    '********************************************************
    ' File:    NTLockWorkStation.vbs (WSH sample in VBScript)
    ' Author:  (c) G. Born
    '
    ' Locking a Windows 2000 workstation
    '********************************************************
    Option Explicit

    Dim WshShell

    ' Create WshShell object (for Run).
    Set WshShell = WScript.CreateObject("WScript.Shell")

    ' Ask user to allow lock.
    If MsgBox("Lock workstation?", vbYesNo, "WSH Sample") = vbYes Then
        ' Use LockWorkStation API call.
        WshShell.Run "RunDll32.exe user32.dll,LockWorkStation"
    End If

    '*** End

The user can double-click on the file to lock the workstation. After the user enters a password, the desktop with all open windows is restored. This sample isn't very useful by itself (because you can lock your workstation by pressing Ctrl+Alt+Del and then click the Lock Computer button). But the technique it demonstrates can come in handy during script execution.

## Invoking the Copy Disk Dialog Box

Windows uses DiskCopy.dll internally to handle a disk copy between two floppy disks. You can call this library to invoke the Copy Disk dialog box (shown in Figure 14-3).

Figure 14-3 The Copy Disk dialog box

This DLL exports a function that can be called from other programs. You can use RunDll32.exe to call the DiskCopyRunDll entry in DiskCopy.dll from a WSH script by using the following command:

    RunDll32.exe DiskCopy.dll,DiskCopyRunDll

This command invokes the Copy Disk dialog box. Listing 14-4 accesses the Copy Disk dialog box from a WSH script.

Listing 14-4 CopyDisk.vbs

    '************************************************
    ' File:   CopyDisk.vbs (WSH sample in VBScript)
    ' Author: (c) G. Born
    '
    ' Invoking the Copy Disk dialog box
    '************************************************
    Option Explicit

    Dim WshObj      ' Object for the Run method

    Set WshObj = WScript.CreateObject("WScript.Shell")

    WshObj.Run _
        "RunDll32.exe DiskCopy.dll,DiskCopyRunDll", _
        1, True ' Launch dialog box.

    '*** End

## Invoking the Format Dialog Box

You can use a similar technique to invoke the Format dialog box to format a floppy disk in Windows. The format function is implemented in the file Shell32.dll; you can invoke it by using the SHFormatDrive call, which displays the Format dialog box. The following command accesses this function from a WSH script:

    RunDll32.exe Shell32.dll,SHFormatDrive

The script in Listing 14-5 invokes the Format dialog box.

Listing 14-5 Format.vbs

    '**************************************************
    ' File:    Format.vbs (WSH sample in VBScript)
    ' Author:  (c) G. Born
    '
    ' Invoking the Format dialog box for a floppy disk
    '**************************************************
    Option Explicit

    Dim WshObj      ' Object for Run method

    Set WshObj = WScript.CreateObject("WScript.Shell")

    WshObj.Run "RunDll32.exe Shell32.dll,SHFormatDrive", _
               1, True ' Launch dialog box.

    '*** End

## Invoking the Screen Saver Property Page

The Screen Saver property page allows you to install a screen saver. You can invoke this property page from a script or from the Windows shell by using the following command:

    RunDll32.exe desk.cpl,InstallScreenSaver

Listing 14-6 invokes the property page by using VBScript.

Listing 14-6 ScreenSaver.vbs

    '************************************************
    ' File:   ScreenSaver.vbs (WSH sample in VBScript)
    ' Author: (c) G. Born
    '
    ' Installing a screen saver
    '************************************************
    Option Explicit

    Dim WshObj      ' Object for the Run method

    Set WshObj = WScript.CreateObject("WScript.Shell")

    WshObj.Run _
        "RunDll32.exe desk.cpl,InstallScreenSaver", _
        1, True ' Screen saver property page

    '*** End

## Calling Control Panel Modules

The previous sample introduces a method for invoking the Screen Saver property page using RunDll32.exe. You can also use Control.exe instead of RunDll32.exe within the Run method to invoke a Control Panel property page via .cpl files. The following command invokes the Buttons property page of the Mouse Properties property sheet:

    WshObj.Run "Control.exe main.cpl,@0,0"

The parameters following the name of the module (.cpl file) specify which property page of that module is shown in the foreground. Table 14-2 lists some of the modules and their parameters.

Table 14-2 Control Panel Modules and Their Parameters

Module | Name | Index | Description | Examples
--- | --- | --- | --- | ---
Appwiz.cpl | n/a* | 0 to 3 | Opens the property page addressed in index of the Add/Remove Programs dialog box (or property sheet, depending on the operating system version). | Control.exe Appwiz.cpl,,1
Desk.cpl | n/a | 0 to 3 | Opens a page of the Display property sheet. | Control.exe Desk.cpl,,1
Intl.cpl | n/a | 0 to 4 | Opens the Regional Options property sheet and selects a property page. The second parameter defines the property page. | Control.exe Intl.cpl,,1
Main.cpl | @0 to @5 | 0 to x | Supports the property sheets for mouse, keyboard, energy saving, and PCMCIA. The first parameter specifies the module. You can use a name (such as Mouse or Keyboard) or an index value in the format @x (where x is a placeholder for a value from 0 to 5). Names are localized. The second parameter specifies the module's property page. | Control.exe Main.cpl,@0,1 Control.exe Main.cpl,Mouse,1
Mmsys.cpl | @0, @1 | 0 to x | Opens the property sheet for sound or multimedia. The first parameter specifies the property sheet (0 = Multimedia; 1 = Sounds). The second parameter specifies the property page. | Control.exe Mmsys.cpl,@0,1
Sysdm.cpl | n/a | 0 to 3 | Opens the System property sheet and selects one of the pages. | Control.exe Sysdm.cpl,,0
Timedate.cpl | n/a | 0, 1 | Opens the Date/Time property sheet. | Control.exe Timedate.cpl,,0

* "n/a" means "not applicable."

The names of the property sheets vary a bit depending on the version of the operating system. The number of property pages also varies. Table 14-2 shows the options for Windows 98 (most of which can be used in Windows 95, Windows NT, and Windows 2000).

## Using the Run Method to Handle Network Mappings

You can use the WshNetwork object to handle network mappings for drives and printers, but sometimes changing network settings by using this object and its methods can get too complicated. An easier way is to use the Run method along with the MS-DOS Net command. To delete all network mappings on a machine, for example, you can use the following command in a script:

    Set objSh = WScript.CreateObject("WScript.Shell")
    objSh.Run "NET USE * /DELETE /YES", 0, True

The NET USE command accesses the network mappings. The wildcard character (*) defines all mappings, and the switch /DELETE removes these mappings. The option /YES forces the action without user input.

> NOTE

> For more information on the NET command, open the Command Prompt window and type NET /? or NET USE /? to see a help page.