Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Find-a-file 4

Status
Not open for further replies.

peekay

Programmer
Oct 11, 1999
324
ZA
I need to know whether a file with a certain name exists on a C drive and use the following function :<br>
<br>
Type WIN32_FIND_DATA ' 318 Bytes<br>
dwFileAttributes As Long<br>
nFileSizeHigh As Long<br>
nFileSizeLow As Long<br>
dwReserved¯ As Long<br>
dwReserved1 As Long<br>
cFileName As String<br>
cAlternate As String<br>
End Type<br>
<br>
Public lpFindFileData As WIN32_FIND_DATA<br>
Private A As Long, FileToFind As String<br>
<br>
Declare Function FindFirstFile& Lib &quot;kernel32&quot; Alias &quot;FindFirstFileA&quot; (ByVal lpFileName As String, lpFindFileData As WIN32_FIND_DATA)<br>
<br>
Public Sub FindFile()<br>
Dim FileFound As String<br>
FileToFind = &quot;frmFatal.frm&quot;<br>
A = FindFirstFile(FileToFind, lpFindFileData)<br>
FileFound = lpFindFileData.cFileName<br>
End Sub<br>
<br>
However I do not get satisfactory results. Am I using the function wrongly? Can somebody please help.<br>
Thanks<br>
PK<br>
<br>

 
PK,<br>
<br>
I have tried your function and have come up against the same problem as you - bad dll calling convention.<br>
<br>
This is not trivial stuff you're doing. When I've had this problem in the past it's been because of the function definition and translating the data types.<br>
<br>
Could I reccomend a book to you? It's Dan Appleman's Win32 for VB[56]. I've got it at home and I'll have a look this evening.<br>
<br>
Mike<br>
<p>Mike Lacey<br><a href=mailto:Mike_Lacey@Cargill.Com>Mike_Lacey@Cargill.Com</a><br><a href= Cargill's Corporate Web Site</a><br>
 
Have you tried the Dir function?<br>
Heres some example in Help <br>
<br>
Dim MyFile, MyPath, MyName<br>
' In Microsoft Windows:<br>
' Returns &quot;WIN.INI&quot; if it exists.<br>
MyFile = Dir(&quot;C:\WINDOWS\WIN.INI&quot;) <br>
<br>
' Returns filename with specified extension. If more than one *.ini<br>
' file exists, the first file found is returned.<br>
MyFile = Dir(&quot;C:\WINDOWS\*.INI&quot;)<br>
<br>
' Call Dir again without arguments to return the next *.INI file in the <br>
' same directory.<br>
MyFile = Dir<br>
<br>
' Return first *.TXT file with a set hidden attribute.<br>
MyFile = Dir(&quot;*.TXT&quot;, vbHidden)<br>
<br>
<br>

 
DougP<br>
Thanks for your tip which solved my problem<br>
I had indeed used the very same method a month ago when I had the same problem but due to my alzheimerian (blush)nature forgot about it.<br>
PK
 
Why don't you use the microsoft scripting object runtime library. Create a file system object and manage all these type of things. It's very easy that way. <p>Ravi Kochher<br><a href=mailto:rkochher@ssius.com>rkochher@ssius.com</a><br><a href= > </a><br>
 
Hi Raviman<br>
I have no knowledge of scripting objects. Can you please elucidate - maybe via email - or send some code<br>
Thanks<br>
pk<br>

 
Ok,<br>
Here is the sample code.<br>
<br>
Give the reference to the microsoft scripting runtime library.<br>
<br>
Then write the code as following.<br>
<br>
dim fso as new filesystemobject<br>
<br>
If fso.FileExists(source_filename) = False Then<br>
<br>
MsgBox &quot;The Specified File Doesn't exist. Please <br>
Specify A Valid File Name&quot;, vbInformation + Only, &quot;Data Transfer Utility&quot;<br>
end if<br>
<br>
<br>
<br>
<br>
Ps : Here explore the other properties of the filesystem object as well. It offers some nice features.This works in VB6.0 only. If you are using the VB5.0 version then you can download the scripting runtime library from the MS site.<br>
<p>Ravi Kochher<br><a href=mailto:rkochher@ssius.com>rkochher@ssius.com</a><br><a href= > </a><br>
 
