Introduction

Welcome back to Drawing with Windows GDI. We are now in Lesson 2, which means we already understand the basic paint cycle and are ready to make our drawings look much better. Last time, we focused on where drawing happens; this time, we will focus on how shapes look once they are drawn.

By the end of this lesson, we will style GDI shapes with a custom pen for the outline and a custom brush for the fill. Just as importantly, we will learn the safe pattern for using these tools inside a Device Context, so our code stays correct and tidy.

Why GDI Uses Pens And Brushes

Before we return to the code, it helps to build the right mental model. In GDI, a shape usually has two visual parts: its border and its interior area. These are controlled by separate tools.

  1. A pen draws the outline.
  2. A brush fills the interior.
  3. The Device Context, or HDC, remembers which pen and brush are currently active.

So, when we call a function like Rectangle or Ellipse, we usually do not pass colors directly. Instead, we first choose the active pen and brush in the HDC; then, the shape uses those settings automatically. This is the key idea for the whole lesson.

Reentering The Paint Cycle

As you may recall from the previous lesson, drawing belongs inside WM_PAINT. That part does not change. We still include the Windows API header, enter the window procedure, and begin painting by asking Windows for a valid drawing surface.

Several familiar components perform essential tasks here. #include <windows.h> provides access to types like HDC, HPEN, and HBRUSH. WindowProc remains the message handler for the window, and WM_PAINT is still the correct place for rendering. Finally, BeginPaint prepares the client area and returns the hdc that all GDI drawing functions will use.

Creating A Custom Outline And Fill

Now, we create the styling tools themselves. This is the first new step in the lesson: instead of accepting the default look, we build our own pen and brush.

CreatePen creates a pen with three settings: PS_SOLID specifies a continuous line; 5 sets the line width; and RGB(255, 0, 0) makes that line red. CreateSolidBrush creates a brush that fills with a single solid color, in this case, blue.

The RGB macro combines red, green, and blue channel values, where each value must satisfy 0c2550 \le c \le 255. Therefore, RGB(255, 0, 0) is full red, and RGB(0, 0, 255) is full blue.

Selecting Objects Into The Device Context

Creating a pen or brush is not enough on its own. GDI will only use them after we place them into the HDC. That is what SelectObject does.

This code swaps the current drawing tools in the hdc. After these calls, the device context is configured to draw with our red outline and blue fill. A subtle but very important detail is that SelectObject returns the previous object. We save those handles in hOldPen and hOldBrush so that we can restore them later.

The casts, (HPEN) and (HBRUSH), make the returned handle type clear in C++.

Drawing With The Current Style

With the custom pen and brush selected, the shape functions now use them automatically. The coordinates are the same types we used in the previous lesson, but the visual result is quite different because the active GDI tools have changed.

Rectangle draws a bordered rectangle and fills its interior. Ellipse does the same for an oval shape inside its bounding box. Since both calls use the same hdc, both shapes share the same styling: a thick red outline and a blue fill.

This is a useful pattern to remember: the shape functions define the geometry, while the selected pen and brush define the appearance.

Restoring And Releasing Resources

Once the drawing is complete, we must clean up in the correct order. This is one of the most important practices in GDI programming because pens and brushes are operating system resources.

There are three steps here:

  1. Restore the old pen and brush to the hdc.
  2. Delete only the objects we created, namely hRedPen and hBlueBrush.
  3. Finish the paint cycle with EndPaint.

Failing to delete these objects leads to a GDI Leak. Windows uses a limited internal "heap" for these handles. If a program draws in a loop—such as during a window resize—and creates tools without deleting them, it will eventually exhaust those resources. This can cause the application to stop rendering correctly, or even cause the entire Windows UI to glitch and crash.

The comment is worth taking seriously: we should always restore objects before deleting them. Also, notice what we do not delete: hOldPen and hOldBrush. We did not create those objects, so they are not ours to destroy.

Conclusion and Next Steps

In this lesson, we extended the basic paint cycle into something more expressive. We created a custom HPEN and HBRUSH, selected them into the HDC, drew a rectangle and an ellipse with those active tools, and then restored the original objects and freed the ones we created. That full lifecycle is the core pattern for styling with GDI.

With this foundation in place, we are ready to practice; the next exercises will help us apply styles confidently and build the cleanup habits that make GDI code reliable.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal