Figure 5   Shell Object Components

Method Description
BrowseForFolder(hwnd,szTitle, nOptions, vRoot) Runs the system tree-based dialog for choosing a folder. A simplified version of the SHBrowseForFolder can also be a special folder such as Printers, Programs, Desktop, Recycle Bin, and so on.
CascadeWindows Orders all the open top-level windows forming a cascade.
ControlPanelItem(szDir) Runs the specified Control Panel's property dialog. Note that szDir must be the name (file + ext) of a valid CPL file.
EjectPC Ejects the computer from its docking station. (For those computers that have an Eject command on the Start menu.)
Explore(vDir) Runs the Explorer from the specified folder. Note that vDir can also be a special folder such as Printers, Programs, Desktop, Recycle Bin, and so on.
FileRun Runs the system's Run dialog. The same as selecting Run from the Start menu.
FindComputer Runs the system's Find Computer dialog. The same as selecting Find | Computer from the Start menu.
FindFiles Runs the system's Find Files dialog. The same as selecting Find | Files or Folders from the Start menu.
Help The same as selecting Help from the Start menu.
MinimizeAll Clears the desktop iconizing all the open windows. The same as clicking the desktop button on the taskbar or pressing Windows + M.
NameSpace(vDir) Creates and returns a folder object for the specified path. Note that vDir can also be a special folder such as Printers, Programs, Desktop, Recycle Bin, and so on.
Open(vDir) Opens the specified folder as a separate window. Note that vDir can also be a special folder such as Printers, Programs, Desktop, Recycle Bin, and so on.
RefreshMenu Refreshes the Start menu to reflect possible changes. It's useful if you programmatically modify some of the system's policies that affect the Start menu.
SetTime Displays the dialog to set date and time. The same as double-clicking on the clock icon in the tray area.
ShutdownWindows Starts the standard procedure to exit Windows. The same as the Start menu's Shutdown command.
Suspend Suspends the computer. (For those computers that have a Suspend command on the Start menu.)
TileHorizontally Horizontally tiles all the top-level windows currently open.
TileVertically Vertically tiles all the top-level windows currently open.
TrayProperties Runs the Taskbar Properties system dialog. The same as selecting Settings | Taskbar from the Start menu.
UndoMinimizeALL Restores the desktop after a MinimizeAll command. The same as clicking the desktop button on the taskbar or pressing Shift + Windows + M. Note the double uppercase L in the name.
Windows Returns a collection of all the top-level windows currently open.


Figure 7    Special Constants and their Folders

Constant Special Folder Virtual
ssfBITBUCKET The Recycle Bin. It refers to the directory where all the files marked for deletion are kept. No
ssfCONTROLS The Control Panel. It includes all the Control Panel's applets. Yes
ssfDESKTOP The Desktop. It's the object that represents the root of the shell's namespace. Yes
ssfDESKTOPDIRECTORY System directory where all the files (mostly shortcuts) are displayed on the Windows desktop. No
ssfDRIVES My Computer. It lists all the drives, printers, and devices on the local PC. Yes
ssfFAVORITES System folder containing bookmarks to favorite folders. No
ssfFONTS System folder containing the files for the installed fonts. No
ssfNETHOOD System directory where references to all the objects appearing in the Network Neighborhood folder are kept. No
ssfNETWORK The Network Neighborhood virtual folder. Yes
ssfPERSONAL System folder containing personal files. No
ssfPRINTERS System folder containing the links to the installed printers. No
ssfPROGRAMS System folder which lists all the shortcuts in the Start | Programs menu. No
ssfRECENT System folder containing all the recently used documents. Pointed by the Start | Documents menu. No
ssfSENDTO System folder containing all the items of the Send To menu. No
ssfSTARTMENU System folder containing all the customizable items of the Start menu. No
ssfSTARTUP System folder containing links to all the programs that run at system startup. No
ssfTEMPLATES System folder for all the document templates. No