Thanks for the tip Ravi. I will try it out<br>
PK
 
'This is for anyone who wants to know about the<br>
'FindFirstFile. Your sub will work fine but the<br>
'lpFileName$ (Your FileToFind$) requires the full<br>
'path.<br>
<br>
Public Function FindFile(FileToFind as String)as String<br>
Dim A as long<br>
A& = FindFirstFile(FileToFind$, lpFindFileData)<br>
FindFile = lpFindFileData.cFileName<br>
End Function<br>
<br>
'Example1<br>
Ret$=FindFile(&quot;C:\frmFatal.frm&quot;)<br>
'This would return the filename IF the file<br>
'exist under C:\<br>
<br>
'Example2<br>
Ret$=FindFile(&quot;C:\*.*&quot;)<br>
'This would return the first file under C:\<br>
<br>
'Example3<br>
Ret$=FindFile(&quot;C:\*.avi&quot;)<br>
'This would return the first .AVI under C:\<br>
<br>

 
I wish to thank Raviman and EveRYear for two excellent contributions.<br>
PK<br>
<p>PK Odendaal<br><a href=mailto: pko@mweb.co.za> pko@mweb.co.za</a><br><a href= > </a><br>
 
There have been many good suggestions in this thread and I would like to add a quick-and-dirty alternative. Some of you will probably puke when you see this but you have to remember that it's only an alternative for lazy programmers, such as yours truly, who don't like to type a lot or spend a lot of time debugging code or fretting about the API standing up and barking like a good doggie.<br>
<br>
Ofile$ = &quot;C:\DUH&quot;: SFile$ = &quot;*.TXT&quot;<br>
Sh$=&quot;C:\COMMAND.COM /C DIR /S /B C:\&quot;+Sfile$+&quot; &gt;&quot;+Ofile$<br>
x = Shell(Sh$)<br>
If FileLen(Ofile$) &lt; 1 Then<br>
MsgBox Sfile$ & &quot; not found.&quot;<br>
Else<br>
Open Ofile$ For Input As #1<br>
Do While Not EOF(1)<br>
Input #1, Fname$<br>
List1.AddItem Fname$<br>
Loop<br>
Close #1<br>
End If<br>
<br>
It certainly isn't a remarkable piece of code but it will do the job with virtually no debugging. What? Do we lose our dignity if we stoop to calls to the command interpreter in preference to DLLs? Or are we all aghast because of my severe sloth and inefficiency?
 
pretty much aghast really &lt;grin&gt; the Dir solution is just a <b>bit</b> clearer....<br>
<br>
-ml <p>Mike Lacey<br><a href=mailto:Mike_Lacey@Cargill.Com>Mike_Lacey@Cargill.Com</a><br><a href= Cargill's Corporate Web Site</a><br>
 
Oh well... just an alternative. It took me about three minutes to write a little sub to search an entire drive for matching files. Anybody had similar luck after pasting blocks of declarations and doing all the formal, proper stuff required to find FileName in the umpteenth layer of subdirectories?<br>
I wouldn't spend hours writing such a sub from scratch or debugging reusable objects to find a file on a hard drive. Let DOS do the work.<br>
I guess I'm a hard-case for the ugly but functional solution. LOL Mike, I hope I didn't truly offend anbody's programming sensibilities :)<br>

 
Oh - I'm immune to you by now...<br>
<br>
(Actually - I just used your code in a live application...) <p>Mike Lacey<br><a href=mailto:Mike_Lacey@Cargill.Com>Mike_Lacey@Cargill.Com</a><br><a href= Cargill's Corporate Web Site</a><br>
 
Alt255<br>
Thanks for your part as well. I'll test it and add it to my already rich arsenal of routines for this topic.<br>
PK <p>PK Odendaal<br><a href=mailto: pko@mweb.co.za> pko@mweb.co.za</a><br><a href= > </a><br>
 
