← Back to all projects

LEARN WINDOWS SYSTEMS PROGRAMMING CPP

Learn Windows Systems Programming: From Toolchain to Deployment

Goal: Master the core concepts of Windows systems programming with C and C++. Go beyond simple applications to understand the build systems, APIs, and deployment strategies that power professional Windows software.


Why Learn Windows Systems Programming?

While application-level development is common, the ability to work at the systems level on Windows is a superpower. This knowledge is critical for:

  • High-Performance Computing: Writing applications that extract maximum performance from the OS.
  • Game Development: Interfacing directly with graphics, input, and system hardware.
  • Cybersecurity: Understanding how malware interacts with the OS and how to build secure software.
  • Developer Tools: Creating debuggers, profilers, and other tools that inspect and manipulate programs.
  • Enterprise & Legacy Systems: Maintaining and building the robust, complex applications that run the world.

After completing these projects, you will:

  • Confidently use the MSVC and Clang toolchains on Windows.
  • Structure complex projects with CMake and MSBuild.
  • Understand and use the core Win32 API for system-level tasks.
  • Build, install, and manage Windows Services.
  • Create professional installers and understand modern deployment.
  • Manage dependencies and avoid “DLL Hell.”

Core Concept Analysis

The Windows Build & Execution Landscape

┌──────────────────────────┐      ┌──────────────────────────┐
│     Source Code (.cpp)     │      │     Library Code (.h/.lib) │
└──────────────────────────┘      └──────────────────────────┘
             │                                  │
             ▼                                  ▼
┌──────────────────────────────────────────────────────────┐
│                       BUILD SYSTEM                         │
│                                                          │
│  CMake: Generates project files for the build tool.      │
│  MSBuild: Reads project files (.vcxproj) to orchestrate. │
└──────────────────────────────────────────────────────────┘
             │
             ▼
┌──────────────────────────────────────────────────────────┐
│                        TOOLCHAIN                         │
│                                                          │
│  Compiler (cl.exe / clang-cl.exe): .cpp -> .obj files    │
│  Linker (link.exe): .obj + .lib -> .exe / .dll           │
└──────────────────────────────────────────────────────────┘
             │
             ▼
┌──────────────────────────────────────────────────────────┐
│                   EXECUTABLE (.exe / .dll)                 │
│                 (Portable Executable Format)             │
│                                                          │
│   .text (code), .data, .rdata (imports), .reloc, etc.    │
└──────────────────────────────────────────────────────────┘
             │
             ▼
┌──────────────────────────────────────────────────────────┐
│                   WINDOWS OS LOADER                      │
│                                                          │
│  Maps PE into memory, resolves imports from system DLLs  │
│  (kernel32.dll, user32.dll, ntdll.dll), and runs it.     │
└──────────────────────────────────────────────────────────┘

Key Concepts Explained

1. Toolchain and Build Systems

  • MSVC (Microsoft Visual C++): The native compiler and toolchain for Windows. cl.exe is the compiler, link.exe is the linker.
  • Clang-cl: A Clang compiler frontend that is command-line compatible with cl.exe. It can be used as a drop-in replacement, allowing you to compile with Clang while targeting the MSVC ABI.
  • CMake: A cross-platform build system generator. You write CMakeLists.txt files describing your targets and dependencies, and CMake generates native project files (e.g., Visual Studio solutions .sln or Ninja files).
  • MSBuild: The build engine used by Visual Studio. It reads XML-based project files (.vcxproj for C++) and executes build tasks (compiling, linking, etc.).
  • Linker Flags: Options passed to link.exe that control the final executable, such as /SUBSYSTEM:WINDOWS, /SUBSYSTEM:CONSOLE, /DEBUG, and optimization flags like /LTCG (Link-Time Code Generation).

2. Windows API & Core DLLs

  • Win32 API: The fundamental C-based API for interacting with the Windows OS.
  • kernel32.dll: Provides core OS functionality: memory management (VirtualAlloc), process and thread management (CreateProcess), file I/O (CreateFile), etc.
  • user32.dll: Provides user-interface functionality: window management (CreateWindowEx), message loops (GetMessage), etc.
  • advapi32.dll: Provides access to advanced core components like the Registry (RegOpenKeyEx) and Service Control Manager (OpenSCManager).
  • Handles: Opaque identifiers (like a file descriptor in Unix) that represent a kernel object (file, process, thread, etc.). You get a handle from a Create... or Open... function and use it in subsequent calls.

3. Distribution & Deployment

  • Installers (MSI): The traditional Windows Installer technology. Uses a database of components, features, and actions to perform transactional installations, modifications, and uninstallations. WiX Toolset is the standard open-source way to create MSIs.
  • Installers (MSIX): The modern, containerized approach. Apps are installed in a sandboxed environment, ensuring clean installation and uninstallation and preventing system-wide modification.
  • Windows Services: Long-running background processes that run without a user interface and can start at boot. They are managed by the Service Control Manager (SCM).
  • Side-by-side Assemblies (SxS): A solution to “DLL Hell.” Allows multiple versions of the same DLL to coexist on a system. Applications use a manifest file to specify which version they require. The WinSxS folder is where these are stored.
  • Registry: A system-wide hierarchical database for configuration data. While still used by the OS, modern applications are encouraged to store settings in configuration files within %APPDATA% or %LOCALAPPDATA% to be more self-contained.
  • Package Managers:
    • vcpkg: A command-line package manager for C/C++ libraries. It integrates with CMake and MSBuild to simplify acquiring and linking dependencies.
    • NuGet: A package manager primarily for the .NET ecosystem, but also used for C++ libraries, especially within Visual Studio.

Project List

The following projects will guide you through the core concepts of Windows systems programming, from setting up your build to deploying a complete application.


