Computer Programming Tutorials Navigation

 
Web ask-4it.com
look-4it.com try-2-find.com

How To Use FindFirstFile Win32 API From Visual Basic Code


by Sergey Popov

Download Visual Basic code for this article here: visual-basic-findfirstfile-win32-api.zip

Who should read this article?

This article is intended for advanced Visual Basic programmers. It may be interesting for programmers studying Visual Basic programming language as well.

Prerequisites

You will need a basic knowledge of the Visual Basic programming language and Win32 API. You need Microsoft Visual Basic 6.0 development environment installed at your computer.

What the difference between FindFirstFile Win32 API function and Dir Visual Basic function?

Both functions search a directory for a file whose name matches the specified pattern, but input parameters, results and using are quite different.

The Dir Visual Basic function input parameters:

  1. pathname optional parameter with the file name pattern
  2. attributes optional parameter with the file attribute pattern

The Dir function returns a String value representing the name of file or directory that matches file name and/or file attribute patterns.

If you decide to list all files in the some directory and specify the file name pattern, then you need to call the Dir function without parameters until it will return empty string.

The FindFirstFile Win32 API function input parameters:

  1. lpFileName - the same as pathname parameter of the Dir function
  2. lpFindFileData - pointer to the buffer that receives information about the found file or subdirectory. WIN32_FIND_DATA structure should be used as buffer.

The FindFirstFile function returns a Long value representing a search handle, if the function succeeds, or INVALID_HANDLE_VALUE, if the function fails.

You need to call the FindNextFile Win32 API function with returned search handle subsequently, if you want to list all files in the directory. You must close the search handle by using the FindClose function when it is no longer needed.

One more distinctive feature: according to my tests, FindFirstFile/FindNextFile Win32 API functions work twice as faster then the Dir Visual Basic function.

The FindFirstFile Win32 API function output

Lets review output of the FindNextFile Win32 API function more closely. It populates the WIN32_FIND_DATA structure if some file was found.

Here is the definition of this structure:

typedef struct _WIN32_FIND_DATA
{
	DWORD    dwFileAttributes;
	FILETIME ftCreationTime;
	FILETIME ftLastAccessTime;
	FILETIME ftLastWriteTime;
	DWORD    nFileSizeHigh;
	DWORD    nFileSizeLow;
	DWORD    dwReserved0;
	DWORD    dwReserved1;
	TCHAR    cFileName[MAX_PATH];
	TCHAR    cAlternateFileName[14];
} WIN32_FIND_DATA, *PWIN32_FIND_DATA;

We obtain the following extended file info:

  1. dwFileAttributes - file attributes
  2. ftCreationTime - structure that specifies when the file was created
  3. ftLastAccessTime - structure that specifies when the file was last read from or written to
  4. ftLastWriteTime - structure that specifies when the file was last written to
  5. nFileSizeHigh, nFileSizeLow - file size, in bytes
  6. cFileName - null-terminated string that is the name of the file
  7. cAlternateFileName - null-terminated string that is an alternative name for the file in the classic 8.3 format

As you can see, we can get all this information by one function call only. We don't need to call GetAttr, FileLen or FileDateTime Visual Basic functions separately. It's a quite big saving of time.

Using of the FindFirstFile Win32 API from Visual Basic code

We need the following declarations in our Visual Basic code:

The FindFirstFile Win32 API function, which creates a search handle and obtains first file info

Declare Function FindFirstFile Lib "kernel32" Alias "FindFirstFileA" _
	(ByVal lpFileName As String, lpFindFileData As WIN32_FIND_DATA) As Long

The FindNextFile Win32 API function, which continues a file search from a previous call to the FindFirstFile function

Declare Function FindNextFile Lib "kernel32" Alias "FindNextFileA" _
	(ByVal hFindFile As Long, lpFindFileData As WIN32_FIND_DATA) As Long

The FindClose Win32 API function, which closes the search handle created by the FindFirstFile function

Declare Function FindClose Lib "kernel32" (ByVal hFindFile As Long) As Long

The WIN32_FIND_DATA structure that we need to receive the FindFirstFile and the FindNextFile functions output

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
	cAlternateFileName As String * 14
End Type

The INVALID_HANDLE_VALUE is return value, which indicates that the FindFirstFile function failed

Const INVALID_HANDLE_VALUE As Long = -1

File name is limited to MAX_PATH characters

Const MAX_PATH As Integer = 260

The FILETIME structure is a 64-bit value representing UTC-based date and time of file

Type FILETIME
    dwLowDateTime As Long
    dwHighDateTime As Long
End Type

You may notice two disadvantages of the WIN32_FIND_DATA structure from the point of view of Visual Basic programming:

  1. cFileName and cAlternateFileName fields are fixed-length null-terminated strings. So we need TrimNull function, which will extract actual file name from such strings.
  2. All file dates are packed in the FILETIME structures. Therefore, we need some additional FileTimeToDate function to convert them to the VB Date format.

