A quick reference for using the Windows-specific windows.h / fileapi.h library to do more with files than the C++ standard library offers.
Windows exposes a large library of OS-specific functions via windows.h. This page covers examples using the fileapi.h subset — so this is just the file-handling slice of a much larger library.
Several functions expect or return a HANDLE. A HANDLE is a generic container — it can represent almost anything. What matters is how it's used. One advantage: since HANDLE is a base object type, you can mix objects of different types that inherit from it in the same container.
DWORD stands for Double-Word. A Word is 16 bits (vs. 8 bits for a Byte). A DWORD maps to an unsigned long in C++ — just with a different name.
8 bit = BYTE
16 bit = WORD
32 bit = DWORD (Double-word)
64 bit = QWORD (Quad-word)
An unsigned long / DWORD holds 32 bits — values from 0 to ~4.2 billion.
WIN32_FIND_DATA is defined in Winbase.h and is a struct that provides easy access to file properties:
typedef struct _WIN32_FIND_DATA {
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD dwOID;
TCHAR cFileName[MAX_PATH];
} WIN32_FIND_DATA;
See: https://msdn.microsoft.com/en-us/library/ms915521.aspx
A pointer to a 16-bit Unicode string. LPCWSTR = Long Pointer to Constant Wide String — referencing a wchar_t (16-bit wide char instead of the 8-bit char). To assign a string literal directly:
LPCWSTR myWideStr = L'this is my string';
See: https://msdn.microsoft.com/en-us/library/cc230352.aspx
Lets 32-bit systems work with 64-bit integers. Accessible via .LowPart and .HighPart, splitting the data into 2 × 32 bits.
Note: OpenFile is deprecated — Microsoft recommends CreateFile. The two actions below (find vs. open) are independent of each other.
#include <iostream>
#include <string>
#include <Windows.h>
using namespace std;
int main()
{
WIN32_FIND_DATA filedata;
size_t length_of_arg;
HANDLE fileHandle = INVALID_HANDLE_VALUE;
DWORD dwerror = 0; // unsigned long
LPCWSTR wPfad = L"c:\test\test.txt"; // L prefix converts to wide string (wchar_t)
LPCSTR pfad = "c:\test\test.txt";
// 1. Find file and assign handle
fileHandle = FindFirstFile(wPfad, &filedata);
// If no file was found, return.
if (INVALID_HANDLE_VALUE == fileHandle)
{
cout << "File not found." << endl;
return 0;
}
else {
cout << "File found. We can access it.";
}
// 2. Open file for reading/writing
fileHandle = CreateFileA(pfad, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
CloseHandle(fileHandle); // always close an opened file handle
return 0;
}
See also: CreateFileA documentation
This example also handles file sizes > 4 GB (64-bit safe).
#include <iostream>
#include <string>
#include <Windows.h>
using namespace std;
int main()
{
WIN32_FIND_DATA filedata;
size_t length_of_arg;
HANDLE fileHandle = INVALID_HANDLE_VALUE;
LARGE_INTEGER filesize;
ULONGLONG filesizelong;
DWORD dwerror = 0; // unsigned long
wstring strPfad = L"c:\test";
LPCWSTR pfad = L"c:\test";
// Find file/folder and return pointer to filedata struct
fileHandle = FindFirstFile(pfad, &filedata);
if (filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
cout << "This is a folder. Scanning it now." << endl;
// Append backslash and wildcard
strPfad.append(L"\*");
pfad = strPfad.c_str();
fileHandle = FindFirstFile(pfad, &filedata);
do
{
if (filedata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
cout << ".DIR" << endl;
}
else
{
wcout << "Filename: " << filedata.cFileName << endl;
// Option 1: calculate manually (skips the filesize variable):
// filesizelong = static_cast<ULONGLONG>((filedata.nFileSizeHigh) * MAXDWORD) + 1 + filedata.nFileSizeLow;
// Option 2: use LARGE_INTEGER
filesize.HighPart = filedata.nFileSizeHigh;
filesize.LowPart = filedata.nFileSizeLow;
filesizelong = filesize.QuadPart;
cout << endl << "Filesize: " << filesizelong << " bytes." << endl << endl;
}
} while (FindNextFile(fileHandle, &filedata) != 0);
dwerror = GetLastError();
if (dwerror != ERROR_NO_MORE_FILES)
{
cout << "no more files" << endl;
}
FindClose(fileHandle);
return dwerror;
}
else {
cout << "Not a folder." << endl;
system("pause");
return 0;
};
return 0;
}
File attributes on Windows are returned as a single DWORD (unsigned long). Multiple attributes are combined via bitwise OR — each bit has a defined meaning, and certain attributes are mutually exclusive. To check whether a specific attribute is set, AND the DWORD with the attribute constant.
More detail: Combining Attributes with Bitwise OR
#include "pch.h"
#include <iostream>
#include <windows.h>
using namespace std;
int main()
{
WIN32_FIND_DATA FileData; // file data representation
HANDLE myhandle = FindFirstFile(L"c:\Test", &FileData); // handle to the file
// Essentially: "is this attribute set?"
if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
{
cout << endl << "a directory";
}
if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) == FILE_ATTRIBUTE_ARCHIVE)
{
cout << endl << "archived";
}
if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == FILE_ATTRIBUTE_HIDDEN)
{
cout << endl << "hidden";
}
cout << endl << "done";
// You're simply checking whether the relevant bit is set.
// Using & masks all other bits when you AND with the specific value you're looking for.
}
// Example: if dwFileAttributes = 48
// 00110000
// then & (AND) &
// FILE_ATTRIBUTE_DIRECTORY (16) 00010000
// result is non-zero, here: 16
H@ppy H@cking