Project 1: Multi-Toolchain “Hello, World”

  • File: LEARN_WINDOWS_SYSTEMS_PROGRAMMING_CPP.md
  • Main Programming Language: C++
  • Alternative Programming Languages: C
  • Coolness Level: Level 1: Pure Corporate Snoozefest
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 1: Beginner
  • Knowledge Area: Build Systems / Toolchain
  • Software or Tool: CMake, MSVC, Clang-cl
  • Main Book: “Professional C++” by Marc Gregoire (for modern C++ setup)

What you’ll build: A simple command-line “Hello, World” application, configured with CMake, that can be compiled with both the MSVC and Clang-cl toolchains.

Why it teaches Windows systems programming: This project demystifies the first and most crucial step: the build process. You’ll learn that the compiler is just a tool and a good build system like CMake lets you switch between tools easily.

Core challenges you’ll face:

  • Setting up the environment → maps to installing Visual Studio, Build Tools, and CMake
  • Writing a basic CMakeLists.txt → maps to defining a project, executable, and C++ standard
  • Generating a Visual Studio solution → maps to using CMake generators (-G "Visual Studio ...")
  • Compiling with Clang-cl → maps to specifying a toolchain with CMake (-T ClangCL)

Key Concepts:

  • CMake Project Setup: CMake Documentation - cmake_minimum_required, project, add_executable
  • Visual Studio Generators: “Mastering CMake” by Kitware - Chapter 2
  • CMake Toolchains: CMake Documentation on CMAKE_TOOLCHAIN_FILE

Difficulty: Beginner Time estimate: Weekend Prerequisites: Basic C++ knowledge, command-line familiarity.

Real world outcome: You will have two separate build directories, one for MSVC and one for Clang, each containing a working .exe.

# Generate for MSVC (default)
> mkdir build-msvc && cd build-msvc
> cmake ..
> cmake --build .
# ./Debug/my_app.exe runs and prints "Hello, World from MSVC!"

# Generate for Clang-cl
> mkdir build-clang && cd build-clang
> cmake .. -G "Visual Studio 17 2022" -T ClangCL
> cmake --build .
# ./Debug/my_app.exe runs and prints "Hello, World from Clang!"

Implementation Hints: Your C++ code will need to use preprocessor macros to determine the compiler.

// This is a hint, not the full code.
// In your main.cpp:
#if defined(_MSC_VER) && !defined(__clang__)
    // print "Hello from MSVC"
#elif defined(__clang__)
    // print "Hello from Clang"
#else
    // print "Hello from unknown compiler"
#endif

Your CMakeLists.txt will be very simple:

  1. Set the minimum CMake version.
  2. Define the project name.
  3. Use add_executable() to define your target from main.cpp.
  4. Use target_compile_features() to request a C++ standard (e.g., C++17).

Learning milestones:

  1. Project compiles with MSVC → You understand the default CMake workflow on Windows.
  2. Project compiles with Clang-cl → You can switch toolchains.
  3. You can explain the roles of CMake, MSBuild, and the compiler → You understand the layers of the build process.

Project 2: Custom ls Command with Win32

  • File: LEARN_WINDOWS_SYSTEMS_PROGRAMMING_CPP.md
  • Main Programming Language: C
  • Alternative Programming Languages: C++
  • Coolness Level: Level 2: Practical but Forgettable
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 1: Beginner
  • Knowledge Area: Win32 API / File System
  • Software or Tool: Win32 API
  • Main Book: “Programming Windows, 5th Edition” by Charles Petzold

What you’ll build: A command-line tool that mimics the basic functionality of the ls or dir command, listing files and directories in a given path using the core Win32 API.

Why it teaches Windows systems programming: This is a gentle introduction to the Win32 API, the heart of Windows programming. You’ll learn about handles, Unicode strings (wchar_t), and the standard Windows error-handling mechanism.

Core challenges you’ll face:

  • Using FindFirstFileW and FindNextFileW → maps to the standard pattern for directory iteration
  • Handling HANDLE objects → maps to understanding and correctly closing kernel object references with FindClose
  • Working with WIN32_FIND_DATAW → maps to accessing file attributes, sizes, and names
  • Unicode vs. ANSI → maps to why wchar_t and W functions are standard on Windows
  • Error checking with GetLastError() → maps to the fundamental Win32 error reporting mechanism

Key Concepts:

  • File I/O: “Windows System Programming, 4th Edition” by Johnson M. Hart - Chapter 6
  • Unicode Support in the Win32 API: Microsoft Docs - “Working with Strings”
  • Error Handling: Microsoft Docs - GetLastError function

Difficulty: Beginner Time estimate: Weekend Prerequisites: Project 1, solid understanding of C pointers and structs.

Real world outcome: Your compiled .exe will take a directory path as an argument and print its contents.

> ./my_ls.exe C:\Windows
[D]      Boot
[D]      System32
[F]      win.ini        (1 KB)
[F]      explorer.exe   (4,321 KB)
...

Implementation Hints:

The core logic loop:

  1. Take a path from the command line. Append \* to it to search for all files.
  2. Call FindFirstFileW with the path. This returns a HANDLE and fills a WIN32_FIND_DATAW struct.
  3. Check if the handle is INVALID_HANDLE_VALUE. If so, call GetLastError() to find out why.
  4. If successful, start a do-while loop that continues as long as FindNextFileW returns TRUE.
  5. Inside the loop, inspect the WIN32_FIND_DATAW struct. Check the dwFileAttributes field to see if it’s a directory (FILE_ATTRIBUTE_DIRECTORY).
  6. Print the file/directory name (cFileName) and other info.
  7. After the loop finishes, call FindClose on the handle to release it.

Questions to guide you:

  • How do you combine a directory path and a filename safely?
  • How do you convert a 64-bit file size (nFileSizeHigh, nFileSizeLow) into a single number?
  • What’s the difference between . and .. directory entries and why should you ignore them in your listing?

Learning milestones:

  1. List files in the current directory → You can use the FindFirstFile/FindNextFile loop.
  2. Handle command-line arguments to list any directory → You can process user input.
  3. Display file sizes and distinguish between files and directories → You can interpret the WIN32_FIND_DATA struct.
  4. Code is robust against errors (e.g., path not found) → You are using GetLastError() correctly.

Project 3: PE Header Dump Tool

  • File: LEARN_WINDOWS_SYSTEMS_PROGRAMMING_CPP.md
  • Main Programming Language: C
  • Alternative Programming Languages: C++
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Binary Formats / Windows Executables
  • Software or Tool: PE file format
  • Main Book: “Practical Malware Analysis” by Sikorski & Honig (for its excellent PE format breakdown)

What you’ll build: A command-line utility that reads a .exe or .dll file and prints key information from its PE headers, like the target machine type, number of sections, and timestamp. A simplified dumpbin /headers.

Why it teaches Windows systems programming: It connects the output of the build process (Project 1) to what the OS actually loads. You’ll learn that an executable is not magic; it’s a structured file that the OS parses.

Core challenges you’ll face:

  • Reading a binary file → maps to using CreateFile and ReadFile correctly
  • Mapping PE structures → maps to casting pointers to IMAGE_DOS_HEADER, IMAGE_NT_HEADERS, etc.
  • Navigating the PE format → maps to following offsets like e_lfanew to find the main headers
  • Distinguishing 32-bit vs. 64-bit headers → maps to checking the OptionalHeader.Magic field

Resources for key challenges:

  • PE Format: Microsoft Docs - PE Format
  • Casting and Pointers: “Understanding and Using C Pointers” by Richard M Reese

Key Concepts:

  • PE Header Structure: “Windows Internals, Part 2, 7th Edition” - Chapter 7
  • File Mapping: “Windows System Programming, 4th Edition” - Chapter 7 (An alternative to ReadFile)
  • Data Alignment and Struct Packing: “Expert C Programming” by Peter van der Linden - Chapter 2

Difficulty: Intermediate Time estimate: 1-2 weeks Prerequisites: Project 2, comfort with pointers, pointer arithmetic, and type casting.

Real world outcome: Your tool will inspect an executable and print its metadata.

> ./pe_dumper.exe C:\Windows\System32\kernel32.dll
Parsing 'C:\Windows\System32\kernel32.dll'...

DOS Header:
  Magic: MZ
  PE Header Offset: 0x000000F8

NT Headers:
  Signature: PE
  Machine: x64 (0x8664)
  NumberOfSections: 12
  Timestamp: 2025-11-20 10:30:00
  SizeOfOptionalHeader: 240
  Characteristics: Executable Image, DLL

Optional Header:
  Magic: PE32+ (0x20b)
  ImageBase: 0x00007FF84A9F0000
  Subsystem: Windows GUI

Implementation Hints:

  1. Open the target file using CreateFileW with read-only access.
  2. Read the first few bytes to get the IMAGE_DOS_HEADER. Check the e_magic field to ensure it’s ‘MZ’.
  3. Use the e_lfanew field from the DOS header as an offset from the start of the file. Seek to that position.
  4. Read the IMAGE_NT_HEADERS structure. Check the Signature to ensure it’s ‘PE\0\0’.
  5. The IMAGE_NT_HEADERS contains FileHeader and OptionalHeader. You can now access and print fields from these structures.
  6. Remember to #include <winnt.h> for these structure definitions.
  7. Be careful with 32-bit vs. 64-bit. The OptionalHeader’s size and layout depend on this. Check the Magic field (IMAGE_NT_OPTIONAL_HDR32_MAGIC or IMAGE_NT_OPTIONAL_HDR64_MAGIC).

Learning milestones:

  1. Correctly parse the DOS and NT headers → You can navigate the basic PE structure.
  2. Display the machine type and subsystem → You can extract meaningful data from the headers.
  3. Handle both 32-bit and 64-bit executables → You understand the differences in the optional header.
  4. The tool works on both .exe and .dll files → You understand that they share the same underlying format.

Project 4: Dependency Management with vcpkg

  • File: LEARN_WINDOWS_SYSTEMS_PROGRAMMING_CPP.md
  • Main Programming Language: C++
  • Alternative Programming Languages: N/A
  • Coolness Level: Level 1: Pure Corporate Snoozefest
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 1: Beginner
  • Knowledge Area: Build Systems / Dependency Management
  • Software or Tool: CMake, vcpkg
  • Main Book: N/A, rely on official documentation.

What you’ll build: A simple console application that uses a third-party library, like {fmt} for string formatting or nlohmann/json for JSON parsing, and manage that dependency entirely through vcpkg and CMake.

Why it teaches Windows systems programming: Real-world applications are built on libraries. This project teaches you the modern, clean way to manage C++ dependencies on Windows, avoiding the old manual process of downloading, building, and configuring libraries.

Core challenges you’ll face:

  • Installing and integrating vcpkg → maps to running the bootstrap script and using the CMake toolchain file
  • Finding and installing a package → maps to using vcpkg search and vcpkg install
  • Integrating with CMake → maps to using find_package and target_link_libraries
  • Understanding manifest mode vs. classic mode → maps to declarative dependencies (vcpkg.json) vs. imperative installation

Key Concepts:

  • vcpkg Integration: vcpkg docs - “CMake Integration”
  • CMake find_package: CMake documentation
  • vcpkg Manifests: vcpkg docs - “Manifest Mode”

Difficulty: Beginner Time estimate: Weekend Prerequisites: Project 1 (CMake setup).

Real world outcome: You’ll have a C++ project that seamlessly compiles and links against a third-party library without needing to manually add include paths or library files to your build settings.

# In your project directory
> vcpkg new --application
> vcpkg add port fmt

# Edit your main.cpp to use fmt
# #include <fmt/core.h>
# fmt::print("The answer is {}.", 42);

# Configure with CMake, pointing to the vcpkg toolchain
> cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=[path-to-vcpkg]/scripts/buildsystems/vcpkg.cmake

# Build
> cmake --build build

# Run
> ./build/Debug/my_app.exe
The answer is 42.

Implementation Hints:

  1. Clone vcpkg from GitHub and run the bootstrap script.
  2. Create a vcpkg.json manifest file in your project root.
  3. Add dependencies to the manifest (e.g., { "name": "fmt", "version>=": "8.0.0" }).
  4. In your CMakeLists.txt, use find_package(fmt CONFIG REQUIRED) to locate the library.
  5. Link your executable against it with target_link_libraries(my_app PRIVATE fmt::fmt).
  6. When you run CMake for the first time, it will automatically download and build the dependencies listed in your manifest.

Learning milestones:

  1. vcpkg successfully downloads and builds a dependency → Manifest mode is working.
  2. CMake finds the package with find_package → Toolchain integration is correct.
  3. The project compiles and links successfully → Your executable can find the headers and library files.
  4. The final .exe runs correctly → The required DLLs (if any) are correctly placed in the build directory.

Project 5: A Basic Windows Service

  • File: LEARN_WINDOWS_SYSTEMS_PROGRAMMING_CPP.md
  • Main Programming Language: C++
  • Alternative Programming Languages: C
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 3. The “Service & Support” Model
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Windows Services / OS Integration
  • Software or Tool: Service Control Manager (SCM)
  • Main Book: “Windows System Programming, 4th Edition” by Johnson M. Hart

What you’ll build: A proper Windows Service that, once installed and started, writes a timestamp to a log file every 30 seconds. The executable will also handle command-line arguments to install and uninstall itself.

Why it teaches Windows systems programming: Services are the foundation of background work on Windows. This project forces you to learn the strict lifecycle and communication protocol required by the Service Control Manager (SCM).

Core challenges you’ll face:

  • Implementing ServiceMain → maps to the entry point for the service, where initialization happens
  • Implementing a Service Control Handler → maps to responding to SCM requests like START, STOP, and PAUSE
  • Communicating status to the SCM → maps to using SetServiceStatus to report state changes
  • Installing and Uninstalling the service → maps to using CreateService and DeleteService APIs
  • Debugging a service → maps to the challenge of debugging non-interactive processes

Key Concepts:

Difficulty: Intermediate Time estimate: 1-2 weeks Prerequisites: Project 2, understanding of function pointers.

Real world outcome: You can install, start, stop, and uninstall your service from the command line, and see its effects in a log file and the Services management console (services.msc).

# Install the service
> ./my_service.exe install

# Open services.msc and see "My Timestamp Service" listed
# Start it from services.msc or the command line
> sc start MyTimestampService

# Check the log file
> type C:\logs\my_service.log
Service started. Timestamp: 2025-12-21 14:30:00
Service is running. Timestamp: 2025-12-21 14:30:30
Service is running. Timestamp: 2025-12-21 14:31:00
...

# Stop and uninstall the service
> sc stop MyTimestampService
> ./my_service.exe uninstall

Implementation Hints:

Your main function should parse command-line arguments (install, uninstall).

  • If no arguments, it should try to start the service logic by calling StartServiceCtrlDispatcher.
  • This function takes a table mapping your service name to its ServiceMain function.

ServiceMain function:

  1. Immediately register your control handler function using RegisterServiceCtrlHandler.
  2. Set the service status to SERVICE_START_PENDING.
  3. Do your one-time startup work.
  4. Set the service status to SERVICE_RUNNING.
  5. Enter the main service loop (e.g., a while loop that waits on an event).
  6. When a stop is requested, the loop will exit.
  7. Perform cleanup and set status to SERVICE_STOPPED.

Service Control Handler function:

  1. This is a callback that receives control codes.
  2. Use a switch statement on the control code.
  3. For SERVICE_CONTROL_STOP, signal your main loop to exit (e.g., by setting an event with SetEvent).
  4. Update the service status with SetServiceStatus accordingly.

Debugging Tip: In the very beginning of your ServiceMain, you can call DebugBreak() and then attach a debugger to the process from Visual Studio (Debug > Attach to Process...).

Learning milestones:

  1. Service installs and appears in services.msc → You can interact with the SCM.
  2. Service starts and logs timestamps → Your ServiceMain logic is working.
  3. Service stops gracefully when requested → Your control handler and main loop communication are correct.
  4. Service uninstalls cleanly → Your cleanup logic is working.

Project 6: WiX Toolset MSI Installer

  • File: LEARN_WINDOWS_SYSTEMS_PROGRAMMING_CPP.md
  • Main Programming Language: WiX (XML)
  • Alternative Programming Languages: N/A
  • Coolness Level: Level 2: Practical but Forgettable
  • Business Potential: 3. The “Service & Support” Model
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Deployment / Installers
  • Software or Tool: WiX Toolset, MSI
  • Main Book: “WiX: A Developer’s Guide to Windows Installer XML” by Nick Ramirez

What you’ll build: A standard MSI installer for one of your previous projects (e.g., the my_ls tool from Project 2). The installer will place the executable in C:\Program Files, create a Start Menu shortcut, and add an entry in “Add/Remove Programs”.

Why it teaches Windows systems programming: Building an installer is a critical part of the software lifecycle. You’ll learn how applications are properly integrated into the OS, how component-based installation works, and why clean uninstalls are so important.

Core challenges you’ll face:

  • Understanding WiX XML syntax → maps to describing your product, components, and features declaratively
  • Defining components and GUIDs → maps to the core principle of MSI: every component needs a unique, stable ID
  • Creating directories and shortcuts → maps to using standard MSI properties and WiX elements
  • Compiling and linking the WiX project → maps to using candle.exe and light.exe to create the MSI

Key Concepts:

  • MSI Components and Features: WiX Tutorial - “Your First Installation”
  • WiX Directory Structure: WiX documentation on the <Directory> element.
  • GUIDs in MSI: WiX Tutorial - “It’s a GUID World”

Difficulty: Intermediate Time estimate: Weekend Prerequisites: A compiled .exe from a previous project.

Real world outcome: You will have a professional-looking MyCoolTool.msi file that users can double-click to install your application, and then cleanly uninstall it from the Control Panel.

Implementation Hints:

