In Windows, the graphics device interface (GDI) displays graphics and formatted text on both the screen and the printer. One of the primary goals of the GDI is to support a device-independent development environment. The GDI provides several hundred functions for drawing points, lines, rectangles, polygons, ellipses, bitmaps, and text-special objects such as pens and brushes to manipulate the appearance of graphical output. Pens define the style, thickness, and colour of the pixels drawn, while a brush determines the fill colour of a shape.

A device context always contains one pen, brush, font, and a series of values to control how the device context behaves. If the application requires a change to the device context such as a new pen, then this new pen must be created and selected into the device context. Selecting a new graphics object does not change pre-existing display elements but any new graphic output. Each time a new GDI object is opened, it consumes Windows resources. It therefore becomes important to release GDI objects after use.

Creating Pens

Pens are created and referred to by using a handle type definition HPEN. In addition to a limited number of pre-supplied stock pens, the programmer can define user-defined pens using the API function CreatePen(). The prototype of this function is

HPEN CreatePen(int iStyle,int cWidth,COLORREF color);

where –
iStyle – The pen style. It can be any one of the following values.
PS_SOLID – The pen is solid.
PS_DASH – The pen is dashed. This style is valid only when the pen width is one or less in device units.
PS_DOT – The pen is dotted. This style is valid only when the pen width is one or less in device units.
PS_DASHDOT – The pen has alternating dashes and dots. This style is valid only when the pen width is one or less in device units.
PS_DASHDOTDOT – The pen has alternating dashes and double dots. This style is valid only when the pen width is one or less in device units.
PS_NULL – The pen is invisible.
PS_INSIDEFRAME – The pen is solid. When this pen is used in any GDI drawing function that takes a bounding rectangle, the figure dimensions are shrunk so that it fits entirely in the bounding rectangle, taking into account the width of the pen. This applies only to geometric pens
cWidth – The width of the pen, in logical units. If nWidth is zero, the pen is a single pixel wide, regardless of the current transformation.
color – is a COLORREF that determines the pen colour.

If the function succeeds, the return value identifies a logical pen. If the function fails, the return value is NULL.

Creating a Brush

Brushes are used to fill in any closed objects. They have colour, style and can be bitmaps. Brushes are created and referred to by using a handle type definition HBRUSH. In addition to the pre-created stock brushes, programmers can define custom brushes using the API function CreateSolidBrush(). The prototype for this function is

HBRUSH CreateSolidBrush( COLORREF color);

Where color is a COLORREF value. If the function succeeds, the return value identifies a logical brush. If the function fails, the return value is NULL.

In addition to solid brushes, a programmer can create a pattern brush that fills the brush area with a bitmapped image and a hatchbrush that creates a specified hatch pattern and colour. The prototype for these two API functions are

HBRUSH CreatePatternBrush(NBITMAP hbmap);

Where hbmap is a handle to the bitmap used to create the logical brush. If the function succeeds, the return value identifies a logical brush. If the function fails, the return value is NULL.

HBRUSH CreateHatchBrush(int style,COLORREF color);

Where
style – is the hatch style of the brush and can be one of the following
HS_BDIAGONAL – 45-degree upward left-to-right hatch
HS_CROSS – Horizontal and vertical crosshatch
HS_DIAGCROSS – 45-degree crosshatch
HS_FDIAGONAL – 45-degree downward left-to-right hatch
HS_HORIZONTAL – Horizontal hatch
HS_VERTICAL – Vertical hatch
Color – is a COLORREF value.

If the function succeeds, the return value identifies a logical brush. If the function fails, the return value is NULL.

Selecting Objects

Before any graphics object can be used it is ‘selected’ into the current device context (DC). The new object will then replace the previous graphic object of the same type. The SelectionObject() API prototype function is

HGDIOBJ SelectObject(HDC hdc,HGDIOBJ h);

where hdc refers to the device context and h is a handle to the object to be selected. SelectObject will return a handle to the previous font which may be useful should the application need to use the previous selection.

The following shortcode segment creates a new brush and then selects it into the current device context

HBRUSH greenbrush; Greenbrush=CreateSolidBrush(RGB(0,255,0)); SelectObject(hdc, Greenbush)

For further reading
https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-selectobject

DeleteObject

The DeleteObject() function deletes a logical pen, brush, font, bitmap, region, or palette, freeing all system resources associated with the object and rendering the specified handle invalid. This is necessary as the system only has a finite amount of resources and failure to release the memory allocated reduces the remaining memory available. The syntax for this function is

BOOL DeleteObject(HGDIOBJ hobject);

Where hobject is a handle to a logical pen, brush, font, bitmap, region, or palette. If the function succeeds, the return value is nonzero. If the specified handle is invalid the return value is zero.

Using Stock Objects

When a window creates its first display device context, it comes with a limited number of pre-created graphics objects known as stock objects. These stock objects consist of pens, brushes, fonts, and palettes. The API function GetStockObjects() retrieves a handle to one of these stock objects. The prototype of this function is

HGDIOBJ GetStockObject(int i);

Where the parameter i can be one of the following values: BLACK_BRUSH, DKGRAY_BRUSH ,DC_BRUSH ,GRAY_BRUSH ,HOLLOW_BRUSH ,LTGRAY_BRUSH ,NULL_BRUSH ,WHITE_BRUSH ,BLACK_PEN ,DC_PEN ,NULL_PEN ,WHITE_PEN, ANSI_FIXED_FONT ,ANSI_VAR_FONT ,DEVICE_DEFAULT_FONT ,DEFAULT_GUI_FONT ,OEM_FIXED_FONT ,SYSTEM_FONT ,SYSTEM_FIXED_FONT , DEFAULT_PALETTE

If the function succeeds, the return value is a handle to the requested logical object. If the function fails, the return value is NULL

Since stock objects are pre-created system resources there is no need to delete the object handle once they are no longer required.

Dealing with Colour Values

The Windows graphics system uses RGB additive colour mixing to display colours. A computer screen combines individual pixels to form an image and each pixel consists of varying degrees of the primary colours red, green and blue. The term additive colour mixing comes from the fact that every RGB colour is made by combining varying amounts of these three basic colours. Since the Windows graphics system uses the 8-bit(0 to 255) RGB colour model this translates to 16,777,216 possible colours. The Windows API uses the COLORREF type to represent an RGB value as a 32-bit value. The GDI contains several macros to combine RGB values into a 32-bit value and to turn a COLORREF data value into its RGB components –

//converts rgb to colourref value
COLORREF RGB(BYTE byRed, BYTE byGreen, BYTE byBlue);
//converts colourref value to RGB equivalent
int iRed= GetRValue(COLORREF rgb);
int iGreen =GetGValue(COLORREF rgb);
int iBlue =GetBValue(COLORREF rgb);