Figure 12   Invoking a Properties Dialog


 ' Global var to store a reference to the Printers folder.
 Private g_Printers As Folder
 
 
 Private Sub Form_Load()
     Dim o As New Shell
     Set g_Printers = o.NameSpace(ssfPRINTERS)
     
     ' Starts from 1 to skip over "Add Printer"
     List1.Clear
     For i = 1 To g_Printers.Items.Count - 1
         List1.AddItem g_Printers.Items.Item(i)
     Next
     
     Set o = Nothing
 End Sub
 
 
 Private Sub List1_Click()
     Dim fi As FolderItem
     
     List2.Clear
     Set fi = g_Printers.Items.Item(List1.ListIndex + 1)
     For i = 0 To fi.Verbs.Count - 1
         List2.AddItem fi.Verbs.Item(i).Name
     Next
 End Sub
 
 
 Private Sub List1_DblClick()
     Dim fi As FolderItem
     Set fi = g_Printers.Items.Item(List1.ListIndex + 1)
     fi.InvokeVerb "P&roperties"
 End Sub
 
 
 Private Sub List2_DblClick()
     Dim fi As FolderItem
     Dim fiv As FolderItemVerb
     
     Set fi = g_Printers.Items.Item(List1.ListIndex + 1)
     Set fiv = fi.Verbs.Item(List2.ListIndex)
     fiv.DoIt
 End Sub

Figure 15   BrowseForFolderEx


 Public Const MAX_PATH = 260
 
 Type BROWSEINFO
     hwndOwner As Long
     pidlRoot As Long
     pszDisplayName As String
     lpszTitle As String
     ulFlags As Long
     lpfn As Long
     lParam As Long
     iImage As Long
 End Type
 
 Declare Function SHBrowseForFolder Lib "shell32.dll" ( _
    lpbi As BROWSEINFO _
 ) As Long
 Declare Function SHGetPathFromIDList Lib "shell32.dll" ( _
    ByVal pidl As String, _
    ByVal pszPath As String _
 ) As Boolean
 Declare Sub CoTaskMemFree Lib "ole32.dll" ( _
   ByVal lpv As Long _
 )
 
 
 
 
 ' --------------------------------------------------
 ' // Browse for folders and returns the full
 ' // path name as a string.
 ' --------------------------------------------------
 Function BrowseForFolderEx( ByVal hWnd As Long, _
   ByVal title As String, ByVal options As Long, _
   Optional root As Variant ) As String
 
     Dim bi As BROWSEINFO
     Dim lpIdList As Long
     Dim sFolderName As String
     
     ' initializes the BROWSEINFO structure
     bi.hwndOwner = hWnd
     bi.lpszTitle = title
     bi.ulFlags = options
     
     ' defaults the missing argument to the DESKTOP
     If IsMissing( root ) Then
         bi.pidlRoot = 0
     Else
         bi.pidlRoot = root
     End If
 
     ' calls the API function
     lpIdList = SHBrowseForFolder( bi )
         
     ' converts the PIDL to a path name
     If lpIdList Then
        sFolderName = String(MAX_PATH, 0)
        SHGetPathFromIDList lpIdList, sFolderName
        BrowseForFolderEx = sFolderName
        CoTaskMemFree lpIdList
     End If
 End Function

