35 out of 155 rated this helpful Rate this topic

FindFirstFile function

Searches a directory for a file or subdirectory with a name that matches a specific name (or partial name if wildcards are used).

To specify additional attributes to use in a search, use the FindFirstFileEx function.

To perform this operation as a transacted operation, use the FindFirstFileTransacted function.

Syntax

HANDLE WINAPI FindFirstFile(
  __in   LPCTSTR lpFileName,
  __out  LPWIN32_FIND_DATA lpFindFileData
);

Parameters

lpFileName [in]

The directory or path, and the file name, which can include wildcard characters, for example, an asterisk (*) or a question mark (?).

This parameter should not be NULL, an invalid string (for example, an empty string or a string that is missing the terminating null character), or end in a trailing backslash (\).

If the string ends with a wildcard, period (.), or directory name, the user must have access permissions to the root and all subdirectories on the path.

In the ANSI version of this function, the name is limited to MAX_PATH characters. To extend this limit to 32,767 widecharacters, call the Unicode version of the function and prepend "\\?\" to the path. For more information, see Naming a File.

lpFindFileData [out]

A pointer to the WIN32_FIND_DATA structure that receives information about a found file or directory.

Return value

If the function succeeds, the return value is a search handle used in a subsequent call to FindNextFile or FindClose, and the lpFindFileData parameter contains information about the first file or directory found.

If the function fails or fails to locate files from the search string in the lpFileName parameter, the return value is INVALID_HANDLE_VALUE and the contents of lpFindFileData are indeterminate. To get extended error information, call the GetLastError function.

If the function fails because no matching files can be found, the GetLastError function returns ERROR_FILE_NOT_FOUND.

Remarks

The FindFirstFile function opens a search handle and returns information about the first file that the file system finds with a name that matches the specified pattern. This may or may not be the first file or directory that appears in a directory-listing application (such as the dir command) when given the same file name string pattern. This is because FindFirstFile does no sorting of the search results. For additional information, see FindNextFile.

The following list identifies some other search characteristics:

  • The search is performed strictly on the name of the file, not on any attributes such as a date or a file type (for other options, see FindFirstFileEx).
  • The search includes the long and short file names.
  • An attempt to open a search with a trailing backslash always fails.
  • Passing an invalid string, NULL, or empty string for the lpFileName parameter is not a valid use of this function. Results in this case are undefined.

Note  In rare cases, file information on NTFS file systems may not be current at the time you call this function. To be assured of getting the current file information, call the GetFileInformationByHandle function.

After the search handle is established, you can use it to search for other files that match the same pattern by using the FindNextFile function.

When the search handle is no longer needed, close it by using the FindClose function, not CloseHandle.

As stated previously, you cannot use a trailing backslash (\) in the lpFileName input string for FindFirstFile, therefore it may not be obvious how to search root directories. If you want to see files or get the attributes of a root directory, the following options would apply:

  • To examine files in a root directory, you can use "C:\*" and step through the directory by using FindNextFile.
  • To get the attributes of a root directory, use the GetFileAttributes function.

Note  Prepending the string "\\?\" does not allow access to the root directory.

On network shares, you can use an lpFileName in the form of the following: "\\server\service\*". However, you cannot use an lpFileName that points to the share itself; for example, "\\server\service" is not valid.

To examine a directory that is not a root directory, use the path to that directory, without a trailing backslash. For example, an argument of "C:\Windows" returns information about the directory "C:\Windows", not about a directory or file in "C:\Windows". To examine the files and directories in "C:\Windows", use an lpFileName of "C:\Windows\*".

Be aware that some other thread or process could create or delete a file with this name between the time you query for the result and the time you act on the information. If this is a potential concern for your application, one possible solution is to use the CreateFile function with CREATE_NEW (which fails if the file exists) or OPEN_EXISTING (which fails if the file does not exist).

If you are writing a 32-bit application to list all the files in a directory and the application may be run on a 64-bit computer, you should call the Wow64DisableWow64FsRedirectionfunction before calling FindFirstFile and call Wow64RevertWow64FsRedirection after the last call to FindNextFile. For more information, see File System Redirector.

