0xHabib
HomePostsVisualizationsCheatsheetsNotesStudy DecksAbout

Built with Love. 0xHabib © 2025

Anonymous analytics are collected for performance monitoring and site improvement purposes.

Windows Development with C++ - Win32 API Fundamentals

Windows Development with C++: Part 1 - Foundations

Part 1 of the Windows Development series. Master Win32 API fundamentals, window creation, the message loop, and modern C++ patterns for native Windows programming.

December 18, 2025
17 min read
byMohamed Habib Jaouadi
#windows-development-series
#win32-api
#c++
#windows-programming
#visual-studio
#native-development
Windows Development with C++
Part 1 of 1
Series Progress100%

📘 Prerequisites: Basic C++ knowledge and a Windows development environment. While this series is approachable for developers of all backgrounds, it includes context relevant to security researchers who want to understand how Windows applications work at a fundamental level.

Introduction

Every sophisticated Windows tool, whether a productivity application, a game, or a security utility, is built on the same foundation: the Win32 API. This native interface layer, dating back to Windows NT in 1993, remains the most powerful way to interact with the Windows operating system. Modern frameworks like .NET, Qt, and Electron ultimately call down to these same APIs.

For security professionals, understanding Win32 is non-negotiable. Whether you're developing red team tooling, analyzing malware, or building defensive solutions, the Win32 API is the common language. This series bridges the gap between theoretical knowledge and practical application, taking you from your first window to advanced system programming.

In Part 1, we'll establish the foundations: setting up a proper development environment, creating and registering window classes, understanding the message loop that drives all GUI applications, and applying modern C++ patterns to write clean, maintainable Windows code.

Development Environment Setup

Visual Studio Installation

Visual Studio is the de facto IDE for Windows development. The Community edition is free for individual developers and provides everything we need.

Required Workloads:

  1. Desktop development with C++ - Core C++ compiler, libraries, and debugging tools
  2. Windows SDK (included) - Headers and libraries for Win32 API
Visual Studio Installer Configurationtext

Project Configuration

When creating a new project, select Windows Desktop Application for a pre-configured Win32 template, or Empty Project for complete control. We'll use the empty project approach to understand every line of code.

Critical Project Settings:

Project Properties Configurationtext

The Unicode Character Set setting is crucial. It defines UNICODE and _UNICODE preprocessor macros, making all Windows API calls use wide-character (UTF-16) versions by default. This is the correct approach for any modern Windows application.

Your First Win32 Window

Let's build a complete window from scratch, understanding every component. The Win32 programming model is fundamentally event-driven: you create a window, and the operating system sends it messages describing user input, system events, and rendering requests.

The Complete Window Application

Minimal Win32 Window Application (main.cpp)cpp

Understanding the Entry Point

Unlike console applications that use main(), Windows GUI applications use WinMain (or the Unicode version wWinMain):

int WINAPI wWinMain(
    HINSTANCE hInstance,       // Handle identifying this running instance
    HINSTANCE hPrevInstance,   // Legacy parameter, always NULL
    LPWSTR lpCmdLine,          // Command line as a wide string
    int nCmdShow               // Initial window visibility state
);

The WINAPI macro maps to the __stdcall calling convention on 32-bit systems (x86), where the callee cleans the stack. On 64-bit systems (x64), WINAPI is still used for compatibility but maps to the native x64 calling convention (fastcall-based), where the first four arguments are passed in registers and the caller reserves stack space.

The Window Class: WNDCLASSEXW

Before creating a window, you must register a window class that defines its behavior. Think of it as a blueprint:

MemberPurpose
lpfnWndProcPointer to the function that handles messages
hInstanceApplication instance that owns this class
lpszClassNameUnique string identifier for this class
styleClass styles (redraw behavior, double-clicks, etc.)
hbrBackgroundDefault background brush
hIcon, hCursorDefault icon and cursor

