One of the most important changes that Windows 95 introduced is the use of the folder to organize files, programs, and other items that the Windows OS needs. Previously, Windows used only directories to organize the OS.
A directory is simply an entry in the file-system internal tables—it can contain only files, and those files must be at the file-system level. A folder is a container that can house any type of item (including files, other folders, and custom-information items) from any level in the OS. Thus, folders are more versatile than directories. Folders are powered by a piece of code (a sort of data provider) that enumerates all the items that the folder contains. Architecturally speaking, directories are folders.
Within Windows Explorer, folders look like directories, even if the folders don't contain any files. For example, the Printers folder looks like a regular folder, yet it contains printer names rather than filenames. Each item in the folder represents a piece of hardware rather than a file.
To list and process a directory's contents, you can use MS-DOS commands or the File System Object (FSO) model's FileSystemObject object. However, you can't use these tools to access the contents of special file-system folders such as Printers and Recycle Bin. Instead, you need to use the Shell object model. You can use Shell objects to access not only special folders but also file-system directories. In addition, you can use Shell to programmatically drive the Windows shell and programmatically access all of Windows Explorer's features.
Shell objects are well suited for use in the Windows Script Host (WSH) environment. However, they aren't natively available on all versions of Windows. The sidebar "Getting Shell Objects onto Your System" discusses which versions don't have these objects and how you can obtain them. After you have these objects in place, you access all the main features of the OS's GUI. Let's look at how you can use the Shell object model's root object to browse through folders, open Control Panel applets, and access special folders.
The Shell.Application Object
The Shell object model's root object is Shell.Application. To create an instance of this object in VBScript code, you use VBScript's CreateObject function:
Set sa = CreateObject _ ("Shell.Application")
After you instantiate the object, you can use any of the methods that Table 1 shows. These methods make many system functions available to scripts. For example, to obtain the system dialog box that lets you search for files and folders, you use the FindFiles method:
The resulting dialog box is the same one that appears when you select Find, then Files or Folders in the Start menu. The title of this dialog box differs depending on the OS you're running. In Windows NT, the title is Find: All Files.
The Shell.Application object's Explore and Open methods open a Windows Explorer window for a specified folder. The difference between these methods is that Explore creates a two-pane window that has the display tree in the left pane and Open creates a one-pane window that doesn't have the display tree.
To programmatically open the Taskbar Properties dialog box (i.e., the dialog box that appears when you click Start, Settings, Taskbar), you use the TrayProperties method:
Other useful system dialog boxes that you can open with the Shell.Application object are Run and Date/Time Properties. You use the FileRun and SetTime methods, respectively, to obtain them:
The system creates each dialog box asynchronously with respect to the rest of the VBScript code. In other words, the lines of code after these methods (and any other methods that create dialog boxes) execute as soon as the order to create the dialog box has been passed to the Shell and without waiting for the dialog box to appear. Depending on runtime conditions, the code
sa.FileRun MsgBox "Hello, world"
can cause the message box to appear before the Run dialog box.
To programmatically shut down Windows, you can use the ShutdownWindows method. Running the code
Set sa = CreateObject _ ("Shell.Application") _ sa.ShutdownWindows
has the same result as clicking Shut Down in the Start menu.
Browsing for Folders
If your users need to browse through files or folders, you can use the Shell .Application object's BrowseForFolder method. This method takes up to four arguments, the first three of which are mandatory. The method's syntax is
FolderName = BrowseForFolder _ (window, title, options _ \[, rootFolder\])
In this syntax, the window argument specifies the parent window for the Browse For Folder dialog box. In scripts, you typically set this parameter to 0, meaning the Browse For Folder dialog box will be the desktop's topmost window. The title argument specifies the title you want inside the dialog box. The options argument lets you customize the dialog box's functionality. The optional rootFolder argument specifies the dialog box's root folder. Let's take a closer look at the options and rootFolder arguments.
The options argument. To customize the Browse For Folder dialog box's functionality, you can specify any combination of applicable constants in the options argument. Table 2 shows some of these constants. (The full list is available at http://msdn.microsoft .com/library/default.asp?url=/library/psdk/shellcc/shell/structures/browseinfo.htm.) To use these constants, you just need to import them into your script. One way is to use Const statements. For example, the code in Listing 1 uses Const statements to import the BIF_EDITBOX and BIF_NEWDIALOGSTYLE constants. Figure 1 shows the resulting dialog box.
If you have VBScript 5.0 or later and use runtime evaluation, the BrowseForFolder method can return two different data types. The data type depends on how you treat the method's return value. If you assign the return value to a variable with code such as
sFld = sa.BrowseForFolder(...)
the return value's data type is String. This string is exactly the text you highlighted. For example, if you click OK in Figure 1, the returned string will be My Documents. This string, however, doesn't help identify the precise folder you selected because the method returns only the folder's display name rather than its pathname.
If you don't assign the return value to a variable, BrowseForFolder returns an object of the Folder data type. Despite having the same name, this Folder object has nothing in common with the FSO model's Folder object. The Shell object model's Folder object is the COM representation of a Windows folder. The Folder object contains a collection of child objects, each representing an item in the folder. Hence, these child objects are called FolderItem objects.
The Shell object model's Folder object has a default property called Title that corresponds to the display name of the object in the Windows shell. Because Title is the default property, the code
returns a message box displaying the folder's display name, but sFld is an object, not a string. If you use VBScript's TypeName function in code such as
the message box reveals that sFld's data type is Folder2 (i.e., a Folder object under Win9x).
So, how do you obtain a folder's pathname? Because Windows folders aren't necessarily file-system folders, not all folders have a pathname. If they do, you can obtain their pathname with the code in Listing 2. This code transforms the folder into a FolderItem object. The FolderItem object has a Path property that you can use to obtain the pathname.
The rootFolder argument. In the BrowseForFolder's optional fourth parameter, you can specify a folder name or a constant to point to where you want to root the display tree that users can browse. For example, to root the display tree under My Computer, you can use that folder's constant (ssfDRIVES) in the code
Const ssfDRIVES = &H11 MsgBox sa.BrowseForFolder _ (0, "My Computer", 0, _ ssfDRIVES)
This rootFolder parameter is an extremely powerful tool because it lets users browse for specific items, such as printers and dial-up connections.
Opening Control Panel Applets
Control Panel applets are small libraries that provide configuration capabilities. These libraries are special DLLs that have the extension .cpl.
To open a Control Panel applet, you typically double-click it. However, you can also programmatically open a Control Panel applet through the Shell because the .cpl libraries are in the System32 folder.
To programmatically open an applet, you need to know the filename of the .cpl library. Web Table 1 on the Win32 Scripting Journal Web site (http://www.win32scripting.com/) provides the names for the main Windows 2000 applets. When you know the library's filename, you use it with the Shell.Application object's ControlPanelItem method to open the applet. For example, to open the Display properties dialog box, you use the code
Set sa = CreateObject _ ("Shell.Application") _ sa.ControlPanelItem("desk.cpl")
A .cpl library can contain more than one applet. For example, in Win2K, Microsoft placed all the standard system Control Panel applets in the sysdm.cpl file. The ControlPanelItem method supports a special syntax that lets you open a particular applet in a library with multiple applets. You can even specify which tab you want initially selected. This syntax is possible because each Control Panel applet is represented by a collection of property pages. You use a special parameter to tell the system which property page you want. For example, the following code opens the first applet (i.e., System Properties) in the sysdm.cpl library and selects that applet's third page:
sa.ControlPanelItem _ ("sysdm.cpl,@0,2")
The number after the filename identifies the applet within the library. By default, 0 is the first applet in the .cpl file because the number is a 0-based index. You must precede the applet number with the at sign (@). The last number in the special syntax is the 0-based index for the tab. If you specify a wrong value for either number, the method defaults to 0.
If you want to use the default value (i.e., 0) for either argument, you can simply omit that argument. For example, the code
sa.ControlPanelItem _ ("sysdm.cpl,,1")
opens the second page of the System Properties dialog box.
If you want to open the Add New Hardware wizard in Win2K, you run the code
However, in earlier versions of Windows, this wizard is the second applet within the sysdm.cpl library. Consequently, the code is
sa.ControlPanelItem _ ("sysdm.cpl,@1")
Unfortunately, Microsoft hasn't published any formal documentation that details the applets in each .cpl library. However, at least for system applets, you might try searching the Microsoft Support Web site (http://support.microsoft.com/) with the keyword applet to see whether any published articles contain this information.
Accessing Special Folders
Suppose you want to enumerate and process all the items in some folders, regardless of whether they're file-system folders or special folders. The Shell object model provides you with an API that you can use. The key to this API is the NameSpace method.
The NameSpace method instantiates a Folder object based on the information you provide. You can use this Folder object and its FolderItem objects as a starting point for further exploration.
The NameSpace method takes one argument. If you want to access a directory, you use a fully qualified path as the argument. For example, if you want to access the directory on the C drive, you specify
Set myFolder = _ sa.NameSpace("C:\")
If you want to access a special folder, you use a special-folder constant. Table 3 shows the constants for several main special folders. You can find a more complete list at http://msdn .microsoft.com/library/default.asp?url= /library/psdk/shellcc/shell/objects/ shell/shellspecialfolderconstants.htm. Or, you can go into Visual Studio's (VS's) shlobj.h file and locate all the constants that start with CSIDL. A third approach is to create a Visual Basic (VB) project, reference the Microsoft Shell library (Shell Controls and Automation is the description), use the Object Browser to go into the Shell32 library, and open the enumeration called ShellSpecialFolderConstants. Table 3 is a subset of this enumeration.
For example, suppose you want to access the special folder My Computer. You can use the code
Set myFolder = _ sa.NameSpace(ssfDRIVES)
After you reference the special-folder constant, you need to import that constant into your script. Although you can use Const statements, a better approach is to use the XML-based WSH file (.wsf) format. (To use the .wsf format, you need to run WSH 2.0 or later.)
Suppose you have a VBScript file, drives.vbs, that uses special-folder constants. Here's how you use the .wsf format to import the constants. First, create a file, myfile.wsf, and enter the code in Listing 3. This code simply wraps the .vbs file into a .wsf workspace. The advantage of using a .wsf workspace is that you can reference external COM objects and automatically import any declaration in the context in which the .vbs file will run. Now, you can use just one line of code to import, access, and display the My Computer folder:
With this approach, you avoid having to fill your .vbs file with numerous Const statements. Even better, this approach lets you develop the .vbs logic while avoiding any further contact with XML or other details of the .wsf syntax.
Because Shell.Application is the Shell object model's root object, knowing how to use it is vital. I've covered the basics here; if you want more information about this object, go to http://msdn.microsoft.com/library/default.asp? url=/library/psdk/shellcc/shell/objects/shell/shell.htm.
With the Shell.Application object, you can browse folders, access applets, and access special folders. In addition, the Shell.Application object lets you access the Folder and FolderItem objects. I'll cover these objects in detail next month.