Skip to content

Windows.h (Win32 API)

C and C++ Windows programming quick reference from message boxes and basic windows to multi-threading, file I/O, custom drawing, and COM basics.

#include <windows.h> // Main Win32 API header — includes everything
#include <stdio.h> // Standard I/O (optional but useful)

#include <windows.h>
int main() {
// MessageBoxA = ASCII version, MessageBoxW = Wide (Unicode)
// Args: (parent window, message, title, buttons/icon flags)
MessageBoxA(NULL, "Hello, World!", "My First Window", MB_OK | MB_ICONINFORMATION);
return 0;
}

// Win32 defines its own types — always prefer these in Win32 code
BOOL flag = TRUE; // Basically int (TRUE=1, FALSE=0)
DWORD val = 0xFFFFFFFF; // Unsigned 32-bit integer
WORD small = 0xFFFF; // Unsigned 16-bit integer
BYTE b = 0xFF; // Unsigned 8-bit integer
HANDLE h = NULL; // Generic opaque object handle
HWND hwnd = NULL; // Handle to a Window
HINSTANCE hInst = NULL; // Handle to a module/instance
LPSTR str = "hello"; // Long Pointer to char (ASCII string)
LPCSTR cstr = "const"; // Long Pointer to const char
LPWSTR wstr = L"wide"; // Long Pointer to wide char (Unicode)

TCHAR buf[256];
// lstrlen — length of a Win32 string
int len = lstrlen(TEXT("Hello")); // TEXT() macro handles A/W automatically
// lstrcpy — copy a string
lstrcpy(buf, TEXT("Hello Win32"));
// lstrcmp — compare strings (0 = equal)
if (lstrcmp(buf, TEXT("Hello Win32")) == 0) {
// Strings are equal
}
// wsprintf — safe sprintf for Win32 (no floats)
wsprintf(buf, TEXT("Value: %d"), 42);

HANDLE h = CreateFile(TEXT("missing.txt"), GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError(); // Retrieve the last Win32 error code
// Common codes: 2 = FILE_NOT_FOUND, 5 = ACCESS_DENIED
printf("Error: %lu\\n", err);
}

// Attach or allocate a console window
AllocConsole(); // Creates a new console for the process
// Write to console via standard handle
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); // Get stdout handle
DWORD written;
WriteConsole(hOut, TEXT("Hello Console\\n"), 14, &written, NULL);

#include <windows.h>
// Window Procedure — handles messages sent to the window
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_DESTROY:
PostQuitMessage(0); // Signal the message loop to exit
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam); // Default handling
}
return 0;
}
// Entry point for GUI apps (instead of main)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmd, int nShow) {
// Step 1: Register the window class
WNDCLASS wc = {0};
wc.lpfnWndProc = WndProc; // Assign our message handler
wc.hInstance = hInstance;
wc.lpszClassName = TEXT("MyWindow");
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // White background
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Standard arrow cursor
RegisterClass(&wc);
// Step 2: Create the window
HWND hwnd = CreateWindow(
TEXT("MyWindow"), // Class name (must match RegisterClass)
TEXT("My App"), // Window title
WS_OVERLAPPEDWINDOW, // Style flags (title bar, borders, etc.)
100, 100, // X, Y position
800, 600, // Width, Height
NULL, NULL, hInstance, NULL
);
ShowWindow(hwnd, nShow); // Make it visible
UpdateWindow(hwnd); // Force a WM_PAINT
// Step 3: Message loop — keeps app alive and processes events
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg); // Translate virtual keys to WM_CHAR
DispatchMessage(&msg); // Send message to WndProc
}
return (int)msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CREATE:
// Called once when the window is first created — good for init
break;
case WM_PAINT: {
// Called when window needs to be redrawn
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps); // Get device context for painting
TextOut(hdc, 10, 10, TEXT("Hello from WM_PAINT"), 19);
EndPaint(hwnd, &ps); // Always pair with BeginPaint
break;
}
case WM_KEYDOWN:
// wParam holds the virtual key code (e.g., VK_ESCAPE, VK_RETURN)
if (wParam == VK_ESCAPE) PostQuitMessage(0);
break;
case WM_LBUTTONDOWN:
// Mouse left button clicked
// LOWORD(lParam) = X, HIWORD(lParam) = Y
MessageBox(hwnd, TEXT("Clicked!"), TEXT("Mouse"), MB_OK);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}