Common class styles include:

  • CS_HREDRAW | CS_VREDRAW - Redraw entire window when resized
  • CS_DBLCLKS - Send double-click messages
  • CS_OWNDC - Each window gets its own device context (for OpenGL)

The Message Loop Explained

The message loop is the heart of every Win32 application. Windows communicates with your application exclusively through messages, which are structures containing information about events:

typedef struct tagMSG {
    HWND   hwnd;       // Window receiving the message
    UINT   message;    // Message identifier (WM_PAINT, WM_KEYDOWN, etc.)
    WPARAM wParam;     // Additional info (meaning depends on message)
    LPARAM lParam;     // Additional info (meaning depends on message)
    DWORD  time;       // Time message was posted
    POINT  pt;         // Cursor position when message was posted
} MSG;
Win32 Message Loop Simulator
Visualize how Windows processes messages through GetMessage, TranslateMessage, and DispatchMessage.
Processed: 0

Message Queue

Click Start to begin

Message Loop

GetMessageW(&msg, ...)

Retrieve from queue

↓
TranslateMessage(&msg)

VK → WM_CHAR

↓
DispatchMessageW(&msg)

Send to WindowProc

WindowProc

Waiting for message...
WM_PAINT
WM_KEYDOWN
WM_MOUSEMOVE
WM_LBUTTONDOWN

The Standard Message Loop

MSG msg = {};
while (GetMessageW(&msg, NULL, 0, 0) > 0) {
    TranslateMessage(&msg);
    DispatchMessageW(&msg);
}

GetMessageW: Retrieves the next message from the thread's message queue. Blocks (waits) if no messages are available. Returns:

  • > 0: Message retrieved successfully
  • 0: WM_QUIT received (time to exit)
  • -1: Error occurred

TranslateMessage: Translates virtual-key messages (WM_KEYDOWN/WM_KEYUP) into character messages (WM_CHAR). Essential for text input.

DispatchMessageW: Sends the message to the appropriate window procedure (WindowProc).

Message Types

Messages fall into several categories:

System Messages (WM_):

  • WM_CREATE - Window is being created
  • WM_DESTROY - Window is being destroyed
  • WM_PAINT - Window needs repainting
  • WM_SIZE - Window was resized
  • WM_CLOSE - User requested to close window

Input Messages:

  • WM_KEYDOWN, WM_KEYUP - Keyboard input
  • WM_CHAR - Character input (after translation)
  • WM_MOUSEMOVE - Mouse movement
  • WM_LBUTTONDOWN, WM_RBUTTONDOWN - Mouse clicks

Custom Messages:

  • WM_USER through WM_USER + 0x7FFF - Reserved for application use
  • WM_APP through WM_APP + 0xBFFF - Safe for cross-application use

Posted vs. Sent Messages

Messages arrive via two mechanisms:

Posted Messages (asynchronous):

  • Added to the message queue via PostMessage
  • Processed in FIFO order by the message loop
  • The sender does not wait for processing

Sent Messages (synchronous):

  • Delivered directly via SendMessage
  • Bypass the queue—the window procedure is called immediately
  • The sender blocks until processing completes

This distinction matters for thread safety: SendMessage across threads can cause deadlocks if not handled carefully.

Modern C++ Patterns for Win32

Important Distinction: The Win32 API itself is a pure C interface. It doesn't know about classes, destructors, or exceptions. The patterns below (RAII, smart pointers) are C++ abstractions we build on top of Win32 to make it safer and easier to manage.

RAII for Windows Handles

Raw Win32 handles must be manually closed with functions like CloseHandle. In modern C++, we wrap these in RAII classes to ensure cleanup happens automatically, even if an exception is thrown:

RAII Handle Wrappercpp

Error Handling with std::expected (C++23)

Win32 functions typically return error codes or use GetLastError(). We can wrap this behavior using C++23's std::expected to create a more expressive, type-safe error handling mechanism:

Modern Error Handlingcpp

String Handling: std::wstring and Conversions

