Windows System Programming : File Attributes and Directory Processing

- How To Install Windows Server 2012 On VirtualBox
- How To Bypass Torrent Connection Blocking By Your ISP
- How To Install Actual Facebook App On Kindle Fire
7/28/2011 3:40:18 PM
This section shows how to search a directory for files and other directories that satisfy a specified name pattern and, at the same time, obtain file attributes. Searches require a search handle provided by FindFirstFile. Obtain specific files with FindNextFile, and terminate the search with FindClose. There is also an extended version, FindFirstFileEx, which has more search options, such as allowing for case sensitivity. An exercise suggests exploring the extended function.

HANDLE FindFirstFile (
LPCTSTR lpFileName,

Return: A search handle. INVALID_HANDLE_VALUE indicates failure.

FindFirstFile examines both subdirectory and file names, looking for a name match. The returned HANDLE is for use in subsequent searches. Note that it is not a kernel handle.


lpFileName points to a directory or pathname that can contain wildcard characters (? and *). Search for a single specific file by omitting wildcard characters.

lpffd points to a WIN32_FIND_DATA structure (the “WIN32” part of the name is misleading, as this can be used on 64-bit computers) that contains information about the first file or directory to satisfy the search criteria, if any are found.

WIN32_FIND_DATA has the following structure:

typedef struct_WIN32_FIND_DATA {
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD dwReserved0;
DWORD dwReserved1;
TCHAR cAlternateFileName[14];

Test dwFileAttributes for the values described with CreateFile along with some additional values, such as FILE_ATTRIBUTE_SPARSE_FILE and FILE_ATTRIBUTE_ENCRYPTED, which CreateFile does not set. The three file times (creation, last access, and last write) are described in an upcoming section. The file size fields, giving the current file length, are self-explanatory. cFileName is not the pathname; it is the file name by itself. cAlternateFileName is the DOS 8.3 (including the period) version of the file name; this information is rarely used and is appropriate only to determine how a file would be named on an old FAT16 file system.

Frequently, the requirement is to scan a directory for files that satisfy a name pattern containing ? and * wildcard characters. To do this, use the search handle obtained from FindFirstFile, which retains information about the search name, and call FindNextFile.

BOOL FindNextFile (
HANDLE hFindFile,

FindNextFile will return FALSE in case of invalid arguments or if no more matching files are found, in which case GetLastError will return ERROR_NO_MORE_FILES.

When the search is complete, close the search handle. Do not use CloseHandle. Closing a search handle will cause an exception. Instead, use the following:

BOOL FindClose (HANDLE hFindFile)

The function GetFileInformationByHandle obtains the same information for a specific file, specified by an open file handle. It also returns a field, nNumberOfLinks, which indicates the number of hard links set by CreateHardLink; this value is one when the file is first created, is increased by one for each CreateHardLink call targeting the file, and is decreased by one when either a hard link name or the original name is deleted.

The FindNextFile method of wildcard expansion is necessary even in programs executed from the MS-DOS prompt because the DOS shell does not expand wildcards.


You can obtain a file’s full pathname using GetFullPathName. GetShortPathName returns the name in DOS 8.3 format, assuming that the volume supports short names.

NT 5.1 introduced SetFileShortName, which allows you to change the existing short name of a file or directory. This can be convenient because the existing short names are often difficult to interpret.

Other Methods of Obtaining File and Directory Attributes

The FindFirstFile and FindNextFile functions can obtain the following file attribute information: attribute flags, three time stamps, and file size. There are several other related functions, including one to set attributes, and they can deal directly with the open file handle rather than scan a directory or use a file name. Three such functions, GetFileSize, GetFileSizeEx, and SetEndOfFile.

Distinct functions are used to obtain the other attributes. For example, to obtain the time stamps of an open file, use the GetFileTime function.

BOOL GetFileTime (
LPFILETIME lpftCreation,
LPFILETIME lpftLastAccess,
LPFILETIME lpftLastWrite)

The file times here and in the WIN32_FIND_DATA structure are 64-bit unsigned integers giving elapsed 100-nanosecond units (107 units per second) from a base time (January 1, 1601), expressed as Universal Coordinated Time (UTC).[4] There are several convenient functions for dealing with times.

[4] Do not, however, expect to get 100-nanosecond precision; precision will vary depending on hardware characteristics.

  • FileTimeToSystemTime (not described here; see MSDN or Program 1) breaks the file time into individual units ranging from years down to seconds and milliseconds. These units are suitable, for example, when displaying or printing times.

    Program 1. lsW: File Listing and Directory Traversal
    /* lsW [options] [files] */

    #include "Everything.h"

    BOOL TraverseDirectory(LPCTSTR, DWORD, LPBOOL);

    int _tmain(int argc, LPTSTR argv[])
    BOOL flags[MAX_OPTIONS], ok = TRUE;
    TCHAR pathName[MAX_PATH + 1], currPath[MAX_PATH + 1];
    LPTSTR pSlash, pFileName;
    int i, fileIndex;

    fileIndex = Options(
    argc, argv, _T("Rl"), &flags[0], &flags[1], NULL);

    /* "Parse" the search pattern into "parent" and file name. */
    GetCurrentDirectory(MAX_PATH, currPath); /* Save current path. */
    if (argc < fileIndex + 1)
    ok = TraverseDirectory(_T("*"), MAX_OPTIONS, flags);
    else for (i = fileIndex; i < argc; i++) {
    _tcscpy(pathName, argv[i]);
    _tcscpy(tempPath, argv[i]);

    /* Find the rightmost slash, if any.
    Set the path and use the rest as the file name. */
    pSlash = _tstrrchr(tempPath, '\\');
    if (pSlash != NULL) {
    *pSlash = '\0';
    _tcscat(tempPath, _T("\\"));
    SetCurrentDirectory(tempPath); /* Now restore pathName. */
    pSlash = _tstrrchr(pathName, '\\');
    pFileName = pSlash + 1;
    } else pFileName = pathName;
    ok = TraverseDirectory(pFileName, MAX_OPTIONS, flags) && ok;
    SetCurrentDirectory(currPath); /* Restore working directory. */

    static BOOL TraverseDirectory(LPCTSTR pathName, DWORD numFlags,
    LPBOOL flags)

    /* Traverse a directory; perform ProcessItem for every match. */
    /* pathName: Relative or absolute pathname to traverse. */
    HANDLE searchHandle;
    WIN32_FIND_DATA findData;
    BOOL recursive = flags[0];
    DWORD fType, iPass;
    TCHAR currPath[MAX_PATH + 1];

    GetCurrentDirectory(MAX_PATH, currPath);

    for (iPass = 1; iPass <= 2; iPass++) {
    /* Pass 1: List files. */
    /* Pass 2: Traverse directories (if -R specified). */
    searchHandle = FindFirstFile(pathName, &findData);
    do {
    fType = FileType(&findData); /* File or directory? */
    if (iPass == 1) /* List name and attributes. */
    ProcessItem(&findData, MAX_OPTIONS, flags);
    if (fType == TYPE_DIR && iPass == 2 && recursive) {
    /* Process a subdirectory. */
    _tprintf(_T("\n%s\\%s:"), currPath, findData.cFileName);
    /* Prepare to traverse a directory. */
    TraverseDirectory(_T("*"), numFlags, flags);
    } while (FindNextFile(searchHandle, &findData));
    return TRUE;

    static BOOL ProcessItem(LPWIN32_FIND_DATA pFileData,
    DWORD numFlags, LPBOOL flags)
    /* List file or directory attributes. */
    const TCHAR fileTypeChar[] = {' ', 'd'};
    DWORD fType = FileType(pFileData);
    BOOL Long = flags[1];
    SYSTEMTIME lastWrite;

    if (fType != TYPE_FILE && fType != TYPE_DIR) return FALSE;

    if (Long) { /* Was "-1" option used on the command line? */
    _tprintf(_T("%c"), fileTypeChar[fType - 1]);
    _tprintf(_T("%10d"), pFileData->nFileSizeLow);
    _tprintf(_T(" %02d/%02d/%04d %02d:%02d:%02d"),
    lastWrite.wMonth, lastWrite.wDay,
    lastWrite.wYear, lastWrite.wHour,
    lastWrite.wMinute, lastWrite.wSecond);
    _tprintf(_T(" %s"), pFileData->cFileName);
    return TRUE;

    static DWORD FileType(LPWIN32_FIND_DATA pFileData)
    /* Types supported - TYPE_FILE: file; TYPE_DIR: directory;
    TYPE_DOT: . or .. directory */
    BOOL isDir;
    DWORD fType;
    fType = TYPE_FILE;
    isDir = (pFileData->dwFileAttributes &
    if (isDir)
    if (lstrcmp(pFileData->cFileName, _T(".")) == 0
    || lstrcmp(pFileData->cFileName, _T("..")) == 0)
    fType = TYPE_DOT;
    else fType = TYPE_DIR;
    return fType;

  • SystemTimeToFileTime reverses the process, converting time expressed in these individual units to a file time.

  • CompareFileTime determines whether one file time is less than (–1), equal to (0), or greater than (+1) another.

  • Change the time stamps with SetFileTime; use NULL for times that are not to be changed. NTFS supports all three file times, but the FAT gives an accurate result only for the last access time.

  • FileTimeToLocalFileTime and LocalFileTimeToFileTime convert between UTC and the local time.

GetFileType, not described in detail here, distinguishes among disk files, character files (actually, devices such as printers and consoles), and pipes . The file, again, is specified with a handle.

The function GetFileAttributes uses the file or directory name, and it returns just the dwFileAttributes information.

DWORD GetFileAttributes (LPCTSTR lpFileName)

Return: The file attributes, or INVALID_FILE_ATTRIBUTES in case of failure.

The attributes can be tested for appropriate combinations of several mask values. Some attributes, such as the temporary file attribute, are originally set with CreateFile. The attribute values include the following:





Be certain to test the return value for failure (INVALID_FILE_ATTRIBUTES, which is 0xFFFFFFFF) before trying to determine the attributes. This value would make it appear as if all values were set.

The function SetFileAttributes changes these attributes in a named file.

opendir, readdir, and closedir in UNIX correspond to the three Find functions. The function stat obtains file size and times, in addition to owning user and group information that relates to UNIX security. fstat and lstat are variations. These functions can also obtain type information. utime sets file times in UNIX. There is no UNIX equivalent to the temporary file attribute.

Temporary File Names

The next function creates names for temporary files. The name can be in any specified directory and must be unique.

GetTempFileName gives a unique file name, with the .tmp suffix, in a specified directory and optionally creates the file.

UINT GetTempFileName (
LPCTSTR lpPathName,
LPCTSTR lpPrefixString,
UINT uUnique,
LPTSTR lpTempFileName)

Return: A unique numeric value used to create the file name. This will be uUnique if uUnique is nonzero. On failure, the return value is zero.


lpPathName is the directory for the temporary file. “.” is a typical value specifying the current directory. Alternatively, use GetTempPath, a Windows function not described here, to give the name of a directory dedicated to temporary files.

lpPrefixString is the prefix of the temporary name. You can only use 8-bit ASCII characters. uUnique is normally zero so that the function will generate a unique four-digit suffix and will create the file. If this value is nonzero, the file is not created; do that with CreateFile, possibly using FILE_FLAG_DELETE_ON_CLOSE.

lpTempFileName points to the buffer that receives the temporary file name. The buffer’s byte length should be at least the same value as MAX_PATH. The resulting pathname is a concatenation of the path, the prefix, the four-digit hex number, and the .tmp suffix.

  •  Windows System Programming : File Pointers & Getting the File Size
  •  SharePoint 2010 : Business Intelligence - Excel Services (part 2) - Accessing Excel Services Over SOAP
  •  SharePoint 2010 : Business Intelligence - Excel Services (part 1) - Accessing Excel Services Over REST
  •  SharePoint 2010 : Business Intelligence - Visio Services
  •  Exchange Server 2010 : Perform Essential Database Management (part 3) - Manage Database Settings
  •  Exchange Server 2010 : Perform Essential Database Management (part 2) - Manage the Transaction Log Files
  •  Exchange Server 2010 : Perform Essential Database Management (part 1) - Manage the Database Files
  •  Architecting Applications for the Enterprise : UML Diagrams (part 3) - Sequence Diagrams
  •  Architecting Applications for the Enterprise : UML Diagrams (part 2) - Class Diagrams
  •  Architecting Applications for the Enterprise : UML Diagrams (part 1) - Use-Case Diagrams
    Top 10
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
    - Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
    - Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
    - Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
    - Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
    - Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
    - Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
    - First look: Apple Watch

    - 3 Tips for Maintaining Your Cell Phone Battery (part 1)

    - 3 Tips for Maintaining Your Cell Phone Battery (part 2)
    programming4us programming4us