Figure 18   CustomDirList.ctl


 Option Explicit
 ' This source code defines an ActiveX control that behaves like
 ' the Explorer's treeview. It lets you choose a directory from
 ' a treeview.
 
 Private g_Shell As Shell
 Private g_curFolder As String
 Private Const sfDesktop = "Desktop"
 Private Const sfMyComputer = "My Computer"
 Private Const imlIdDesktop = 1
 Private Const imlIdMyComputer = 2
 Private Const imlIdFolder = 3
 
 '----------------------------------------------------
 'Events
 '----------------------------------------------------
 Event SelChange(ByVal dirName As String)
 Event AddDirectory(ByVal dirName As String, canContinue As Boolean)
 
 '----------------------------------------------------
 ' FOLDER property (read/write)
 '----------------------------------------------------
 Public Property Get Folder() As String
     Folder = g_curFolder
 End Property
 
 Public Property Let Folder(ByVal New_Folder As String)
     If New_Folder <> sfDesktop And New_Folder <> sfMyComputer Then
         If Right(New_Folder, 1) <> "\" Then
             New_Folder = New_Folder + "\"
         End If
     End If
     
     g_curFolder = New_Folder
     PropertyChanged "Folder"
     SelectCurrentPath TreeView1
 End Property
 
 
 
 '----------------------------------------------------
 '----------------------------------------------------
 'Internal functions
 '----------------------------------------------------
 '----------------------------------------------------
 Private Sub TreeView1_Expand(ByVal Node As ComctlLib.Node)
     Node.Selected = True
     If Node.Child = "..." Then
         DoFillNode TreeView1, Node, Node.Tag
     End If
 End Sub
 
 Private Sub TreeView1_KeyUp(KeyCode As Integer, Shift As Integer)
     If KeyCode = vbKeyPageUp Or KeyCode = vbKeyPageDown Or _
        KeyCode = vbKeyUp Or KeyCode = vbKeyDown Then
         g_curFolder = TreeView1.SelectedItem.Tag
         RaiseEvent SelChange(g_curFolder)
     End If
 End Sub
 
 Private Sub TreeView1_MouseUp(Button As Integer, Shift As Integer, _
                               x As Single, y As Single)
   Dim n As Node
   
   Set n = TreeView1.HitTest(x, y)
   If Not n Is Nothing Then
      g_curFolder = TreeView1.SelectedItem.Tag
      RaiseEvent SelChange(g_curFolder)
   End If
 End Sub
 
 Private Sub UserControl_Initialize()
     Dim f As Folder
     Dim nLen As Long
     
     ' get the My Computer's folder
     Set g_Shell = New Shell
     Set f = g_Shell.NameSpace(ssfDRIVES)
     
     ' initialize the member with the current path
     g_curFolder = String(MAX_PATH, 0)
     nLen = GetCurrentDirectory(MAX_PATH, g_curFolder)
     g_curFolder = Left(g_curFolder, nLen)
     
     ' initialize the tree
     DoInitTree TreeView1, f
     SelectCurrentPath TreeView1
 End Sub
 
 Private Sub UserControl_Resize()
     TreeView1.Move 0, 0, UserControl.Width, UserControl.Height
 End Sub
 
 Private Sub DoInitTree(ByVal Tree As TreeView, ByVal f As Folder)
     Dim nodeDesktop, nodeMyComp, n As Node
     Dim i, nPos As Integer
     Dim sTemp As String
     
     ' add and expand the two main nodes
     Set nodeDesktop = Tree.Nodes.Add(, , "R", "Desktop", imlIdDesktop)
     Set nodeMyComp = Tree.Nodes.Add(nodeDesktop, tvwChild, , _
                                     "My Computer", imlIdMyComputer)
     Tree.Nodes.Item(1).Expanded = True
     Tree.Nodes.Item(2).Expanded = True
     nodeDesktop.Tag = sfDesktop
     nodeMyComp.Tag = sfMyComputer
     
     ' add the other nodes
     For i = 0 To f.Items.Count - 1
         If f.Items.Item(i).IsFolder And f.Items.Item(i).IsFileSystem Then
             
             ' determine the icon for the folder
             Dim sfi As SHFILEINFO
             SHGetFileInfo f.Items.Item(i).path, 0, sfi, Len(sfi), _
               SHGFI_ICON Or SHGFI_SMALLICON
             ImageList1.ListImages.Add , , HIconToPicture(sfi.hIcon)
             nPos = ImageList1.ListImages.Count
             
             ' add the drive node
             Set n = AddTreeItem(Tree, nodeMyComp, f.Items.Item(i).Name, nPos)
             
             ' save the full path
             n.Tag = f.Items.Item(i).path
             
             ' add a dummy node
             AddDummyNode Tree, n
         End If
     Next
 End Sub
 
 Private Sub DoFillNode(ByVal Tree As TreeView, ByVal n As Node, _
                        ByVal path As String)
 On Error GoTo Err_Handler
     
     Dim canContinue As Boolean
     Dim newNode As Node
     Dim i As Integer
     Dim dirName, sTemp As String
     
     ' remove the child dummy node
     Tree.Nodes.Remove (n.index + 1)
     
     ' get the directory list
     Dir1.path = path
     For i = 0 To Dir1.ListCount - 1
         dirName = GetDirFromPath(Dir1.List(i))
         
         ' notify that a new directory is being added
         If Right(Dir1.path, 1) = "\" Then
             sTemp = Dir1.path + dirName
         Else
             sTemp = Dir1.path + "\" + dirName
         End If
 
         canContinue = True
         RaiseEvent AddDirectory(sTemp, canContinue)
         If canContinue = True Then
             Set newNode = AddTreeItem(Tree, n, dirName, imlIdFolder)
             newNode.Tag = Dir1.List(i)
         End If
             
         ' count the subdirs (if any) and add a dummy node
         Dir2.path = Dir1.List(i)
         If Dir2.ListCount > 0 Then
             AddDummyNode Tree, newNode
         End If
     Next
     Exit Sub
 
 Err_Handler:
     Dim sText, sTitle As String
     If Err.Number = 68 Then
         sText = path + " is not accessible." + vbCrLf + Err.Description
         sTitle = "Exploring " + path
         MsgBox sText, vbCritical Or vbRetryCancel, sTitle
     End If
 End Sub
 
 Private Function AddTreeItem(ByVal Tree As TreeView, ByVal n As Node, _
                              ByVal text As String, ByVal index As Integer) As Node
 
         Set AddTreeItem = Tree.Nodes.Add(n, tvwChild, , text, index)
     'End If
 End Function
 
 Private Sub AddDummyNode(ByVal Tree As TreeView, ByVal n As Node)
     AddTreeItem Tree, n, "...", imlIdFolder
 End Sub
 
 Private Sub SelectCurrentPath(ByVal Tree As TreeView)
     Dim iStartPos, nPos, i As Integer
     Dim bExit As Boolean
     Dim curDrive, sTemp As String
     
     ' is it Desktop or My Computer?
     If LCase(g_curFolder) = LCase(sfDesktop) Or _
        LCase(g_curFolder) = LCase(sfMyComputer) Then
         ExpandNode Tree, g_curFolder
         Exit Sub
     End If
     
     ' get and expand the current drive node
     nPos = InStr(1, g_curFolder, "\")
     curDrive = Left(g_curFolder, nPos)
     ExpandNode Tree, curDrive
     
     ' scan the path for further directories
     bExit = False
     iStartPos = nPos
 
     While Not bExit
         i = InStr(iStartPos + 1, g_curFolder, "\")
         If i = 0 Then
             SelectNode Tree, g_curFolder
             bExit = True
         Else
             iStartPos = i
             sTemp = Left(g_curFolder, iStartPos - 1)
             ExpandNode Tree, sTemp
         End If
     Wend
     
 End Sub
 
 Private Sub SelectNode(ByVal Tree As TreeView, ByVal dirName As String)
     Dim path As String
     Dim i As Integer
     
     For i = 1 To Tree.Nodes.Count
         path = Tree.Nodes.Item(i).Tag
         If LCase(path) = LCase(dirName) Then
            Tree.Nodes.Item(i).Selected = True
            Tree.Nodes.Item(i).EnsureVisible
            Exit For
        End If
     Next
 End Sub
 
 Private Sub ExpandNode(ByVal Tree As TreeView, ByVal dirName As String)
     Dim path As String
     Dim i As Integer
     
     For i = 1 To Tree.Nodes.Count
         path = Tree.Nodes.Item(i).Tag
         If LCase(path) = LCase(dirName) Then
            Tree.Nodes.Item(i).Selected = True
            Tree.Nodes.Item(i).Expanded = True
            Exit For
        End If
     Next
 End Sub