A basic WiX source file (Product.wxs):

  1. Start with the root <Wix> element.
  2. Inside, define a <Product> with a Name, Manufacturer, Version, and unique Id (a GUID).
  3. Define a <Package> with installer properties.
  4. Define your media layout with <MediaTemplate>.
  5. Define the directory structure using nested <Directory> elements, starting from TARGETDIR. You’ll want to target ProgramFilesFolder.
  6. Inside your target directory, define a <Component>. A component is the smallest installable unit. Give it a GUID.
  7. Inside the component, use a <File> element to point to your .exe.
  8. Define a <Feature> that groups your components. This is what the user sees in a “Custom” install UI.
  9. To create a shortcut, add another component with a <Shortcut> element.

The build process:

  • candle.exe Product.wxsProduct.wixobj (Compiles)
  • light.exe Product.wixobjProduct.msi (Links)

Learning milestones:

  1. A working MSI is created → You understand the basic WiX build process.
  2. The application installs to the correct directory → You can control the installation path.
  3. A Start Menu shortcut is created → You can create shell links.
  4. The application can be uninstalled from “Add/Remove Programs” → Your component logic is correct, and the system can track your files.

Project 7: Registry Profiler

  • File: LEARN_WINDOWS_SYSTEMS_PROGRAMMING_CPP.md
  • Main Programming Language: C++
  • Alternative Programming Languages: C
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 2. The “Micro-SaaS / Pro Tool”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Win32 API / Registry
  • Software or Tool: Win32 API
  • Main Book: “Windows Internals, Part 1, 7th Edition” by Russinovich, Solomon, and Ionescu

What you’ll build: A command-line tool that monitors a specified registry key for any changes. When a value is added, modified, or deleted under that key, your tool will print a notification to the console.

Why it teaches Windows systems programming: This project goes beyond simple registry reads/writes and teaches you about the asynchronous notification system built into the Win32 API. It’s a foundational concept for building reactive, efficient monitoring tools. It also teaches you why indiscriminate registry use is discouraged (it’s a shared, global resource).

Core challenges you’ll face:

  • Opening registry keys with RegOpenKeyExW → maps to understanding registry hives (HKLM, HKCU) and access rights
  • Setting up notifications with RegNotifyChangeKeyValue → maps to asynchronous programming in Win32 using event handles
  • Waiting on kernel objects with WaitForSingleObject → maps to the core mechanism for waiting for events without burning CPU cycles
  • Interpreting what changed → maps to the realization that RegNotifyChangeKeyValue tells you *that something changed, but not *what**

Key Concepts:

  • Registry Overview: Microsoft Docs - Registry
  • Asynchronous I/O with Events: “Windows System Programming, 4th Edition” - Chapter 9
  • Registry Functions: Microsoft Docs - Using the Registry

Difficulty: Intermediate Time estimate: 1-2 weeks Prerequisites: Project 2, understanding of HANDLE objects.

Real world outcome: You can run your tool to watch a key, then use regedit.exe to make a change and see your tool react instantly.

> ./reg_profiler.exe "HKCU\Software\MyTestApp"
Monitoring registry key: HKCU\Software\MyTestApp
Press Ctrl+C to stop.

[CHANGE DETECTED] A value or subkey has changed.
[CHANGE DETECTED] A value or subkey has changed.
...

Implementation Hints:

  1. Parse the command line to get the registry key path string.
  2. Use RegOpenKeyExW to get a handle to the key.
  3. Create an event object using CreateEventW.
  4. Enter a while loop.
  5. Inside the loop, call RegNotifyChangeKeyValue. Pass it the key handle, tell it to monitor the subtree, specify which changes to watch for (e.g., REG_NOTIFY_CHANGE_LAST_SET), and provide the handle to your event object.
  6. Call WaitForSingleObject on your event handle with an infinite timeout. Your program will block here efficiently.
  7. When RegNotifyChangeKeyValue detects a change, it signals your event, and WaitForSingleObject returns.
  8. Print your “change detected” message.
  9. Loop back to call RegNotifyChangeKeyValue again to re-arm the notification.
  10. Remember to close the key and event handles on exit.

This project also implicitly teaches why to avoid the registry for application settings: any app can watch any other app’s configuration, which is poor encapsulation. Modern apps prefer config files in %LOCALAPPDATA%.

Learning milestones:

  1. Successfully open a registry key → You understand registry paths and permissions.
  2. The program blocks until a change is made → You have correctly set up the notification and wait.
  3. The program detects changes and continues to monitor → Your loop logic is correct.
  4. The program exits cleanly and releases handles → You are managing kernel resources correctly.

Project 8: Side-by-Side Assembly (SxS) Demo

  • File: LEARN_WINDOWS_SYSTEMS_PROGRAMMING_CPP.md
  • Main Programming Language: C++
  • Alternative Programming Languages: C
  • Coolness Level: Level 3: Genuinely Clever
  • Business Potential: 1. The “Resume Gold”
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Deployment / OS Internals
  • Software or Tool: Manifest files, SxS
  • Main Book: “Advanced Windows Debugging” by Hewardt and Pravat (for context on loader issues)

What you’ll build: A solution to the classic “DLL Hell.” You’ll create two distinct versions of a DLL (e.g., version_lib.dll v1.0 and v2.0), each exporting the same function that returns a different version string. You will then build an executable that uses a manifest file to explicitly load and call the v1.0 DLL, even when v2.0 is in the same directory.

Why it teaches Windows systems programming: This project demystifies the Windows loader and solves a historical pain point. You’ll gain a deep understanding of how manifests, fusion (fusion.dll), and the WinSxS cache work together to load the correct version of a dependency.

Core challenges you’ll face:

  • Creating application and assembly manifests → maps to writing the XML files that describe the application and its dependencies
  • Embedding a manifest into an executable → maps to using the mt.exe tool or linker settings (/MANIFEST)
  • Structuring the files correctly → maps to creating the specific directory layout that the SxS loader expects
  • Debugging loader issues → maps to using the Event Viewer’s “Application” log to diagnose manifest and SxS problems

Key Concepts:

