Win32 - Drawing Rectangles (C/C++)
How to draw a rectangle using Windows API.
Updated Jun 28, 2022

main.cpp
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#include <windows.h>
#include <stdint.h>
typedef uint32_t u32;
void* BitmapMemory;
int BitmapWidth;
int BitmapHeight;
int ClientWidth;
int ClientHeight;
// Draws a pixel at X, Y (from top left corner)
void DrawPixel(int X, int Y, u32 Color) {
u32 *Pixel = (u32 *)BitmapMemory;
Pixel += Y * BitmapWidth + X;
*Pixel = Color;
}
void ClearScreen(u32 Color) {
u32 *Pixel = (u32 *)BitmapMemory;
for(int Index = 0;
Index < BitmapWidth * BitmapHeight;
++Index) { *Pixel++ = Color; }
}
void DrawRectangle(int RectangleX,
int RectangleY,
int RectangleWidth,
int RectangleHeight,
u32 Color) {
u32 *Pixel = (u32 *)BitmapMemory;
Pixel += RectangleY * BitmapWidth + RectangleX;
for(int Y = 0; Y < RectangleHeight; ++Y) {
for(int X = 0;
X < RectangleWidth;
++X) { *Pixel++ = Color; }
Pixel += BitmapWidth - RectangleWidth;
}
}
LRESULT CALLBACK WindowProc(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam) {
switch(Message) {
case WM_KEYDOWN: {
switch(WParam) { case 'O': { DestroyWindow(Window); }; }
} break;
case WM_DESTROY: { PostQuitMessage(0); } break;
default: { return DefWindowProc(Window, Message, WParam, LParam); }
}
return 0;
}
int WINAPI wWinMain(HINSTANCE Instance, HINSTANCE PrevInstance, PWSTR CmdLine, int CmdShow) {
WNDCLASS WindowClass = {};
const wchar_t ClassName[] = L"MyWindowClass";
WindowClass.lpfnWndProc = WindowProc;
WindowClass.hInstance = Instance;
WindowClass.lpszClassName = ClassName;
WindowClass.hCursor = LoadCursor(0, IDC_CROSS);
if(!RegisterClass(&WindowClass)) {
MessageBox(0, L"RegisterClass failed", 0, 0);
return GetLastError();
}
HWND Window = CreateWindowEx(0, ClassName, L"Program",
WS_OVERLAPPEDWINDOW|WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
0, 0, Instance, 0);
if(!Window) {
MessageBox(0, L"CreateWindowEx failed", 0, 0);
return GetLastError();
}
// Get client area dimensions
RECT ClientRect;
GetClientRect(Window, &ClientRect);
ClientWidth = ClientRect.right - ClientRect.left;
ClientHeight = ClientRect.bottom - ClientRect.top;
BitmapWidth = ClientWidth;
BitmapHeight = ClientHeight;
// Allocate memory for the bitmap
int BytesPerPixel = 4;
BitmapMemory = VirtualAlloc(0,
BitmapWidth * BitmapHeight * BytesPerPixel,
MEM_RESERVE|MEM_COMMIT,
PAGE_READWRITE
);
// BitmapInfo struct for StretchDIBits
BITMAPINFO BitmapInfo;
BitmapInfo.bmiHeader.biSize = sizeof(BitmapInfo.bmiHeader);
BitmapInfo.bmiHeader.biWidth = BitmapWidth;
// Negative height makes top left as the coordinate system origin for the DrawPixel function, otherwise its bottom left
BitmapInfo.bmiHeader.biHeight = -BitmapHeight;
BitmapInfo.bmiHeader.biPlanes = 1;
BitmapInfo.bmiHeader.biBitCount = 32;
BitmapInfo.bmiHeader.biCompression = BI_RGB;
HDC DeviceContext = GetDC(Window);
bool Running = true;
while(Running) {
MSG Message;
while(PeekMessage(&Message, nullptr, 0, 0, PM_REMOVE)) {
if(Message.message == WM_QUIT) Running = false;
TranslateMessage(&Message);
DispatchMessage(&Message);
}
ClearScreen(0x333333);
DrawRectangle(100, 100, 64, 64, 0xff00ff);
StretchDIBits(DeviceContext,
0, 0,
BitmapWidth, BitmapHeight,
0, 0,
ClientWidth, ClientHeight,
BitmapMemory, &BitmapInfo,
DIB_RGB_COLORS, SRCCOPY);
}
return 0;
}
Build
cl main.cpp /link user32.lib gdi32.lib
build.bat
@echo off
set COMMON_COMPILER_FLAGS=/W4 /wd4100 /Oi /nologo /Fegame.exe
set DEBUG_FLAGS=/Zi /MTd
set RELEASE_FLAGS=/O2
set COMPILER_FLAGS=%COMMON_COMPILER_FLAGS% %DEBUG_FLAGS%
REM set COMPILER_FLAGS=%COMMON_COMPILER_FLAGS% %RELEASE_FLAGS%
set LINKER_FLAGS=/INCREMENTAL:NO /OPT:REF
set LIBS=user32.lib gdi32.lib
cl %COMPILER_FLAGS% main.cpp /link %LINKER_FLAGS% %LIBS%