// Create controls inside WM_CREATE using CreateWindow
case WM_CREATE: {
// Button control
CreateWindow(TEXT("BUTTON"), TEXT("Click Me"),
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
50, 50, 120, 30, // x, y, width, height
hwnd, (HMENU)1, // Parent, control ID
hInstance, NULL);
// Single-line text input
CreateWindow(TEXT("EDIT"), TEXT(""),
WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL,
50, 100, 200, 25,
hwnd, (HMENU)2, hInstance, NULL);
// Static label
CreateWindow(TEXT("STATIC"), TEXT("Enter text:"),
WS_VISIBLE | WS_CHILD,
50, 80, 100, 20,
hwnd, (HMENU)3, hInstance, NULL);
break;
}
// Handle button click via WM_COMMAND
case WM_COMMAND:
if (LOWORD(wParam) == 1) { // Control ID 1 = Button
// BN_CLICKED is in HIWORD(wParam), but for buttons just match ID
TCHAR buf[256];
GetDlgItemText(hwnd, 2, buf, 256); // Read text from edit control ID 2
MessageBox(hwnd, buf, TEXT("You typed:"), MB_OK);
}
break;

// --- Write to a file ---
HANDLE hFile = CreateFile(
TEXT("output.txt"), // Filename
GENERIC_WRITE, // Access mode
0, // No sharing
NULL, // Default security
CREATE_ALWAYS, // Overwrite if exists
FILE_ATTRIBUTE_NORMAL, // Normal file
NULL
);
if (hFile != INVALID_HANDLE_VALUE) {
const char* data = "Hello File!";
DWORD written;
WriteFile(hFile, data, lstrlenA(data), &written, NULL);
CloseHandle(hFile); // Always close handles when done
}
// --- Read from a file ---
hFile = CreateFile(TEXT("output.txt"), GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
char buf[256] = {0};
DWORD bytesRead;
ReadFile(hFile, buf, sizeof(buf) - 1, &bytesRead, NULL);
printf("Read: %s\\n", buf);
CloseHandle(hFile);
}

// Set a timer with ID=1, fires every 1000ms (1 second)
SetTimer(hwnd, 1, 1000, NULL);
// Handle in WndProc
case WM_TIMER:
if (wParam == 1) {
// Called every second — update UI, check state, etc.
InvalidateRect(hwnd, NULL, TRUE); // Trigger repaint
}
break;
// Stop the timer when no longer needed
KillTimer(hwnd, 1);

HKEY hKey;
// --- Write a registry value ---
// Opens or creates a subkey under HKCU
RegCreateKeyEx(HKEY_CURRENT_USER, TEXT("Software\\\\MyApp"),
0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL);
DWORD val = 42;
RegSetValueEx(hKey, TEXT("MyValue"), 0, REG_DWORD,
(BYTE*)&val, sizeof(val)); // Write DWORD value
RegCloseKey(hKey);
// --- Read a registry value ---
RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\\\MyApp"),
0, KEY_READ, &hKey);
DWORD data, size = sizeof(data);
RegQueryValueEx(hKey, TEXT("MyValue"), NULL, NULL,
(BYTE*)&data, &size); // Read into 'data'
RegCloseKey(hKey);
printf("Registry value: %lu\\n", data);

// Thread function — must match LPTHREAD_START_ROUTINE signature
DWORD WINAPI MyThread(LPVOID lpParam) {
int* val = (int*)lpParam; // Cast the parameter
printf("Thread got: %d\\n", *val);
return 0; // Exit code
}
int data = 99;
HANDLE hThread = CreateThread(
NULL, // Default security
0, // Default stack size
MyThread, // Thread function
&data, // Parameter passed to thread
0, // Run immediately (use CREATE_SUSPENDED to delay)
NULL // Don't need thread ID
);
WaitForSingleObject(hThread, INFINITE); // Block until thread finishes
CloseHandle(hThread);