Difficulty: Advanced Time estimate: 1-2 weeks Prerequisites: Project 3, understanding of DLLs (how to create and export functions).

Real world outcome: Your executable, when run, will print “v1.0” despite a version_lib.dll v2.0 existing right next to it, proving your manifest is controlling the loader.

/my_app/
  my_app.exe
  /MyOrg.MyLib.v1/
    version_lib.dll  (v1.0)
    MyOrg.MyLib.v1.manifest
  /MyOrg.MyLib.v2/
    version_lib.dll  (v2.0)
    MyOrg.MyLib.v2.manifest

> ./my_app.exe
Library version: 1.0.0.0

Implementation Hints:

  1. DLLs: Create two projects for a version_lib.dll. In v1, a function GetVersionString() returns “1.0.0.0”. In v2, it returns “2.0.0.0”.
  2. Assembly Manifests: For each DLL, create a .manifest file. It should define the assembly identity with a name, version, type, and publicKeyToken (can be all zeroes for this demo). It also lists the file it contains (version_lib.dll).
  3. Application Manifest: Create a manifest for my_app.exe. This manifest will contain a <dependency> element pointing to the specific version of the assembly you want (e.g., version “1.0.0.0”).
  4. Embedding: Use mt.exe or Visual Studio project settings to embed the application manifest into my_app.exe as a resource. The resource ID should be 1 (RT_MANIFEST).
  5. Layout: The loader needs a specific directory structure to find private assemblies. Create subdirectories named after the assembly and version, and place the DLLs and their corresponding assembly manifests inside.

Learning milestones:

  1. The application loads the DLL when both are in the same folder (no manifest) → Basic DLL loading works.
  2. The application fails to load when multiple DLL versions are present (no manifest) → You’ve created DLL Hell.
  3. The application manifest is correctly embedded in the .exe → You can verify this with a resource viewer.
  4. The application successfully loads the specific version declared in the manifest → You have mastered SxS loading.

Project 9: Simple Auto-Updater

  • File: LEARN_WINDOWS_SYSTEMS_PROGRAMMING_CPP.md
  • Main Programming Language: C++
  • Alternative Programming Languages: C
  • Coolness Level: Level 2: Practical but Forgettable
  • Business Potential: 2. The “Micro-SaaS / Pro Tool”
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Deployment / Networking
  • Software or Tool: WinINet or WinHttp, MSI
  • Main Book: N/A, rely on documentation and articles.

What you’ll build: An “updater” component for a simple application. The main application, on startup, will quietly make an HTTP request to a static URL you control. It will fetch a JSON file that specifies the latest version and a download link for an MSI. If the fetched version is newer than the application’s current version, it will download the new MSI and launch it.

Why it teaches Windows systems programming: This is a real-world problem that combines networking, file I/O, version comparison, and process management. It forces you to think about security, user experience, and robust error handling.

Core challenges you’ll face:

  • Making HTTP requests with native APIs → maps to using WinINet (higher-level) or WinHttp (more robust)
  • Parsing JSON → maps to integrating a C++ JSON library (e.g., nlohmann/json via vcpkg)
  • Downloading a file from the internet → maps to reading an HTTP response body and writing it to a temporary file
  • Launching the installer → maps to using CreateProcess or ShellExecuteEx to run the downloaded MSI
  • Version comparison → maps to embedding version resources in your executable and reading them at runtime

Key Concepts:

Difficulty: Advanced Time estimate: 2-3 weeks Prerequisites: Project 4 (vcpkg), Project 6 (MSI), basic HTTP knowledge.

Real world outcome: You can host a JSON file and an MSI on a static server (like GitHub Pages). When you run an old version of your app, it will detect the new version, download the MSI, and prompt the user to upgrade.

version.json hosted on your server:

{
  "version": "1.1.0",
  "url": "https://my-updates.example.com/MyApp-1.1.0.msi"
}

Application Output:

> ./my_app.exe
Current version: 1.0.0. Checking for updates...
New version 1.1.0 found. Downloading...
Download complete. The installer will now launch.
(A UAC prompt appears for the MSI installer)

Implementation Hints:

  1. Version Resource: Add a Version Information resource (.rc file) to your application’s project. This allows you to stamp it with a version number that can be queried at runtime.
  2. Update Check Logic: On startup, run this in a background thread to avoid blocking the UI.
  3. Networking: Use InternetOpen, InternetOpenUrl, and InternetReadFile from WinINet for a straightforward implementation.
  4. JSON Parsing: Use nlohmann/json from vcpkg to parse the response from the server.
  5. Download: Read the file in chunks from the HTTP request and write it to a temporary file in the user’s %TEMP% directory.
  6. Launch: Once the download is verified, use ShellExecuteEx to launch the MSI. This is often easier than CreateProcess as it will handle elevation (UAC) correctly.
  7. Security: For a real product, you’d need to verify the downloaded file’s digital signature using the WinTrust API. This is an advanced (but critical) step.

Learning milestones:

  1. Application can read its own version number → Version resources are working.
  2. Application can fetch and parse the remote JSON file → Networking and JSON integration are successful.
  3. Application can download the MSI to a temp file → File download logic is correct.
  4. Application launches the downloaded installer → Process launching is successful.
  5. The entire process works only when the remote version is newer → Version comparison logic is correct.

Project 10: Advanced MSBuild Customization

  • File: LEARN_WINDOWS_SYSTEMS_PROGRAMMING_CPP.md
  • Main Programming Language: MSBuild (XML)
  • Alternative Programming Languages: PowerShell or Batch for scripts
  • Coolness Level: Level 1: Pure Corporate Snoozefest
  • Business Potential: 3. The “Service & Support” Model
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Build Systems
  • Software or Tool: MSBuild
  • Main Book: “MSBuild Trickery” by Mike Stall (online blog series)

What you’ll build: You will extend a Visual Studio C++ project file (.vcxproj) to include a custom build step. This step will run after a successful build and will automatically zip the build output and copy it to a designated “deployment” folder.

