Windows Driver Frameworks
Windows Driver Frameworks
The author begins by reminding us that Windows, like any modern operating system, exists
to manage a handful of critical resources and services:
Memory management
A flat, virtual address space is presented to every process, with the OS shuffling pages
between RAM and disk behind the scenes.
File systems
Files and directories live in a hierarchical namespace; Windows provides both random‐
access and streamed I/O plus directory operations.
Processors and scheduling
Tasks (processes/threads) are scheduled across one or many CPUs, with preemption
and priority adjustment.
Named resources
Everything from files to synchronization objects (-- mutexes, events, etc.) has a name
and a global namespace.
Concurrency and synchronization
APIs for threads, mutexes, semaphores, I/O completion ports, etc., let you coordinate
work both locally and across the network.
Security
Access tokens, ACLs, privileges, and integrity levels control who can open which object
in what mode.
Modern note: In C11 or later you’d still call the core Win32/Win64 APIs
(e.g. CreateFile, ReadFile, WriteFile, etc.) exactly as before, but you might wrap them in safer
RAII‐style C++ classes or use the Windows Driver Frameworks for kernel‐mode code.
Although multiple “flavors” of Windows exist (desktop, server, embedded), they all speak the
same basic Win32/Win64 API. Over time the API has grown in several dimensions:
1
Usability — richer GUIs, user‐friendly dialogs, accessibility enhancements.
API extensions — new synchronization primitives, file‐system features (Transactional
NTFS), networking models (IOCP, Winsock extensions), etc.
The author stresses that, for compatibility, Microsoft has kept new additions additive. You
can usually build today’s programs to run on yesterday’s OS, or guard your code with a
version‐check.
At the time of writing, the major supported editions fall into two kernel‐generations:
Kernel “NT5” (5.x) Kernel “NT6” (6.x)
Windows 2000 (NT 5.0) Windows Vista (NT 6.0)
Windows XP (NT 5.1) Windows 7 (NT 6.1)
Windows Server 2003 (NT 5.2) Windows Server 2008 / R2 (NT 6.0 / 6.1)
Best practice: Query GetVersionEx (or VersionHelpers.h) at runtime if you plan to call APIs
that only exist in NT6+; otherwise gracefully fail or disable those features.
Windows CE, although much lighter, implements a subset of these APIs for mobile and
embedded devices. And the very old 9x line (95/98/Me) and NT 3.x/4.x have largely been
retired or lack many modern OS services.
The author’s case for Windows boils down to two big pillars:
1. Market dominance. Tens of millions of desktops and servers ship with Windows, so
your user base is massive.
2. Ecosystem. Cheap, plentiful development tools, a familiar GUI, wide hardware support,
and enterprise‐grade features (clustering, Active Directory, Windows Services, etc.) all
lower your time-to-market.
2
Put another way: you trade off a proprietary API for uniformity, stability, and the ability to
reach virtually every PC on the planet.
Proprietary core API. Win32/Win64 isn’t POSIX or X/Open; Microsoft alone defines and
extends it.
Supported standards. You still get Standard C/C++ libraries, Winsock (POSIX‐style
networking), ODBC/ADO/ODBC drivers, RPC, COM, HTTP(S), SQL, etc.
Open interop is achievable via those supported standards—e.g., TCP/IP sockets let
Windows talk to Linux boxes, RPC or REST let diverse systems collaborate, and
database protocols (ODBC, OLE DB) let you plug into Oracle, SQL Server, or MySQL.
The author’s take is balanced: Windows is closed at the core but embraces enough open
standards to sit happily in a heterogeneous environment.
Although the book uses a raw Win32 file-copy example (the classic HANDLE hSrc =
CreateFile(...); ReadFile(...); WriteFile(...); CloseHandle(...)), in 2025 you might wrap these in:
All of these still ultimately invoke the same Windows API foundation that this chapter lays
out.
-------------------------------
3
1. Windows API Is a Handle-Based, Object-Oriented‐Style Interface
Function Names
o Long, descriptive, and case-sensitive: e.g.
cpp
CopyEdit
WaitForSingleObject(handle, INFINITE);
WaitNamedPipe(TEXT("\\\\.\\pipe\\MyPipe"), NMPWAIT_WAIT_FOREVER);
Predefined Types
o Uppercase, self-documenting:
BOOL (32-bit boolean)
HANDLE (pointer-sized opaque)
DWORD (32-bit unsigned)
LPCTSTR / LPTSTR (pointer to (const) TCHAR)
4
o The “LP” prefix originally stood for “long pointer” (16-bit days), now simply a
pointer. Modern code can use char*/wchar_t* or, better, <string>/std::wstring.
Modern code should avoid Hungarian notation and the legacy TCHAR macros in favor
of explicit char/wchar_t or C++ <string> types.
Always call CloseHandle (or UnmapViewOfFile + CloseHandle for mappings) to avoid
leaks.
5
Prefer the “Ex” and Unicode variants of functions (e.g. CreateFile2,
WaitForSingleObjectEx, CreateFileW) for future-proofing and wider feature support.
This overview captures the author’s main points about Windows’ handle-centric design,
naming conventions, portability trade-offs, and when to use the C runtime versus the native
API—plus a few modern best practices for writing clear, maintainable Windows code.
------------------------------
The author uses three variants of a “cp”-style utility to contrast portability, flexibility, and
Windows-specific power:
Key Points
1. Opens files via FILE *in = fopen(..., "rb"), FILE *out = fopen(..., "wb").
2. Reads and writes in a fixed-size buffer loop with fread/fwrite.
3. Checks bytesRead == bytesWritten and uses perror() + errno.
6
4. Always fclose() both streams.
5. I/O is synchronous and portable to UNIX/Linux.
Limitations
o No file locking, asynchronous I/O, memory mapping, or >4 GB support in strict
ANSI C.
o Error reporting limited to errno.
Modern tweak: In C99/C11 you can declare variables at first use, e.g.
CopyEdit
size_t bytes;
char buffer[BUF_SIZE];
if (fwrite(buffer,1,bytes,out) != bytes) { … }
Key Points
1. Opens with CreateFile (generic access flags, share modes, creation disposition).
2. Reads/Writes via ReadFile/WriteFile, checking return BOOL and byte counts.
3. Retrieves extended error codes with GetLastError().
4. Closes handles with CloseHandle() (generic for most kernel objects).
5. Still synchronous—but paves the way for overlapped I/O, security, and large-file
support.
Windows-specific advantages
o Full control over security attributes, sharing modes, and async operations.
o Can easily swap in memory‐mapped files or thread pools later.
CopyEdit
7
8
C. Using the Convenience Function (CopyFile)
The author will next show how a single call to CopyFile(src, dst, FALSE) can replace all
the boilerplate above.
This illustrates Windows’ rich “one-function” helpers for common tasks.
This structured comparison shows how you can evolve a simple file-copy utility from fully
portable C into a Windows-powered tool, mastering both portability and platform-specific
power.
9
1.10 File Copying with a Windows Convenience Function
CopyFile Overview
o CopyFile(src, dst, bFailIfExists) encapsulates all the steps—opening, buffering,
reading, writing, closing—and also preserves metadata (timestamps, attributes,
security).
o It can even leverage internal optimizations (e.g. block-level transfers) on newer
Windows, improving performance over manual loops.
Corrected & Modernized Example
CopyEdit
#include <windows.h>
#include <stdio.h>
if (argc != 3) {
return 1;
return 2;
return 0;
}
10
o Uses fprintf(stderr, …) for error output.
o Calls CopyFile Unicode-neutral via TCHAR (or explicitly use
CopyFileW/CopyFileA).
Timing & Performance
o The author mentions a helper timep utility (described in Chapter 6) for
measuring execution time.
o For large files, CopyFile often outperforms a simple ReadFile/WriteFile loop,
thanks to optimized kernel routines.
Prefer explicit Unicode APIs (CopyFileW) and avoid legacy TCHAR macros in new C++
projects—use wchar_t or std::wstring.
11
Always check return values and report errors clearly with GetLastError() formatted as
decimal or hexadecimal.
For performance tests, use high-resolution timers (e.g. QueryPerformanceCounter) or
modern profiling tools rather than simple wrappers.
12