// Create a named mutex — prevents multiple instances or race conditions
HANDLE hMutex = CreateMutex(NULL, FALSE, TEXT("MyAppMutex"));
if (GetLastError() == ERROR_ALREADY_EXISTS) {
// Another instance is already running
MessageBox(NULL, TEXT("Already running!"), TEXT("Error"), MB_OK);
return 1;
}
// Acquire the mutex (lock) — waits up to 5 seconds
WaitForSingleObject(hMutex, 5000);
// --- Critical section (shared resource access) ---
// ... do thread-safe work here ...
ReleaseMutex(hMutex); // Release the lock
CloseHandle(hMutex);

15. Critical Sections (Faster than Mutex for same-process)

Section titled “15. Critical Sections (Faster than Mutex for same-process)”
CRITICAL_SECTION cs;
InitializeCriticalSection(&cs); // Init once at startup
// In each thread, wrap shared data access:
EnterCriticalSection(&cs); // Lock — only one thread enters at a time
// ... access shared data safely ...
LeaveCriticalSection(&cs); // Unlock
DeleteCriticalSection(&cs); // Cleanup on exit

STARTUPINFO si = {0};
PROCESS_INFORMATION pi = {0};
si.cb = sizeof(si); // Must set this field
// Launch notepad.exe as a child process
BOOL ok = CreateProcess(
NULL, // No module name (use command line)
TEXT("notepad.exe"), // Command line
NULL, NULL, // Process/Thread security attributes
FALSE, // Don't inherit handles
0, // Normal priority
NULL, // Use parent's environment
NULL, // Use parent's working directory
&si, &pi
);
if (ok) {
WaitForSingleObject(pi.hProcess, INFINITE); // Wait for it to finish
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}

17. Memory Mapped Files (Shared Memory Between Processes)

Section titled “17. Memory Mapped Files (Shared Memory Between Processes)”
// Process A — create and write
HANDLE hMap = CreateFileMapping(
INVALID_HANDLE_VALUE, // Use paging file (not a real file)
NULL,
PAGE_READWRITE,
0, 256, // Max size: 256 bytes
TEXT("MySharedMem") // Named so other processes can open it
);
LPVOID pBuf = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 256);
CopyMemory(pBuf, "Hello from A!", 14); // Write to shared memory
// Process B — open and read
HANDLE hMap2 = OpenFileMapping(FILE_MAP_READ, FALSE, TEXT("MySharedMem"));
LPVOID pBuf2 = MapViewOfFile(hMap2, FILE_MAP_READ, 0, 0, 256);
printf("Shared: %s\\n", (char*)pBuf2);
// Cleanup
UnmapViewOfFile(pBuf); CloseHandle(hMap);
UnmapViewOfFile(pBuf2); CloseHandle(hMap2);

HHOOK hHook;
// Callback for low-level keyboard events
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION) {
KBDLLHOOKSTRUCT* kb = (KBDLLHOOKSTRUCT*)lParam;
if (wParam == WM_KEYDOWN) {
printf("Key pressed: %lu\\n", kb->vkCode);
}
}
return CallNextHookEx(hHook, nCode, wParam, lParam); // MUST call this!
}
// Install the hook
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, NULL, 0);
// Run message loop to keep hook alive
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg);
// Remove hook when done
UnhookWindowsHookEx(hHook);

case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
// Draw a filled rectangle
HBRUSH hBrush = CreateSolidBrush(RGB(0, 120, 215)); // Blue brush
RECT rc = {50, 50, 200, 150};
FillRect(hdc, &rc, hBrush);
DeleteObject(hBrush); // Always delete GDI objects!
// Draw a line
MoveToEx(hdc, 0, 0, NULL); // Move pen to (0,0)
LineTo(hdc, 300, 300); // Draw line to (300,300)
// Draw text with custom font
HFONT hFont = CreateFont(24, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH, TEXT("Arial"));
SelectObject(hdc, hFont); // Apply font to DC
SetTextColor(hdc, RGB(255,255,255));
SetBkMode(hdc, TRANSPARENT); // Transparent text background
TextOut(hdc, 60, 90, TEXT("Win32 GDI"), 9);
DeleteObject(hFont);
EndPaint(hwnd, &ps);
break;
}