If the path points to a symbolic link, the WIN32_FIND_DATA buffer contains information about the symbolic link, not the target.

Examples

The following C++ example shows you a minimal use of FindFirstFile.


#include <windows.h>
#include <tchar.h>
#include <stdio.h>

void _tmain(int argc, TCHAR *argv[])
{
   WIN32_FIND_DATA FindFileData;
   HANDLE hFind;

   if( argc != 2 )
   {
      _tprintf(TEXT("Usage: %s [target_file]\n"), argv[0]);
      return;
   }

   _tprintf (TEXT("Target file is %s\n"), argv[1]);
   hFind = FindFirstFile(argv[1], &FindFileData);
   if (hFind == INVALID_HANDLE_VALUE) 
   {
      printf ("FindFirstFile failed (%d)\n", GetLastError());
      return;
   } 
   else 
   {
      _tprintf (TEXT("The first file found is %s\n"), 
                FindFileData.cFileName);
      FindClose(hFind);
   }
}


For another example, see Listing the Files in a Directory.

Requirements

Minimum supported client

Windows XP

Minimum supported server

Windows Server 2003

Header

WinBase.h (include Windows.h)

Library

Kernel32.lib

DLL

Kernel32.dll

Unicode and ANSI names

FindFirstFileW (Unicode) and FindFirstFileA (ANSI)

See also

File Management Functions
FindClose
FindFirstFileEx
FindFirstFileTransacted
FindNextFile
GetFileAttributes
SetFileAttributes
Symbolic Links
Using the Windows Headers
WIN32_FIND_DATA

 

 

Send comments about this topic to Microsoft

Build date: 9/10/2011

Did you find this helpful?
(2000 characters remaining)
Community Content Add
Annotations FAQ
Beware of the ? wildcard
You should be aware that ? wildcard character matches zero or one character. Microsoft's documention is either ambigous or wrong on this point in several places. (The confusion extends to Microsoft's own developers. Look in the Visual C runtime source code, in file wild.c, where it says that '?' matches exactly one character)

Likewise, "??" matches zero, one or two characters. "???" matches zero, one, two or three, and so on.

All Windows command line tools exhibit the same behavior because they end up calling FindFirstFile() to do wildcard expansion.

The consequences are important. For example, the command line "del *.?" will delete "file" as well as "file.a"
FindFirstFile caching behavior over SMB 2.0

If you use FindFirstFile on network shares, then you should be aware of this significant caveat on Vista+/Server2008+ (which use SMB 2.0)

This is a quote from the Windows SDK team blog:
http://blogs.msdn.com/b/winsdk/archive/2009/07/10/file-exists-access-getfileattributes-findfirstfile-findnextfile-stat-behavior-over-smb-2-0.aspx

"When an application on client creates a file on a shared directory on server or application on server creates a file on shared directory on server, and file is created successfully but when the application on client try to check the existence of the recently created file by _access or other method, it reports that the file does not exists. This behavior is observed when SMB 2.0 is used.SMB 2.0 was introduced on Windows Vista and Windows Server 2008. The file does exists about after 20 seconds."

Be aware of reparse points
Be aware of reparse points when recursively enumerating directories. Otherwise you may get weird results, such as infinite loops, when you enumerate a directory such as C:\Users\All Users\Application Data (which is a reparse point, that points to its parent directory) and you see "Application Data" again in the results, so you enter it again... $0$0 $0 $0You may also see directories that you have no permission to enter, and weirdly, enumerating them will enumerate the parent directory instead.$0 $0$0 $0 $0http://social.msdn.microsoft.com/forums/en-US/windowscompatibility/thread/05d14368-25dd-41c8-bdba-5590bf762a68/$0
C#
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
        public struct WIN32_FIND_DATA
        {
            public uint dwFileAttributes;
            public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
            public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
            public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
            public uint nFileSizeHigh;
            public uint nFileSizeLow;
            public uint dwReserved0;
            public uint dwReserved1;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst=260)]
            public string cFileName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst=14)]
            public string cAlternateFileName;
        }

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);
On casting the return value to a 32 bit value on 64 bit operating systems

