Windows Win32 File Operations

The Win32 API provides a comprehensive set of functions for interacting with the file system on Windows. These functions allow applications to create, read, write, delete, and manage files and directories.

Core Concepts

Understanding how Windows handles files is crucial for effective Win32 programming. Key concepts include:

Common File Operations

Creating and Opening Files

The primary function for creating or opening files is CreateFile. This function is versatile and can be used for a wide range of file operations.

HANDLE CreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);

  • lpFileName: The name of the file.
  • dwDesiredAccess: The requested access to the file (e.g., GENERIC_READ, GENERIC_WRITE).
  • dwShareMode: How the file should be shared among other processes.
  • dwCreationDisposition: How to create or open the file (e.g., CREATE_ALWAYS, OPEN_EXISTING).
  • dwFlagsAndAttributes: File attributes and flags.

Reading from Files

Once a file is opened and a handle is obtained, data can be read using the ReadFile function.

BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);

  • hFile: The handle to the file to read from.
  • lpBuffer: A buffer that receives the data.
  • nNumberOfBytesToRead: The number of bytes to read.
  • lpNumberOfBytesRead: A pointer to a variable that receives the number of bytes actually read.

HANDLE hFile = CreateFile(
    L"C:\\path\\to\\your\\file.txt",
    GENERIC_READ,
    FILE_SHARE_READ,
    NULL,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,
    NULL
);

if (hFile != INVALID_HANDLE_VALUE) {
    char buffer[1024];
    DWORD bytesRead;
    if (ReadFile(hFile, buffer, sizeof(buffer) - 1, &bytesRead, NULL)) {
        buffer[bytesRead] = '\0'; // Null-terminate the buffer
        // Process the read data in 'buffer'
        std::cout << "Read " << bytesRead << " bytes: " << buffer << std::endl;
    }
    CloseHandle(hFile);
} else {
    // Handle error
    std::cerr << "Failed to open file. Error code: " << GetLastError() << std::endl;
}
            

Writing to Files

Writing data to a file is accomplished using the WriteFile function.

BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);

  • hFile: The handle to the file to write to.
  • lpBuffer: A buffer containing the data to write.
  • nNumberOfBytesToWrite: The number of bytes to write.
  • lpNumberOfBytesWritten: A pointer to a variable that receives the number of bytes actually written.

HANDLE hFile = CreateFile(
    L"C:\\path\\to\\new\\file.txt",
    GENERIC_WRITE,
    0,
    NULL,
    CREATE_ALWAYS,
    FILE_ATTRIBUTE_NORMAL,
    NULL
);

if (hFile != INVALID_HANDLE_VALUE) {
    const char* dataToWrite = "This is some data to write to the file.\n";
    DWORD bytesWritten;
    if (WriteFile(hFile, dataToWrite, strlen(dataToWrite), &bytesWritten, NULL)) {
        std::cout << "Successfully wrote " << bytesWritten << " bytes." << std::endl;
    }
    CloseHandle(hFile);
} else {
    // Handle error
    std::cerr << "Failed to create/open file for writing. Error code: " << GetLastError() << std::endl;
}
            

Closing Files

It's essential to close file handles when they are no longer needed to free up system resources. This is done with the CloseHandle function.

BOOL CloseHandle(HANDLE hObject);

hObject: A handle to an open object, including file handles.

Directory Operations

Beyond individual files, the Win32 API also provides functions for managing directories.

Creating Directories

Use CreateDirectory to create new directories.

BOOL CreateDirectory(LPCTSTR lpPathName, LPSECURITY_ATTRIBUTES lpAttribute);

  • lpPathName: The path of the directory to create.
  • lpAttribute: Security attributes (usually NULL).

Deleting Directories

The RemoveDirectory function deletes an empty directory.

BOOL RemoveDirectory(LPCTSTR lpPathName);

lpPathName: The path of the directory to remove.

Listing Directory Contents

Finding files and subdirectories within a directory often involves using FindFirstFile and FindNextFile.


WIN32_FIND_DATA findFileData;
HANDLE hFind = FindFirstFile(L"C:\\Windows\\*.*", &findFileData); // Example: list contents of C:\Windows

if (hFind != INVALID_HANDLE_VALUE) {
    do {
        std::wcout << findFileData.cFileName << std::endl;
    } while (FindNextFile(hFind, &findFileData) != FALSE);
    FindClose(hFind);
} else {
    std::cerr << "Error finding files. Error code: " << GetLastError() << std::endl;
}
            

Error Handling

Win32 API functions typically return a specific value to indicate success or failure. For detailed error information, use the GetLastError function, which returns a system error code.


DWORD errorCode = GetLastError();
if (errorCode != 0) {
    // Format and display the error message
    LPVOID lpMsgBuf;
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        errorCode,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );
    std::cerr << "System Error: " << (LPCTSTR)lpMsgBuf << std::endl;
    LocalFree(lpMsgBuf);
}