Another example :<br>
<br>
'Insert the following code to your form:<br>
<br>
Private Sub Form_Load()<br>
'Replace 'calc.exe' with the name of the file you want to find.<br>
'You can put here 'cal*.*' to find file that start with 'cal'<br>
MsgBox PathTo(&quot;calc.exe&quot;)<br>
End Sub<br>
Function PathTo(strFile As String) As String<br>
Dim x As Integer<br>
Dim strDirs As String<br>
Dim strDir As String<br>
Dim strEntry As String<br>
'Replace 'C:\' with the drive you want to make the search on it.<br>
strDirs = &quot;C:\&quot; & vbNullChar<br>
Do While Len(strDirs)<br>
x = InStr(strDirs, vbNullChar)<br>
strDir = Left$(strDirs, x - 1)<br>
strDirs = Mid$(strDirs, x + 1)<br>
If Len(Dir$(strDir & strFile)) Then<br>
PathTo = strDir & Dir$(strDir & strFile)<br>
Exit Function<br>
End If<br>
strEntry = Dir$(strDir & &quot;*.*&quot;, vbDirectory)<br>
Do While Len(strEntry)<br>
If (GetAttr(strDir & strEntry) And vbDirectory) Then<br>
If strEntry &lt;&gt; &quot;.&quot; And strEntry &lt;&gt; &quot;..&quot; Then<br>
strDirs = strDirs & strDir & strEntry & &quot;\&quot; & vbNullChar<br>
End If<br>
End If<br>
strEntry = Dir$<br>
Loop<br>
Loop<br>
PathTo = &quot;&quot;<br>
End Function<br>
<br>
<p>Eric De Decker<br><a href=mailto:vbg.be@vbgroup.nl>vbg.be@vbgroup.nl</a><br><a href= Visual Basic Center</a><br>
 