The return value for this function is a HANDLE. A handle is a typedef of void*. This is a 64 bit value on 64 bit versions of Windows. There is no documented range of values for what you could possibly get returned, so it is safe to assume that this can return a 64 bit value. For safety, the return value should only be stored in a variable of type HANDLE anyway.

Is it safe to assign return value to 32-bit variable in 64-bit app?

If this function is used in 64-bit app is the guaranty
that return handle can be safely casted to the 32-bit?

Matches On Long *And* Short Filename
If FindFirstFile/FindNextFile return files whose name doesn't seem to match the mask you provided, it's probably because the 8.3-version of the filename is also checked.

For example, in a particular directory on my machine, the file .\SSL_set_connect_state.pod matches when using the mask "SS7*". Running DIR /X reveals this file is also known as SS7177~1.POD, and therefore the match is appropriate.

The DIR command operates the same way (given the same mask). I assume DIR uses FindFirstFile/FindNextFile or something equivalent internally.

Harry.
get FindFirstFile handle to work with ReadFile
hi,
can we use the returned handle from FindFirstFile for ReadFile
whenever i try to do that ReadFile returns ERROR_INVALID_HANDLE
or can we copy the found file position to pass it to SetFilePointer ?
Stale information
The documentation says:
Note In rare cases, file information on NTFS file systems may not be current at the time you call this function. To be assured of getting the current file information, call the GetFileInformationByHandle function.

What are are the cases when the function returns stale data?
Filesystem Redirection
The article advises that filesystem redirection for 32-bit applications should be disabled when running in 64-bit environments; however it is not made apparent why this is necessary or what the expected behaviour is to be if it is not disabled (undefined?). Can we add more detail here?

[Conrad] The link in the article actually does explain what redirection does, basically if you do not disable redirection, the returned files you list through this API will not match what a user sees in Windows Explorer which is a 64-bit app, causing confusion. Always turn redirection on again afterwards!
Unicode settings are important
It took me a while to figure out why this function was failing and GetLastError() kept returning code 2 - file not found when using a known good path and file name.

It turns out that unicode compile settings were turned on. This caused the function to get the input file path (lpFileName) in the incorrect format.

Delete files whilst searching
Is it safe to delete the files resulting from the search whilst searching? Or will that cause problems with the iteration?
Wrappers I found useful
Found VB wrapper: http://vb.mvps.org/hardcore/html/usingfileinformationwrapperclass.htm
and C++ wrapper: http://www.geocities.com/krishnapg/FileEnumerator.html
.Net wrapper: http://www.codeproject.com/KB/files/FileSystemEnumerator.aspx
FindFirstFile - Guidelines for Error-Handling

It is worth noting that it is important to check the return value of GetLastError(). All examples I found in a brief search on the Web simply check for FindFirstFile returning INVALID_HANDLE_VALUE and assume the file was not found. In this has happened, GetLastError() will return ERROR_FILE_NOT_FOUND. If any other return value occurs, it will indicate some other error - the file path passed in may be invalid for some reason, it may have been impossible to connect to a network drive, etc.

(I personally wish more MSDN articles listed common (or at least anticipated) error codes, rather than the ubiquitous "To get extended error information call GetLastError" - this may encourage developers to handle those cases robustly).

[MSFT] - this topic is being updated to make this clearer.

Bug?!
The characters of '<' and '>' are treated like wildcard by this function.

[MSFT] - these are listed in the Naming A File topic as illegal characters in path and file names. That topic is being updated to make this clearer.
FindFirstFile, FindNextFile side-effects

GetFileVersionInfoSize() on the results of FindFirstFile() will fail, but it will work for the following results returned by FindNextFile().

This happens when FindFirstFile("c:\windows\*.dll") and my current directory is not c:\windows.

The current directory is unchanged after FindNextFile(), but GetFileVersionInfoSize("twain_32.dll") suceeds, even though it does not contain the full path.

Solution was to SetCurrentDirectory() between FindFirstFile and FindNextFile() and hope the user does not enter a "*" in the path portion of the argument...