Windows internally uses UTF-16 (wide strings). Modern C++ makes handling these easier:

Unicode String Utilitiescpp

Understanding Window Styles

Window styles control appearance and behavior. They're combined using bitwise OR:

Primary Styles (WS_)

StyleDescription
WS_OVERLAPPEDWINDOWStandard resizable window with title, system menu, minimize/maximize
WS_POPUPPopup window, no frame
WS_CHILDChild window, must have parent
WS_VISIBLEInitially visible
WS_DISABLEDInitially disabled
WS_MINIMIZEDInitially minimized
WS_MAXIMIZEDInitially maximized

Extended Styles (WS_EX_)

Extended styles are passed as the first parameter to CreateWindowExW:

StyleDescription
WS_EX_TOPMOSTWindow stays on top of all non-topmost windows
WS_EX_LAYEREDEnables transparency and per-pixel alpha
WS_EX_TRANSPARENTClick-through window
WS_EX_TOOLWINDOWTool window (thin title bar, not in taskbar)
WS_EX_APPWINDOWForce taskbar button
Creating a Layered Transparent Windowcpp

Error Handling Best Practices

Win32 functions report errors in several ways. Understanding these patterns is crucial for robust code:

Pattern 1: Return Value + GetLastError

Most Win32 functions return a "failure" value (NULL, INVALID_HANDLE_VALUE, FALSE, 0) and set the thread-local error code:

HANDLE hFile = CreateFileW(L"nonexistent.txt", GENERIC_READ, 0, NULL,
                           OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if (hFile == INVALID_HANDLE_VALUE) {
    DWORD error = GetLastError();
    
    switch (error) {
        case ERROR_FILE_NOT_FOUND:
            // Handle file not found
            break;
        case ERROR_ACCESS_DENIED:
            // Handle permission denied
            break;
        default:
            // Log or display error
            break;
    }
}

Pattern 2: HRESULT Return Values

COM-based APIs return HRESULT codes directly:

#include <comdef.h>  // For _com_error

HRESULT hr = SomeComFunction();

if (FAILED(hr)) {
    _com_error err(hr);
    LPCTSTR errMsg = err.ErrorMessage();
    // Handle error
}

// Or check specific error codes
if (hr == E_OUTOFMEMORY) {
    // Handle out of memory
}

Pattern 3: Boolean with Output Parameter

Some functions return success/failure and provide additional details via output parameters:

DWORD bytesRead = 0;
BOOL success = ReadFile(hFile, buffer, bufferSize, &bytesRead, NULL);

if (!success) {
    // GetLastError() contains the error
} else if (bytesRead == 0) {
    // End of file
}

Practical Exercise: A Responsive Window

Let's put it all together with a window that responds to multiple input types:

Complete Responsive Window Examplecpp

This example demonstrates:

  • Storing per-window state using GWLP_USERDATA
  • Handling multiple input types (mouse, keyboard)
  • Using InvalidateRect to trigger repaints
  • Modern C++ string formatting with std::format
  • Proper resource cleanup in WM_DESTROY

Conclusion

In this first part, we've established the foundational knowledge for Windows development with C++. You now understand:

  • How to set up a proper Win32 development environment
  • The structure of a Windows GUI application (window class, creation, message loop)
  • How messages flow through the system and how to handle them
  • Modern C++ patterns that make Win32 programming safer and more maintainable

These concepts form the basis for everything that follows. The window procedure pattern, in particular, is the fundamental building block of all Windows GUI programming.


Next in Series: Part 2 will cover Windows GUI Programming in depth—creating controls (buttons, text boxes, list views), working with dialogs and resource files, and understanding GDI for custom drawing.

References and Further Reading

  • Microsoft Win32 Documentation - Official Win32 API reference
  • Windows SDK Samples - Official code samples
  • Programming Windows, 5th Edition - Charles Petzold's classic text
  • Windows Internals, 7th Edition - Deep dive into Windows architecture
  • C++ Core Guidelines - Modern C++ best practices

The concepts covered here apply directly to understanding how malware interacts with the Windows GUI subsystem, how tools like Process Explorer work under the hood, and how to build robust security tools that integrate with the Windows desktop environment.

Read Also

Technical visualization of Command and Control infrastructure
14 min read
December 14, 202514 min read

Command & Control in 2025: Architecture, Evasion & Operations

by Mohamed Habib Jaouadi

A technical deep dive into modern C2 architecture (Sliver, Havoc), evasion techniques (Shellter Elite, Stack Spoofing, AMSI Blinding), and alternative infrastructure (Discord C2, Cloud Redirectors).

#C2
#Malware Development
#Red Teaming
+3
Windows Protected Processes - Security Analysis and Inspection Tools
17 min read
November 22, 202517 min read

Windows Protected Processes Series: Part 1

by Mohamed Habib Jaouadi

Part 1 of the Windows Protected Processes series. Learn about protected processes, Process Explorer limitations, and why even administrators can't access critical system processes like CSRSS and LSASS.

#windows-protected-processes-series
#windows-internals
#process-inspection
+3
Windows Protected Processes Part 2 - Advanced Inspection and Security
33 min read
November 22, 202533 min read

Windows Protected Processes Series: Part 2

by Mohamed Habib Jaouadi

Advanced inspection techniques with Process Hacker, WinDbg kernel debugging, LSASS credential protection, BYOVD attacks, detection strategies, and system hardening for Windows protected processes.

#windows-protected-processes-series
#process-hacker
#windbg
+5
DNS Fundamentals and Security Analysis - DNS Security Series Part 1
20 min read
August 25, 202520 min read

DNS Security Analysis Series: Part 1 - DNS Fundamentals and Architecture

by Mohamed Habib Jaouadi

Deep dive into DNS architecture, record types, resolution process, and security analysis techniques for network defenders and DNS analysts.

#dns-security-series
#dns-analysis
#dns-forensics
+3
Network Architecture and Blue Team Defense Strategies
15 min read
August 7, 202515 min read

Enterprise Network Architecture for Blue Team Operations: Visibility, Segmentation, and Modern Defense Strategies

by Mohamed Habib Jaouadi

A guide to enterprise network architecture for blue team operations.

#blue-team
#network-architecture
#network-security
+5
Malware Development Series Part 3 - Detection and Windows Processes
16 min read
July 27, 202516 min read

Malware Development Series: Part 3

by Mohamed Habib Jaouadi

Detection mechanisms, Windows processes, threads, memory types, and the Process Environment Block (PEB) for security professionals.

#malware-development-series
#malware-detection
#windows-processes
+4
Statistics and Probability for Engineering Benchmarks
17 min read
July 14, 202517 min read

The Statistics You Learned in School but Never Applied

by Mohamed Habib Jaouadi

Bridge the gap between academic statistics and real-world engineering.

#performance
#statistics
#benchmarking
+2
Malware Development Series Part 2 - Memory Management and PE Analysis
18 min read
July 13, 202518 min read

Malware Development Series: Part 2

by Mohamed Habib Jaouadi

Windows memory management, API fundamentals, PE file format, and DLL mechanics for security professionals.

#malware-development-series
#windows-memory
#pe-format
+3
Malware Development Series - Security Research and Analysis
10 min read
July 7, 202510 min read

Malware Development Series: Part 1

by Mohamed Habib Jaouadi

Part 1 of the malware development series. Learn the fundamentals of ethical malware development, Windows architecture, and essential tools for penetration testers and red teams.

#malware-development-series
#ethical-hacking
#red-team
+3
The Enigma Machine
14 min read
July 5, 202514 min read

The Hill Cipher: Linear Algebra Meets Cryptography

by Mohamed Habib Jaouadi

Exploring the Hill cipher, a polygraphic substitution cipher that uses linear algebra and matrix operations for encryption and decryption.

#cryptography
#classical-ciphers
#linear-algebra
+2