Why it teaches Windows systems programming: While CMake is for generation, MSBuild is the engine. Understanding it directly allows you to create highly customized, powerful build logic that’s deeply integrated with the Visual Studio ecosystem, a common requirement in enterprise environments.

Core challenges you’ll face:

  • Editing .vcxproj files → maps to understanding the XML structure of MSBuild projects
  • Defining custom Targets → maps to creating your own build actions
  • Using AfterTargets to control execution order → maps to hooking your custom logic into the standard build process
  • Using MSBuild properties and items → maps to accessing build variables like $(OutDir) and $(TargetName)
  • Executing external commands → maps to using the <Exec> task to run PowerShell or 7z.exe

Key Concepts:

Difficulty: Advanced Time estimate: 1-2 weeks Prerequisites: Familiarity with Visual Studio projects and XML.

Real world outcome: After building your project in Visual Studio, a MyCoolApp-v1.2.zip file will automatically appear in a C:\deploy folder.

Build Output in Visual Studio:

... 
  my_app.vcxproj -> C:\Users\douglas\source\repos\my_app\x64\Debug\my_app.exe
  Running custom deployment step...
  Zipping output to C:\deploy\my_app-Debug.zip
  Deployment complete.

Implementation Hints:

  1. Unload your C++ project in Visual Studio and open the .vcxproj file for editing.
  2. Scroll to the bottom, just before the closing </Project> tag.
  3. Define a new <Target> with a unique name, like ZipAndDeploy.
  4. Use the AfterTargets="Build" attribute on your target to make it run after the main build.
  5. Inside the target, use the <Message> task to print status text to the build output.
  6. Use the <Exec> task to run a command. You can use PowerShell’s Compress-Archive or invoke an external tool like 7-Zip.
  7. Use MSBuild properties in your command. For example, the path to your executable is $(TargetPath). The output directory is $(OutDir).
  8. Create a property group to define your deployment directory, e.g., <DeployDir>C:\deploy</DeployDir>.

Example Target structure:

<Target Name="ZipAndDeploy" AfterTargets="Build">
  <Message Text="Running custom deployment step..." Importance="high" />
  <PropertyGroup>
    <DeployDir>C:\deploy</DeployDir>
    <ZipFileName>$(ProjectName)-$(Configuration).zip</ZipFileName>
  </PropertyGroup>
  <Exec Command="powershell -Command Compress-Archive -Path '$(OutDir)*' -DestinationPath '$(DeployDir)\$(ZipFileName)' -Force" />
  <Message Text="Deployment complete to $(DeployDir)\$(ZipFileName)." Importance="high" />
</Target>

Learning milestones:

  1. A custom message appears in the build log → You have successfully added a custom target.
  2. The target runs only after a successful build → Your AfterTargets logic is correct.
  3. The build output is successfully zipped → The <Exec> task is working and can access build properties.
  4. The zip file is copied to the correct deployment folder → You can define and use custom properties.

Project 11: Create a Modern MSIX Package

  • File: LEARN_WINDOWS_SYSTEMS_PROGRAMMING_CPP.md
  • Main Programming Language: XML (for manifest)
  • Alternative Programming Languages: N/A
  • Coolness Level: Level 2: Practical but Forgettable
  • Business Potential: 2. The “Micro-SaaS / Pro Tool”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Deployment / Installers
  • Software or Tool: MSIX, Windows Application Packaging Project
  • Main Book: N/A, rely on Microsoft’s official documentation.

What you’ll build: You will package one of your existing C++ applications (like the my_ls tool) as a modern MSIX package. This will involve creating a manifest, assigning an identity, and generating a signed package that can be installed with a double-click.

Why it teaches Windows systems programming: This is the future of Windows application deployment. It teaches you about application containerization, declarative capabilities, and the clean install/uninstall model that solves many legacy deployment problems.

Core challenges you’ll face:

  • Creating a Packaging Project in Visual Studio → maps to using the “Windows Application Packaging Project” template
  • Configuring the Package.appxmanifest → maps to defining the application’s identity, capabilities, and entry point
  • Handling application assets → maps to providing icons and logos in various required sizes
  • Signing the package → maps to creating a temporary self-signed certificate for testing

Key Concepts:

Difficulty: Intermediate Time estimate: Weekend Prerequisites: A working C++ application. Visual Studio 2019 or newer.

Real world outcome: You will have a .msix file. When you double-click it, a modern, trustworthy-looking installer UI will appear and install your application. The app will appear in the Start Menu and can be uninstalled with a single click, leaving no trace.

Implementation Hints:

  1. In your existing Visual Studio solution, add a new project using the “Windows Application Packaging Project” template.
  2. In the new project, right-click “Applications” and add a reference to your existing C++ project.
  3. Open the Package.appxmanifest file. Use the manifest designer to configure your app.
    • Application Tab: Set the entry point to your executable.
    • Visual Assets Tab: Generate all the required icon and tile assets from a single image.
    • Capabilities Tab: Declare any capabilities your app needs (e.g., internetClient if it uses the network). For a simple tool, you may not need any.
    • Packaging Tab: Set the package name and publisher identity. This must match the subject of your signing certificate.
  4. To sign the package for testing, the manifest designer has a “Create…” button on the Packaging tab to generate a self-signed certificate. You will need to trust this certificate on your machine to install the package.
  5. Build the solution. The MSIX package will be created in the packaging project’s output directory.

Learning milestones:

  1. The packaging project builds successfully → Your project references and manifest are set up correctly.
  2. The generated .msix file can be installed → Your package is correctly signed and trusted.
  3. The installed application runs from the Start Menu → The entry point in your manifest is correct.
  4. The application uninstalls cleanly → You have experienced the primary benefit of MSIX.

