• home
  • forum
  • my
  • kt
  • download
  • How to use FindFirstFile Win32 API from Visual Basic code

    Author: 2007-09-05 17:40:48 From:

    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.

    discuss this topic to forum

    relation tutorial

    No relevant information

    Category

      .NET (8)
      Buttons (3)
      Database Related (7)
      Date and Time (1)
      Development (3)
      Error Handling (2)
      File Manipulation (5)
      Introduction to Visual Basic (9)
      Miscellaneous (2)
      Multimedia (9)
      Networking (9)
      Security (1)
      VB Script (6)

    New

    Hot