Option Explicit
Public Const MAX_PATH = 260 'GetDriveType return values Public Const DRIVE_REMOVABLE = 2 Public Const DRIVE_FIXED = 3 Public Const DRIVE_REMOTE = 4 Public Const DRIVE_CDROM = 5 Public Const DRIVE_RAMDISK = 6 Type FILETIME dwLowDateTime As Long dwHighDateTime As Long End Type Type WIN32_FIND_DATA dwFileAttributes As Long ftCreationTime As FILETIME ftLastAccessTime As FILETIME ftLastWriteTime As FILETIME nFileSizeHigh As Long nFileSizeLow As Long dwReserved0 As Long dwReserved1 As Long cFileName As String * MAX_PATH cAlternate As String * 14 End Type Public Declare Function GetLogicalDriveStrings _ Lib "kernel32" Alias "GetLogicalDriveStringsA" _ (ByVal nBufferLength As Long, _ ByVal lpBuffer As String) As Long Public Declare Function FindFirstFile _ Lib "kernel32" Alias "FindFirstFileA" _ (ByVal lpFileName As String, _ lpFindFileData As WIN32_FIND_DATA) As Long Public Declare Function FindNextFile _ Lib "kernel32" Alias "FindNextFileA" _ (ByVal hFindFile As Long, _ lpFindFileData As WIN32_FIND_DATA) As Long Public Declare Function FindClose _ Lib "kernel32" (ByVal hFindFile As Long) As Long 'flags for the user options Public displayExpanded As Boolean Public displaySorted As Boolean Public NoOfDrives As Integer Public Function TrimNull(startstr As String) As String Dim pos As Integer pos = InStr(startstr, Chr$(0)) If pos Then TrimNull = Left$(startstr, pos - 1) Exit Function End If 'if this far, there was no Chr$(0), so return the string TrimNull = startstr End Function Public Sub GetAllDrivesFolders(tvwTree As Control, nodParentNode As Node) 'this routine uses a pre-dimmed array to speed up 'processing. Initially, the array is DIM'med to '200 elements; in the While loop it is increased 'another 200 elements when "found Mod 200 = 0" '(or the number found divided by 200 equals 0). 'At the end of the loop, it is resized down to the 'total found. This is significantly faster than 'using a Redim Preserve statement for each element found. Dim nodX As Node Dim WFD As WIN32_FIND_DATA Dim hFile As Long Dim sFile As String Dim sPath As String Dim i As Integer Dim r As Long Dim found As Integer 'assign the fullpath property to the path to search, 'assuring that the path is qualified. If Right$(nodParentNode.FullPath, 1) "\" Then sPath = nodParentNode.FullPath & "\" Else: sPath = nodParentNode.FullPath End If 'find the first file matching the parameter \*.* hFile = FindFirstFile(sPath & "*.*" & Chr$(0), WFD) 'reset the counter flag found = 0 ReDim fArray(200) If hFile -1 Then sFile = TrimNull(WFD.cFileName) WFD.dwFileAttributes = vbDirectory While FindNextFile(hFile, WFD) sFile = TrimNull(WFD.cFileName) 'ignore the 2 standard root entries If (sFile ".") And (sFile "..") Then If (WFD.dwFileAttributes And vbDirectory) Then found = found + 1 'if found is at 200, then add some more array elements If found Mod 200 = 0 Then ReDim Preserve fArray(found + 100) fArray(found) = sFile End If End If Wend End If r = FindClose(hFile) 'trim down the array to equal the elements found ReDim Preserve fArray(found) 'add the folders to the treeview For i = 1 To found Set nodX = tvwTree.Nodes.Add(nodParentNode.Key, _ tvwChild, _ sPath & fArray(i) & "Dir", _ fArray(i)) 'and get some more GetAllDrivesFolders tvwTree, nodX Next i nodParentNode.Sorted = displaySorted nodParentNode.Expanded = displayExpanded End Sub Private Sub Form_Load() 'centre the form Me.Move (Screen.Width - Me.Width) / 2, (Screen.Height - Me.Height) / 2 'set initial options displaySorted = True displayExpanded = False 'load the system drives GetSystemDrives 'store the initial number of treeview elements for 'later subtraction when presenting the total number 'of files loaded (tvwControl_click routine) NoOfDrives = tvwControl.Nodes.Count lblMessage = "Click on any drive letter to load it's folders." End Sub Private Sub cmdEnd_Click() Unload Me Set Form1 = Nothing End End Sub Private Sub GetSystemDrives() Dim nodX As Node Dim r As Long Dim allDrives As String Dim currDrive As String Dim drvIcon As Integer 'get the list of all available drives allDrives = rgbGetAvailableDrives() Do Until allDrives = Chr$(0) 'strip off one drive item from the allDrives$ currDrive = StripNulls(allDrives) 'we can't have the trailing slash, so .. currDrive = Left$(currDrive, 2) 'add the drive to the treeview Set nodX = tvwControl.Nodes.Add(, tvwChild, _ currDrive & "Dir", _ currDrive) nodX.Expanded = True Loop 'force sorting of the drive letters nodX.Sorted = True End Sub Private Function rgbGetAvailableDrives() As String 'returns a single string of available drive 'letters, each separated by a chr$(0) Dim r As Long Dim tmp As String tmp = Space$(64) r& = GetLogicalDriveStrings(Len(tmp), tmp) rgbGetAvailableDrives = Trim$(tmp) End Function Private Function StripNulls(startstr As String) As String 'Take a string separated by a chr$(0), and split off 1 item, and 'shorten the string so that the next item is ready for removal. Dim pos As Integer Dim c As Integer pos = InStr(startstr$, Chr$(0)) If pos Then StripNulls = Mid$(startstr, 1, pos - 1) startstr = Mid$(startstr, pos + 1, Len(startstr)) Exit Function End If End Function Private Sub tvwControl_Click() Dim nodX As Node 'show a wait message for long searches lblMessage = "Searching drive " & tvwControl.SelectedItem & " for folders ... please wait" DoEvents 'identify the selected node Set nodX = tvwControl.SelectedItem 'verify it's valid If (UCase$(Right$(nodX.Key, 3)) = "DIR") And (nodX.Children = 0) Then GetAllDrivesFolders tvwControl, nodX End If 'subtract NoOfDrives because initial drives loaded 'should not be counted as a folder lblMessage = "Total folders displayed : " & tvwControl.Nodes.Count - NoOfDrives End Sub 'Comment 'When the form loads, the treeview is filled with the available drives via 'the GetSystemDrives routine. Clicking a drive letter invokes the 'tvwControl_Click() routine, which calls the GetAllDrivesFolders Sub. 'The first execution of GetAllDrivesFolders returns the first-level of 'folders (try commenting out the line "GetAllDrivesFolders tvwTree, nodX" 'to demonstrate), and for each folder added to the treeview, the routine 'again calls GetAllDrivesFolders passing the node item to search from. 'Once no more folders are found (that is, there are no more folders within 'a given level), control returns to the calling line, which loads the next 'folder and restarts the process until all the first-level folders have 'been searched for sub-folders This code is intended to demonstrate how to recursively search for all folders on a target drive using the Win95/NT4 APIs FindFirstFile and FindNextFile, and display the results into a treeview control. FindFirstFile, on successful finding of a file matching the filespec passed returns a handle for subsequent calls by FindNextFile, and the data of the retrieved file in the WIN32_FIND_DATA structure. The structure member dwFileAttributes, when AND'd with the VB constant vbDirectory can be used to determine if the returned item is a file or folder. The routine stores the folder names in an array, and once a pass is completed at each level, creates the treeview data. Start a new project, and to the form add a command button (cmdEnd), a Treeview control (tvwControl) and an autosizing label (lblMessage) as indicated in the illustration. Place the following into the general declarations area of a bas module: |