Here is source code for the TrimNull function:

Function TrimNull(sFileName As String) As String
	Dim i As Long
	' Search for the first null character
	i = InStr(1, sFileName, vbNullChar)
	If i = 0 Then
		TrimNull = sFileName
	Else
		' Return the file name
		TrimNull = Left$(sFileName, i - 1)
	End If
End Function

I think this function is quite simple and doesn't require additional comments.

Now lets implement the FileTimeToDate conversion function. We need two additional Win32 API functions to accomplish this task.

The FILETIME structure contains UTC-based file date and time. Therefore, we need to convert it to the local time according to the current settings for the time zone and daylight saving time.

The FileTimeToLocalFileTime function converts a file time to a local file time

Declare Function FileTimeToLocalFileTime Lib "kernel32" _
	(lpFileTime As FILETIME, lpLocalFileTime As FILETIME) As Long

The FileTimeToSystemTime function converts a file time to system time format. It populates the SYSTEMTIME structure, which can be easily used to create Visual Basic Date value.

Declare Function FileTimeToSystemTime Lib "kernel32" _
	(lpFileTime As FILETIME, lpSystemTime As SYSTEMTIME) As Long

Here is the SYSTEMTIME structure, which represents date and time

Type SYSTEMTIME
	wYear As Integer
	wMonth As Integer
	wDayOfWeek As Integer
	wDay As Integer
	wHour As Integer
	wMinute As Integer
	wSecond As Integer
	wMilliseconds As Integer
End Type

The FileTimeToDate function gets UTC-based file date and time packed in the FILETIME structure and converts it to the Visual Basic Date value.

Function FileTimeToDate(lpFileTime As FILETIME) As Date
	Dim lpLocalFileTime As FILETIME
	Dim lpSystemTime As SYSTEMTIME
	Dim dResult As Date
	dResult = Empty
	' Convert from UTC-based to the local file time
	If FileTimeToLocalFileTime(lpFileTime, lpLocalFileTime) Then
		' Unpack FILETIME structure to SYSTEMTIME structure
		If FileTimeToSystemTime(lpLocalFileTime, lpSystemTime) Then
			' Create Visual Basic Date value
			dResult = DateSerial(lpSystemTime.wYear, _
				lpSystemTime.wMonth, lpSystemTime.wDay) _
				+ TimeSerial(lpSystemTime.wHour, _
				lpSystemTime.wMinute, lpSystemTime.wSecond)
		End If
	End If
	FileTimeToDate = dResult
End Function

We have used DateSerial and TimeSerial standard Visual Basic functions to create resulting Date value.

Finally lets review code sample. This code populates txtResult textbox with the list of all files from the location specified in the txtPath textbox. Please note that correct pattern should be specified in the txtPath textbox, i.e. "C:*.*", but not "C:".

' Buffer for output result
Dim sBuff As String
' File search handle
Dim iSearchHandle As Long
' File search buffer
Dim pFindFileBuff As WIN32_FIND_DATA
sBuff = vbNullString
' Find first file and create search handle
iSearchHandle = FindFirstFile(Me.txtPath.Text, pFindFileBuff)
' Check if FindFirstFile call was successful
If iSearchHandle <> INVALID_HANDLE_VALUE Then
	' Store first file name and date in the buffer
	sBuff = TrimNull(pFindFileBuff.cFileName) & " " _
	& CStr(FileTimeToDate(pFindFileBuff.ftLastWriteTime)) & vbCrLf
	' Find the rest of files with the FindNextFile function
	Do While FindNextFile(iSearchHandle, pFindFileBuff)
		sBuff = sBuff & TrimNull(pFindFileBuff.cFileName) & " " _
		& CStr(FileTimeToDate(pFindFileBuff.ftLastWriteTime)) & vbCrLf
	Loop
	' Close file search handle
	Call FindClose(iSearchHandle)
End If
' Show results
Me.txtResult.Text = sBuff

As you can see we have utilized all information reviewed above in this small Visual Basic sample. Feel free to download and run full source code.

How to use sample Visual Basic code

Here are some recommendations on how to use sample Visual Basic code:

  1. Unpack visual-basic-findfirstfile-win32-api.zip into a single folder on your computer.
  2. Run compiled executable Project1.exe. It doesn't require any additional DLLs except Visual Basic run-time.
  3. Or load Project1.vbp in your Visual Basic development environment to view sample sources.



Back to article category: Development Tasks

Related Information



Related Searches



Additional Development Tasks Articles

How to create custom progress bar using Visual Basic
Tutorial describes how to create lightweight customizable progress bar for your Visual Basic applications.




 
Web ask-4it.com
look-4it.com try-2-find.com






Home  |  Tools  |  Downloads  |  RSS Feed  |  Link to Us  |  Contact Us  |  Privacy Policy  |  Terms of Use

Copyright © 2005, ASK-4IT.COM. All Rights Reserved.

All trademarks, icons, and logos, shown or mentioned at this web site, are the property of their respective owners.