Project 12: Capstone - A Modular System Monitoring Tool

  • File: LEARN_WINDOWS_SYSTEMS_PROGRAMMING_CPP.md
  • Main Programming Language: C++
  • Alternative Programming Languages: C
  • Coolness Level: Level 4: Hardcore Tech Flex
  • Business Potential: 4. The “Open Core” Infrastructure
  • Difficulty: Level 4: Expert
  • Knowledge Area: Systems Integration
  • Software or Tool: Win32 API, CMake, WiX/MSIX
  • Main Book: “Windows Internals, Part 1 & 2” by Russinovich, Solomon, and Ionescu

What you’ll build: A complete, deployable system utility. The tool consists of a background Windows Service that collects system metrics and a GUI “dashboard” application that communicates with the service to display the data in real-time. The entire system will be packaged in an MSI or MSIX installer.

Why it teaches Windows systems programming: This capstone project integrates almost everything you’ve learned: build systems, system APIs, services, inter-process communication, and deployment. It mirrors the architecture of professional system software like antivirus clients or monitoring agents.

Core challenges you’ll face:

  • Designing an Inter-Process Communication (IPC) mechanism → maps to choosing and implementing a way for the GUI to talk to the service (e.g., Named Pipes, Sockets)
  • Creating a multi-project CMake solution → maps to managing a shared code library, a service executable, and a GUI executable
  • Developing a native GUI → maps to using the raw Win32 API for UI (hard), or a framework like WinUI 3 or Qt (recommended)
  • Bundling multiple executables into one installer → maps to installing both the service and the GUI app, and configuring the service to start
  • Handling permissions → maps to the service running as a privileged user while the GUI runs as the standard user

Key Concepts:

  • Inter-Process Communication: Microsoft Docs - IPC Overview
  • Named Pipes: “Windows System Programming, 4th Edition” - Chapter 11
  • Multi-project CMake: “Professional CMake: A Practical Guide” by Craig Scott
  • Installer with Services: WiX documentation on the <ServiceInstall> element.

Difficulty: Expert Time estimate: 1 month+ Prerequisites: All previous projects, or a very solid understanding of the concepts they teach.

Real world outcome: You will have a fully functional monitoring tool. You install it, a service starts collecting CPU/memory usage in the background, and you can launch a desktop app to see live graphs of that data.

Implementation Hints:

  1. Project Structure: Set up a single root CMakeLists.txt that uses add_subdirectory() for three parts:
    • shared-lib: Common code for data structures, etc.
    • monitoring-service: The C++ project for your Windows Service.
    • dashboard-gui: The C++ project for your GUI application.
  2. IPC: Named Pipes are a good choice for this. The service creates a named pipe server, and the GUI connects as a client to request data. Define a simple protocol (e.g., client sends “GET_CPU”, service responds with the value).
  3. Service Logic: The service, in its main loop, will periodically collect data (e.g., using GetSystemTimes for CPU usage) and listen for client connections on the named pipe.
  4. GUI: For simplicity, you could start with a console application that prints the data. A true GUI is a big step; consider using a simple MessageBox to display alerts as a starting point before diving into a full UI framework.
  5. Installer: Your WiX or MSIX project will need to:
    • Install both executables.
    • Use the <ServiceInstall> and <ServiceControl> elements (in WiX) to register and start your service upon installation.

Learning milestones:

  1. The service and GUI compile from a single CMake command → Your multi-project build is set up correctly.
  2. The GUI can send a message to the service and get a response → Your IPC mechanism is working.
  3. The installer correctly installs and starts the service → Your deployment logic is complete.
  4. The entire system works, showing real-time data from the service in the GUI → You have successfully integrated all components into a professional-grade application.

Project Comparison Table

Project Difficulty Time Core Concept Fun Factor
1. Multi-Toolchain “Hello, World” Beginner Weekend Build Systems ★☆☆☆☆
2. Custom ls Command Beginner Weekend Win32 API ★★☆☆☆
3. PE Header Dump Tool Intermediate 1-2 weeks Binary Formats ★★★☆☆
4. vcpkg Dependency Management Beginner Weekend Build Integration ★★☆☆☆
5. Basic Windows Service Intermediate 1-2 weeks OS Integration ★★★☆☆
6. WiX Toolset MSI Installer Intermediate Weekend Deployment ★★☆☆☆
7. Registry Profiler Intermediate 1-2 weeks Async Win32 ★★★☆☆
8. SxS Assembly Demo Advanced 1-2 weeks DLL Loading ★★★★☆
9. Simple Auto-Updater Advanced 2-3 weeks Networking/Deploy ★★★☆☆
10. Advanced MSBuild Customization Advanced 1-2 weeks Build Internals ★★☆☆☆
11. Modern MSIX Package Intermediate Weekend Modern Deploy ★★★☆☆
12. Capstone: Monitoring Tool Expert 1 month+ Systems Integration ★★★★★

Recommendation

For a true beginner to Windows systems programming, start with Project 1: Multi-Toolchain “Hello, World” and immediately follow it with Project 2: Custom ls Command.

Project 1 is not glamorous, but it forces you to set up your environment correctly and understand the relationship between your code, the build system, and the compiler. This foundation is essential. Project 2 is the perfect next step because it introduces you to the core patterns of the Win32 API—handles, Unicode, and error handling—in a practical, easy-to-verify way.

After completing these two, you will have the fundamental skills and confidence to tackle any of the other intermediate projects based on what interests you most, whether that’s deployment (Project 6), OS integration (Project 5), or binary structures (Project 3).


Summary

  • Project 1: Multi-Toolchain “Hello, World”: C++
  • Project 2: Custom ls Command with Win32: C
  • Project 3: PE Header Dump Tool: C
  • Project 4: Dependency Management with vcpkg: C++
  • Project 5: A Basic Windows Service: C++
  • Project 6: WiX Toolset MSI Installer: WiX (XML)
  • Project 7: Registry Profiler: C++
  • Project 8: Side-by-Side Assembly (SxS) Demo: C++
  • Project 9: Simple Auto-Updater: C++
  • Project 10: Advanced MSBuild Customization: MSBuild (XML)
  • Project 11: Create a Modern MSIX Package: XML
  • Project 12: Capstone - A Modular System Monitoring Tool: C++

```