How about using recursion? It's an elegant solution to solving problems that deal with trees! Grab the following class and test code. Enjoy!<br>
<br>
-----&lt;Class Start&gt;-----<br>
Option Explicit<br>
<br>
Private colDirs As Collection<br>
Private colFiles As Collection<br>
<br>
Private sStartDir As String<br>
Private sFileSpec As String<br>
Private bCollSet As Boolean<br>
<br>
Public Function FindFiles()<br>
<br>
Dim i, iFirst, iSecond, iDirCount As Integer<br>
<br>
If sStartDir = &quot;&quot; Then<br>
Err.Raise Number:=5, _<br>
Source:=&quot;FindFile.Directory&quot;, _<br>
Description:=&quot;Directory Property must be supplied.&quot;<br>
End If<br>
If sFileSpec = &quot;&quot; Then<br>
Err.Raise Number:=5, _<br>
Source:=&quot;FindFile.FileSpec&quot;, _<br>
Description:=&quot;File Specification Property must be supplied.&quot;<br>
End If<br>
If bCollSet = False Then<br>
Err.Raise Number:=5, _<br>
Source:=&quot;FindFile.Collection&quot;, _<br>
Description:=&quot;Collection Property must be supplied.&quot;<br>
End If<br>
<br>
RecurseDirs sStartDir, sFileSpec<br>
<br>
While colDirs.Count &gt; 0<br>
iDirCount = colDirs.Count<br>
RecurseDirs colDirs(1), sFileSpec<br>
If colDirs.Count = iDirCount Then<br>
For i = 1 To colDirs.Count<br>
iFirst = CountChar(colDirs(1), &quot;\&quot;)<br>
If colDirs.Count &gt; 1 Then<br>
iSecond = CountChar(colDirs(2), &quot;\&quot;)<br>
Else<br>
iSecond = False<br>
End If<br>
If iFirst &gt; iSecond And iSecond Then<br>
colDirs.Remove 1<br>
End If<br>
Next<br>
colDirs.Remove 1<br>
End If<br>
Wend<br>
<br>
End Function<br>
<br>
Private Sub Class_Initialize()<br>
<br>
Set colDirs = New Collection<br>
Set colFiles = New Collection<br>
<br>
End Sub<br>
<br>
Private Function RecurseDirs(Path, FileSpec)<br>
<br>
Dim sFound As String<br>
Dim sCurrentPath As String<br>
<br>
If Mid$(Path, Len(Path)) &lt;&gt; &quot;\&quot; Then<br>
Path = Path & &quot;\&quot;<br>
End If<br>
<br>
sCurrentPath = CurDir<br>
ChDir Path<br>
<br>
sFound = Dir(Path & FileSpec, vbNormal + vbHidden + vbSystem + vbReadOnly)<br>
While sFound &lt;&gt; &quot;&quot;<br>
colFiles.Add Item:=Path & sFound<br>
sFound = Dir<br>
Wend<br>
<br>
sFound = Dir(Path & &quot;*.*&quot;, vbDirectory + vbNormal + vbHidden + vbSystem + vbReadOnly)<br>
While sFound &lt;&gt; &quot;&quot;<br>
If (Left(sFound, 1) &lt;&gt; &quot;.&quot;) And (GetAttr(Path & sFound) And vbDirectory) Then<br>
If colDirs.Count = 0 Then<br>
colDirs.Add Item:=Path & sFound<br>
Else<br>
colDirs.Add Item:=Path & sFound, Before:=1<br>
End If<br>
End If<br>
sFound = Dir<br>
Wend<br>
<br>
ChDir sCurrentPath<br>
<br>
End Function<br>
<br>
Private Function CountChar(sString As String, sChar As String) As Integer<br>
<br>
Dim iPos As Integer<br>
<br>
iPos = InStr(sString, sChar)<br>
While iPos &lt;&gt; 0<br>
CountChar = CountChar + 1<br>
iPos = InStr(iPos + 1, sString, sChar)<br>
Wend<br>
<br>
End Function<br>
<br>
Public Property Let Directory(sDir As String)<br>
<br>
Dim sTemp As String<br>
Dim iOptions As Integer<br>
<br>
If sDir = &quot;&quot; Then<br>
Err.Raise Number:=5, _<br>
Source:=&quot;FindFile.Directory&quot;, _<br>
Description:=&quot;Directory Property must be supplied.&quot;<br>
Else<br>
sStartDir = sDir<br>
End If<br>
<br>
End Property<br>
<br>
Public Property Let FileSpec(FileSpec As String)<br>
<br>
Dim iOptions As Integer<br>
<br>
If FileSpec = &quot;&quot; Then<br>
Err.Raise Number:=5, _<br>
Source:=&quot;FindFile.FileSpec&quot;, _<br>
Description:=&quot;File Specification Property must be supplied.&quot;<br>
Else<br>
sFileSpec = FileSpec<br>
End If<br>
<br>
End Property<br>
<br>
Public Property Set Collection(vObject As Object)<br>
<br>
Set colFiles = vObject<br>
bCollSet = True<br>
<br>
End Property<br>
<br>
Private Sub Class_Terminate()<br>
Set colDirs = Nothing<br>
Set colFiles = Nothing<br>
End Sub<br>
-----&lt;Class End&gt;-----<br>
<br>
-----&lt;Test Program Start&gt;-----<br>
Option Explicit<br>
<br>
Public Sub Main()<br>
Dim objFile As FileFind<br>
Dim colFiles As Collection<br>
Dim lIndex As Long<br>
<br>
'Create the FileFind Object.<br>
Set objFile = New FileFind<br>
<br>
'Create a collection to hold the list of files it found.<br>
Set colFiles = New Collection<br>
<br>
'Tell it the directory to search.<br>
objFile.Directory = &quot;C:\TEMP&quot;<br>
<br>
'Tell it what to search for.<br>
objFile.FileSpec = &quot;*.exe&quot;<br>
<br>
'Tell it where to put the files that were found.<br>
Set objFile.Collection = colFiles<br>
<br>
'Tell it to get to work!<br>
objFile.FindFiles<br>
<br>
'Display the files it found.<br>
For lIndex = 1 To colFiles.Count<br>
Debug.Print colFiles(lIndex)<br>
Next lIndex<br>
End Sub<br>
-----&lt;Test Program End&gt;-----<br>
<br>
<p>Steve Meier<br><a href=mailto:sdmeier@jcn1.com>sdmeier@jcn1.com</a><br><a href= > </a><br>
 
