Handling files and folders interactively requires that the user specify the pathnames of files and folders at run time. In previous chapters, we used the InputBox function or the WSHInputBox method to implement an input dialog box. But how do you implement file dialog boxes in WSH scripts? Let's look at two approaches.
If you need the path to a folder, Windows provides the dialog box shown in Figure 12-17. The user can easily select a drive and the folder. The good news is that you can invoke this dialog box from a WSH script.
Figure 12-17 Dialog box for selecting a folder
NOTE
The dialog box is provided by a function contained in the file Shdocvw.dll, which is part of Internet Explorer versions 4 and 5. You also need Shell32.dll version 4.71 or later, which is available in Windows 98 (version 4.72) and Windows 2000 (version 5). In Windows 95 and Windows NT 4, Shell32.dll version 4.71 is available if Internet Explorer 4 is installed with the Active Desktop update. In Windows 95 and Windows NT, installing Internet Explorer 5 doesn't update Shell32.dll. You must install Internet Explorer 4 with Active Desktop and then upgrade to Internet Explorer 5.
Before you can access the methods of the Internet Explorer 4 or 5 Application object, you must create an object reference by using the following command:
Set objDlg = WScript.CreateObject("Shell.Application") |
You can then use the methods of the Application object and its subobjects.
To invoke the dialog box shown in Figure 12-17, you use the BrowseForFolder method:
Set objF = objDlg.BrowseForFolder(hWnd, Title, Options[, Root]) |
This method returns a reference to an object of the Windows shell's namespace (which is different from the FileSystemObject object). The parameters of this method are not well documented, but I've collected the following information:
Table 12-4 Constants for the Third Parameter of BrowseForFolder*
Constant | Description |
---|---|
&H0001 | Only file system folders can be selected. If this bit is set, the OK button is disabled if the user selects a folder that doesn't belong to the file system (such as the Control Panel folder). |
&H0002 | The user is prohibited from browsing below the domain within a network (during a computer search). |
&H0004 | Room for status text is provided under the text box. (I haven't found a way to show the status, however.) |
&H0008 | Returns file system ancestors only. |
&H0010 | Shows an edit box in the dialog box for the user to type the name of an item. |
&H0020 | Validate the name typed in the edit box. |
&H1000 | Enables the user to browse the network branch of the shell's namespace for computer names. |
&H2000 | Enables the user to browse the network branch of the shell's namespace for printer names. |
&H4000 | Allows browsing for everything. |
* Values are documented in the file Shlobj.h, which is part of the Platform SDK.
Table 12-5 Constants for the Fourth Parameter of BrowseForFolder
Constant | Description |
---|---|
0 | The Desktop (virtual) folder is the root directory. Using this constant along with &H0001 for the third parameter circumvents problems with the OK button. |
1 | Internet Explorer is the root. |
2 | The Programs folder of the Start menu is the root. |
3 | The Control Panel folder is the root. The third parameter must be set to &H4000 (browse for everything). |
4 | The Printers folder is the root. The third parameter must be set to &H4000 (browse for everything). |
5 | The Documents folder of the Start menu is the root. |
6 | The Favorites folder of the Start menu is the root. |
7 | The Startup folder of the Start menu is the root. The third parameter must be set to &H4000 (browse for everything). |
8 | The Recent folder is the root. The third parameter must be set to &H4000 (browse for everything). |
9 | The SendTo folder is the root. The third parameter must be set to &H4000 (browse for everything). |
10 | The Recycle Bin folder is the root. The third parameter must be set to &H4000 (browse for everything). |
11 | The Start menu folder is the root. |
16 | The Desktop (physical) folder is the root. |
17 | My Computer is the root. |
18 | Network Neighborhood is the root. |
19 | The Nethood folder is the root. |
20 | The Fonts folder is the root. |
21 | The Templates folder is the root. |
NOTE
The BrowseForFolder method is powerful but potentially dangerous because it can retrieve shell namespace objects. Changing these objects in your script can cause a lot of problems on your machine. If you use the method only to browse file system folders, there's no risk.
The next sample uses only three parameters, and the third parameter is set to &H0010 (show edit box) + &H0001 (only file system objects). If the user selects a folder and closes the dialog box using the OK button, the method returns the selected folder name.
Listing 12-24 invokes a Browse For Folder dialog box. After the user closes the dialog box, the script uses both methods described in this section to detect whether the user clicked the OK button or the Cancel button. Therefore, two dialog boxes with the results are shown. Note that the following sample doesn't return the full path to the selected object. (The next sample has a BrowseForFolder function, which derives the full path to the object.)
Listing 12-24 Dialog.vbs
'************************************************ ' File: Dialog.vbs (WSH sample in VBScript) ' Author: (c) G. Born ' ' Using the shell dialog box to select a folder '************************************************ Option Explicit ' Flags for the options parameter Const BIF_returnonlyfsdirs = &H0001 Const BIF_dontgobelowdomain = &H0002 Const BIF_statustext = &H0004 Const BIF_returnfsancestors = &H0008 Const BIF_editbox = &H0010 Const BIF_validate = &H0020 Const BIF_browseforcomputer = &H1000 Const BIF_browseforprinter = &H2000 Const BIF_browseincludefiles = &H4000 Dim wsh, objDlg, objF ' Get Application object of the Windows shell. Set objDlg = WScript.CreateObject("Shell.Application") ' Use the BrowseForFolder method. ' For instance: Set objF = objDlg.BrowseForFolder _ ' (&H0, "Select the folder to copy", &H10, "C:\Born") Set objF = objDlg.BrowseForFolder (&H0, _ "Select the folder to copy", _ BIF_editbox + BIF_returnonlyfsdirs) ' Here we use the first method to detect the result. If IsValue(objF) Then MsgBox "Selected folder: " & objF.Title Else MsgBox "Canceled" End If ' Here we use TypeName to detect the result. If InStr(1, TypeName(objF), "Folder") > 0 Then MsgBox "Selected folder: " & objF.Title Else MsgBox "Canceled" End If Function IsValue(obj) ' Check whether the value has been returned. Dim tmp On Error Resume Next tmp = " " & obj If Err <> 0 Then IsValue = False Else IsValue = True End If On Error GoTo 0 End Function '*** End |
TIP
The Shdocvw.dll file contains additional objects, properties, and methods for accessing the Windows shell. (See also Chapter 14 for more information on accessing the Windows shell.) You can find descriptions at http://msdn.microsoft.com/library/default.asp. You can also inspect the methods by using the Object Browser in Microsoft Script Editor, Microsoft Visual Basic Editor (which is available in each Microsoft Office application), or Microsoft Visual Basic 5 Control Creation Edition (CCE) if you define a reference to this DLL file. (See Advanced Development with Microsoft Windows Script Host 2.0 for details.)
Listing 12-24 doesn't support the path to a given object, and if the user selects a drive, the volume name is retrieved along with the drive letter. The sample also doesn't allow you to select files in the Browse For Folder dialog box.
Let's extend the program a bit. A value of &H4000 (the constant BIF_browseincludefiles) also allows you to use BrowseForFolder to select files. The following command invokes the Browse For Folder dialog box and allows file selection:
Set oItem = WshShell.BrowseForFolder( _ &H0, "Select a file or folder to copy", _ BIF_returnonlyfsdirs + BIF_browseincludefiles, "C:\") |
BIF_browseincludefiles must be defined and the variable WshShell must be a valid object variable pointing to the WshShell object. The method returns an object, which is assigned to the variable oItem. This object variable doesn't contain the path to the folder, so you need something to retrieve the full path and the name of a selected object. You can use the following command:
name = oItem.ParentFolder.ParseName(oItem.Title).Path |
Within this statement, the ParentFolder method is applied to the object. This method returns an object that hosts the parent folder. Then you apply the ParseName method to select an entry in the collection. The method retrieves the name of the selected object, which is returned by the oItem.Title property. The Path property of the object contains the entire path, including the name.
At this point, you're done (if you're omitting error checking). Unfortunately, if the user closes the dialog box by clicking the Cancel button, the preceding statement doesn't return a valid path and object name, and a run-time error (code 424) occurs. Also, the BrowseForFolder method causes a run-time error (code 5) in Windows 2000 if a file is selected from the root folder of a drive. In addition, if the user selects a drive, you have to extract the drive letter from the volume name.
To simplify handling, I moved all the code into a user-defined function named BrowseForFolder. You can call the function by using the following statement:
tmp = BrowseForFolder(Title, flags, dir) |
The Title parameter submits the text shown in the dialog box. The flags parameter specifies the code (see Table 12-4) to search for files and folders. The dir parameter is a string containing the path that's selected in the dialog box. If you submit the value "", My Computer is preselected.
The function returns a string containing the path to the object. If the string contains the value "-1", the user clicked the Cancel button. A value of "-5" indicates that the user selected a file in the root folder, which Windows 2000 doesn't allow. You can use the following code to determine whether the returned name is valid:
file = BrowseForFolder(Title, flags, dir) If file = "-5" Then WScript.Echo "Not possible to select files in root folder" Else If file = "-1" Then WScript.Echo "No object selected; Cancel clicked" Else WScript.Echo "Object: ", file End If End If |
Listing 12-25 is a small VBScript program that invokes the Browse For Folder dialog box and lets the user select a file or a folder. The result is shown in a dialog box (Figure 12-18).
Figure 12-18 Selecting a file in the Browse For Folder dialog box
Listing 12-25 FileSelectDialog.vbs
'******************************************************** ' File: FileSelectDialog.vbs (WSH sample in VBScript) ' Author: (c) G. Born ' ' Using the shell dialog box to select a folder ' or a file ' Warning: A run-time error occurs if the script ' is executed in Windows 2000 and the user selects ' a file in the root folder of a drive. '******************************************************** Option Explicit ' Flags for the options parameter Const BIF_returnonlyfsdirs = &H0001 Const BIF_dontgobelowdomain = &H0002 Const BIF_statustext = &H0004 Const BIF_returnfsancestors = &H0008 Const BIF_editbox = &H0010 Const BIF_validate = &H0020 Const BIF_browseforcomputer = &H1000 Const BIF_browseforprinter = &H2000 Const BIF_browseincludefiles = &H4000 Dim file file = BrowseForFolder( _ "Select a file or folder to copy", _ BIF_returnonlyfsdirs + BIF_browseincludefiles, _ "") If file = "-5" Then WScript.Echo "Not possible to select files in root folder" Else If file = "-1" Then WScript.Echo "No object selected; Cancel clicked" Else WScript.Echo "Object: ", file End If End If ' Using the shell's BrowseForFolder method to ' return the full path to the selected object ' title = Text shown in the dialog box ' flag = One of the values for controlling the ' BrowseForFolder behavior ' dir = Preselected directory (can be "") Function BrowseForFolder(title, flag, dir) On Error Resume Next Dim oShell, oItem, tmp ' Create WshShell object. Set oShell = WScript.CreateObject("Shell.Application") ' Invoke Browse For Folder dialog box. Set oItem = oShell.BrowseForFolder(&H0, title, flag, dir) If Err.Number <> 0 Then If Err.Number = 5 Then BrowseForFolder= "-5" Err.Clear Set oShell = Nothing Set oItem = Nothing Exit Function End If End If ' Now we try to retrieve the full path. BrowseForFolder = oItem.ParentFolder.ParseName(oItem.Title).Path ' Handling: Cancel button and selecting a drive If Err<> 0 Then If Err.Number = 424 Then ' Handle Cancel button. BrowseForFolder = "-1" Else Err.Clear ' Handle situation in which user selects a drive. ' Extract drive letter from the title--first search ' for a colon (:). tmp = InStr(1, oItem.Title, ":") If tmp > 0 Then ' A : is found; use two ' characters and add \. BrowseForFolder = _ Mid(oItem.Title, (tmp - 1), 2) & "\" End If End If End If Set oShell = Nothing Set oItem = Nothing On Error GoTo 0 End Function '*** End |
NOTE
On machines that had only Windows 2000 or Windows 98 installed, the BrowseForFolder method failed to return valid filenames during the first attempt to access a folder. An error code reported that the selected file was missing. After I installed Microsoft Office on those machines, the error didn't occur again.