In Windows, the graphics device interface (GDI) is responsible for displaying graphics and formatted text on both the screen and the printer. One of the primary goals of 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, and to manipulate the appearance of this graphical output, special objects such as pens and brushes. 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, one brush, one font, and a series of other 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 change any pre-existing display elements but only any new graphic output. Each time a new window is opened, it consumes GDI resources. It, therefore, becomes important to release GDI objects after use.
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 their own pens using the API function call 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 dimensions of the figure 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 color.
If the function succeeds, the return value identifies a logical pen. If the function fails, the return value is NULL.
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 their own custom brushes by 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 also create a pattern brush that fills the brush area with a bitmapped image and a hatch brush which 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 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.
Before any graphics object can be used it must be ‘selected’ into the current device context (DC). The new object will then replace the previous graphic object of the same type. The prototype of the SelectionObject() API 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 short code segment creates a brush fills it with colour 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
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 memory allocated reduces the amount of remaining memory available to the system. 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 however, the specified handle is not valid the return value is zero
When a window creates its first display device context, it comes with a limited number of pre-created graphics objects known as stock objects for changing the display output. 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.
The Windows graphics system normally uses the RGB color model to specify colour values. The colour values will be made up of a combination of red, green, and blue using values from 0 to 255 to specify the brightness of each colour component. The Windows API uses the COLORREF type to represent an RGB value as a single 32-bit value. The GDI contains several macros to combine RGB values into a single 32 big value and to turn a COLORREF data 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 =BYTE GetBValue(COLORREF rgb);