&nbsp;&nbsp;&nbsp;&nbsp;The following subroutine is more than 100% faster than Microsoft's VB6 &quot;WinSeek&quot; example and uses less than 1/10th the lines of code.<br>&nbsp;&nbsp;&nbsp;&nbsp;Anybody who has tried the &quot;WinSeek&quot; sample project has probably found it's flaws: it is slow and buggy. 17 seconds after I directed it to find all &quot;*.COM&quot; files on my C: drive, it reported &quot;157 files found&quot;. The GetFiles subroutine found 149 files (the same number reported by the Windows &quot;Find Files&quot; feature) and performed the task in less than 7 seconds.<br>&nbsp;&nbsp;&nbsp;&nbsp;Portions of this subroutine would work well in a project requiring multiple searches based on different file types. The first portion retrieves the directory structure and requires about 90% of the operating time (it could be performed once and the results retained globally). The second portion retrieves the file names from the directories stored in the Dirs() array (file searches could require less than a second).<br>&nbsp;&nbsp;&nbsp;&nbsp;Do you see where I am going with this?<br><br>&nbsp;&nbsp;&nbsp;&nbsp;Try:<br>Call GetFiles(&quot;C:&quot;, &quot;*.COM&quot;)<br><br>Private Sub GetFiles(Drive$, FileSpec$)<br>ReDim Dirs(1) As String<br>On Error Resume Next<br>SrchPath = Drive$ + &quot;\&quot;: Dirs(1) = SrchPath<br>FirstDir = 1: LastDir = 1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>'Get the directory structure</b><br>Do<br>&nbsp;&nbsp;&nbsp;&nbsp;For D = FirstDir To LastDir<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SrchName = Dir(Dirs(D), vbDirectory)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Do While SrchName &lt;&gt; &quot;&quot;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;If SrchName &lt;&gt; &quot;.&quot; And SrchName &lt;&gt; &quot;..&quot; Then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;If (GetAttr(Dirs(D) & SrchName) And vbDirectory) = vbDirectory Then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ReDim Preserve Dirs(UBound(Dirs) + 1)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Dirs(UBound(Dirs)) = Dirs(D) & SrchName<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;If Right$(Dirs(UBound(Dirs)), 1) &lt;&gt; &quot;\&quot; Then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Dirs(UBound(Dirs)) = Dirs(UBound(Dirs)) + &quot;\&quot;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;End If<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;End If<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;End If<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SrchName = Dir<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Loop<br>&nbsp;&nbsp;&nbsp;&nbsp;Next<br>&nbsp;&nbsp;&nbsp;&nbsp;FirstDir = LastDir + 1<br>&nbsp;&nbsp;&nbsp;&nbsp;If FirstDir &gt; UBound(Dirs) Then Exit Do<br>&nbsp;&nbsp;&nbsp;&nbsp;LastDir = UBound(Dirs)<br>Loop<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>'Place the filenames in the list box</b><br>For F = 1 To UBound(Dirs)<br>&nbsp;&nbsp;&nbsp;&nbsp;SrchName = Dir(Dirs(F) & FileSpec$, 7)<br>&nbsp;&nbsp;&nbsp;&nbsp;Do While SrchName &lt;&gt; &quot;&quot;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List1.AddItem Dirs(F) & SrchName:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SrchName = Dir<br>&nbsp;&nbsp;&nbsp;&nbsp;Loop<br>Next<br>End Sub<br> <p> <br><a href=mailto: > </a><br><a href= plain black box</a><br>
 
This thread now spans more than a year of posts!! It's a mini time capsule!

I spent about 2 hours trying the various solutions proposed here - with no luck. What I am trying to do is a little different - I know the file name(bookmaster.mdb) I want but don't know the path where it is found(typical of a user install where they can put it where they wanted). I finally wrote the following code which works slick and fast. This uses the filesystemobject and recursion. I thought it might be useful for someone looking for the same functionality as myself - plus help someone learn about filesystemobject and recursion. Personally I have been using the DOS/SHELL routine for years to do something like this - but this is faster and less problematic and even takes less coding.
--------------------------------------------------------

Private Function LookForFile(path As String) As Boolean


Dim fso, f, fc
Dim fld As Folder


Set fso = CreateObject(&quot;Scripting.FileSystemObject&quot;)
Set f = fso.GetFolder(path)
Set fc = f.SubFolders
For Each fld In f.SubFolders
If fso.FileExists(path & &quot;\&quot; & fld.Name & &quot;\bookmaster.mdb&quot;) Then
installPath = path & &quot;\&quot; & fld.Name
LookForFile = True
Exit For
End If
If fld.SubFolders.Count > 1 Then Call LookForFile(path & &quot;\&quot; & fld.Name)
If installPath > &quot; &quot; Then LookForFile = True: Exit Function
Next



End Function
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top