// Save original WndProc of a control (e.g., an EDIT box)
WNDPROC OldEditProc;
LRESULT CALLBACK SubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
if (msg == WM_KEYDOWN && wParam == VK_RETURN) {
MessageBox(hwnd, TEXT("Enter pressed in edit!"), TEXT(""), MB_OK);
return 0; // Eat the message
}
// Pass everything else to the original handler
return CallWindowProc(OldEditProc, hwnd, msg, wParam, lParam);
}
// Subclass the edit control
HWND hEdit = CreateWindow(TEXT("EDIT"), ..., hwnd, (HMENU)2, hInstance, NULL);
OldEditProc = (WNDPROC)SetWindowLongPtr(hEdit, GWLP_WNDPROC, (LONG_PTR)SubclassProc);

#include <windows.h>
#include <shobjidl.h> // IFileOpenDialog
// COM must be initialized before use
CoInitialize(NULL);
IFileOpenDialog* pDialog = NULL;
// Create a COM object (File Open Dialog)
CoCreateInstance(&CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER,
&IID_IFileOpenDialog, (void**)&pDialog);
pDialog->lpVtbl->Show(pDialog, NULL); // Show the dialog
IShellItem* pItem = NULL;
pDialog->lpVtbl->GetResult(pDialog, &pItem); // Get selected file
PWSTR filePath;
pItem->lpVtbl->GetDisplayName(pItem, SIGDN_FILESYSPATH, &filePath);
// filePath now holds the selected file path (wide string)
CoTaskMemFree(filePath); // Free COM-allocated string
pItem->lpVtbl->Release(pItem); // Release COM objects when done
pDialog->lpVtbl->Release(pDialog);
CoUninitialize(); // Cleanup COM

22. Useful Macros & Helpers Quick Reference

Section titled “22. Useful Macros & Helpers Quick Reference”
// ---- Bit manipulation helpers ----
LOWORD(0xABCD1234) // → 0x1234 (lower 16 bits) — used for coords/IDs
HIWORD(0xABCD1234) // → 0xABCD (upper 16 bits)
MAKELONG(lo, hi) // Combine two WORDs into a DWORD
// ---- Window helpers ----
GetClientRect(hwnd, &rc); // Get window's inner drawable area
SetWindowText(hwnd, TEXT("New Title")); // Change window title
GetWindowText(hwnd, buf, 256); // Read window title
EnableWindow(hwnd, FALSE); // Disable/grey out a control
ShowWindow(hwnd, SW_HIDE); // Hide a window
InvalidateRect(hwnd, NULL, TRUE); // Force window to repaint
// ---- Screen/cursor ----
GetCursorPos(&pt); // Get mouse position on screen
ScreenToClient(hwnd, &pt); // Convert screen → window coordinates
GetSystemMetrics(SM_CXSCREEN); // Screen width in pixels
GetSystemMetrics(SM_CYSCREEN); // Screen height in pixels
// ---- Module/path ----
GetModuleFileName(NULL, buf, 256); // Path of current .exe
GetCurrentDirectory(256, buf); // Current working directory
SetCurrentDirectory(TEXT("C:\\\\")); // Change working directory
// ---- Timing ----
DWORD t = GetTickCount(); // Milliseconds since system boot (32-bit wraps)
ULONGLONG t2 = GetTickCount64(); // 64-bit version — no wrap issues
Sleep(1000); // Pause thread for 1000ms

FlagMeaning
MB_OKMessage box with OK button
MB_YESNOYes/No buttons
MB_ICONERRORError icon
MB_ICONWARNINGWarning icon
WS_OVERLAPPEDWINDOWStandard window with title/borders
WS_CHILDChild control (inside another window)
WS_VISIBLEMake visible immediately
`CS_HREDRAW \CS_VREDRAW`
VK_ESCAPEEscape virtual key
VK_RETURNEnter virtual key
GENERIC_READOpen file for reading
GENERIC_WRITEOpen file for writing
CREATE_ALWAYSCreate/overwrite file
OPEN_EXISTINGOpen only if exists

Built for Win32 C/C++ development. Compile with -luser32 -lgdi32 -lkernel32 or use Visual Studio / MinGW.