*********************************************************************
WINDOWS FILE SEARCH SUBROUTINE
*********************************************************************

Visual Basic 3.0 Professional comes with a sample app called WINSEEK.MAK 
(in the vb\samples\filectls directory). This program allows the user to 
select a directory and search it and all subdirectories for a certain 
file extension.

The problem is that it takes about 10 times longer to do a search than 
does the search utility in File Manager. On my machine (dx-33, 8Megs RAM, 
Windows 3.11, 540 Meg Hard Drive, about 9500 files) the File Manager 
utility takes about 5 seconds to find 537 WAV files, while WINSEEK.MAK 
takes almost a minute. This is completely unacceptable.

I think the problem is that this app uses the filelistbox and 
directorylistbox controls, manipulting their Path properties to search 
through all the appropriate directories. When you update the dirlistbox, 
it in turn updates the filelistbox, and I think it just adds alot of time 
in addition to the code which picks off the files that match and puts them 
in a list box.

An alternative is to use the Dir($) function. The drawback to this is that 
you cannot (easily) know the difference between a file and a directory -- 
let me explain.

You must first call the function with at least an existing path. For 
example, 

filename = Dir$("c:\")

and filename will contain the name of the first file in the specified 
directory. I say first -- it is the first file on the directory as far as 
the disk is concerned. In other words the files appear to be retreived in 
not any particular order. Now you can call the function again, this time 
without the argument,

filename = Dir$

and filename will contain the next file in the specified directory. You can 
do this until the function returns a NULL filename, indicating that there 
are no more files. The next time the function is called, a new path must be 
supplied or an error will occur.

This can be used to list all files in a particular directory. In addition, 
there are flags you can set so that the function not only returns regular 
files, but hidden, read only, and directories as well. I said AS WELL. There 
is no flag you can set to get ONLY directories.

An additional discomfort here is that files need not have a three character 
extension, and directory names may include a period. So you cannot just look 
for the period and assume from that whether the name is a file or directory.

***********
update: this form and code below will work as fast as the find utility in
File Manager, except that no directory will be searched if it contains a ".".
On my Hard Disk, this eliminates 5 out of 404 directories. To search every
directory, eliminate the "*." patterns from the code below.

******************************
Here's My Solution
******************************

First check the directory for all files that match. Very simple.

    ' get all files on this directory which match pattern
    If Right$(thispath, 1) <> "\" Then thispath = thispath + "\"
    thisfile = Dir$(thispath + thispattern, 0)
    Do While thisfile <> ""
        list1.AddItem LCase$(thispath + thisfile)
        thisfile = Dir$
    Loop

Now we look at ALL the files in this directory(with no extension, ie no "."
), and put them in an array.

    ' get all files on this directory
    thisfile = Dir$(thispath + "*.", 0)
    thesefiles = 0
    ReDim filelist(10)
    Do While thisfile <> ""
        thesefiles = thesefiles + 1
        If (thesefiles Mod 10) = 0 Then ReDim Preserve filelist(thesefiles + 10)
		' I don't want to guess how many files will be in this directory
		' and I don't want to redim on EVERY file found
        filelist(thesefiles) = thisfile
        thisfile = Dir$
    Loop

The filelist array now contains the names of the files in this directory having
no ".".

Now we want to look at the files AND subdirectories in this directory. Upon 
getting each name, we will check it against the above array -- if it doesn't 
match then it is a directory! These names will be put into a separate array.

    ' now look at all "names" on this directory
    thisfile = Dir$(thispath + "*.", 16)
    checkfile = 1
    thesedirs = 0
    ReDim dirlist(10)
    Do While thisfile <> ""
        ' now check to see if this name is on the file list
        If thisfile = "." Or thisfile = ".." Then
            ' do nothing, we don't count these as directories
        ElseIf thisfile = filelist(checkfile) Then
            ' assuming the files are on the disk in the same order -- a safe
	    ' assumption unless files have been added or deleted while this sub 
	    ' was in progress -- we only need to check one file in the array. If 
	    ' it matches, increment the counter
            checkfile = checkfile + 1
        Else
	    ' we have found a subdirectory . . . . save it!
            thesedirs = thesedirs + 1
            If (thesedirs Mod 10) = 0 Then ReDim Preserve dirlist(thesedirs + 10)
            dirlist(thesedirs) = thisfile
        End If
        thisfile = Dir$
    Loop

Now dirlist is an array which contains all the names of the subdirectories of 
this directory. We finally must call this sub (recursive calling) for all the 
subdirectories. This sub, although calling itself, will only be as recursive as 
the deepest directory. In other words, if a directory looked like 
c:\first\second\third\fourth\fifth\sixth then the sub would be nested on itself 
6 times. (You run into stack space problems after 30 or more recursions). What 
I'm trying to say is that it may result in an error "out of stack space" if the 
hard drive had some really multilevel directories.

    ' now lets go through all subdirectories, and call this sub
    For x = 1 To thesedirs
        Call dirloop(thispath + dirlist(x), thispattern)
    Next x
    totalsearched = totalsearched + x - 1
    text2.Text = totalsearched

the final line updates a counter on the form.

This is 15 to 20 times faster than the WINSEEK.MAK included with VB 3.0. As
mentioned earlier, the code above will not check directories which have a "."
in their name. To check these directories as well, simply delete the + "*." parts
of the two Dir$ functions in which it appears. Then this will be about 5 times
faster than WINSEEK.MAK, and about 2 or 3 times slower than File Manager. Well,
maybe I can close the gap farther by writing a DLL. . . . . . . . 

Good Luck, and I hope this helps you. If you have any suggestions on how to speed 
up the code, please let me know!

Later!

Jay Windley
jaywindley@AOL.COM