Your browser doesn't support JavaScript api – Windows Programming

Common Controls

In addition to standard controls, Windows offers an extended set of child controls known as common controls that can further enhance interaction with the user. To use these common controls, an application must include the header file commctrl.h and call the function InitCommonControlsEx() to ensure that the appropriate components are loaded and initialised. This is necessary because common controls are not referenced in the standard Windows header files.

The prototype for the InitCommonControlsEx() API function is

BOOL InitCommonControlsEx (INITCOMMONCONTROLSEX const *picce);

Where *picce is a pointer to an INITCOMMONCONTROLSEX structure that determines which control classes will be registered.

The function will return TRUE if successful, or FALSE otherwise.

The prototype of theINITCOMMONCONTROLSEX structure is

typedef struct tagINITCOMMONCONTROLSEX {DWORD dwSize;DWORD dwICC;} INITCOMMONCONTROLSEX, *LPINITCOMMONCONTROLSEX;

where 
dwSize indicates the size of the structure, in bytes
wICC indicates which common control classes will be loaded from the DLL.

Common Controls List

Animation Control

The Animation control is a Windows common control that allows an application to display AVI (Audio Video Interleave) animation clips within a window. Animation controls are designed for simple visual feedback and can only display AVI files that do not contain audio streams.

A common use of an animation control is to provide the user with an indication that a lengthy operation is currently being performed. For example, during file operations, an application may display a small animated sequence to show that processing is taking place. A well-known example was the Windows XP file copy animation, where animated sheets of paper appeared to move between folders while files were being copied.

The animation control does not play AVI files like a full media player. Instead, it is intended for short, repetitive animations that provide status information or improve the user interface.

animate control

For further reading – https://docs.microsoft.com/en-us/windows/win32/controls/animation-control-reference

The following example demonstrates the flying folder avi animation


ComboBoxEx Control

The ComboBoxEx control is an extended version of the standard Windows combo box control. It provides all the normal features of a combo box while adding additional functionality, most notably native support for images associated with list items.

Unlike a standard combo box, where each item consists only of text, a ComboBoxEx control allows each item in the drop-down list to contain:

  • A text label.
  • An image displayed beside the text.
  • A selected image that can be shown when the item is chosen.

The images are normally stored in an image list (HIMAGELIST) and are associated with individual items using the ComboBoxEx item structure.

comboxex control


For further reading https://docs.microsoft.com/en-us/windows/win32/controls/comboboxex-control-reference

The following example creates a comboboxex control with 5 items. Each item has an associated bitmap image. Changing the selected item copies the text and icon to a static control.


Date and Time Picker

A Date and Time Picker (DTP) control provides a convenient graphical interface for entering or selecting dates and times. Rather than typing a value manually, the user can click the drop-down arrow to display a monthly calendar and choose a date. The control also allows the date and time to be adjusted using the keyboard or up/down arrow keys. The appearance and display format of the control can be customised using format strings, allowing applications to display dates in a variety of regional or application-specific formats.

data and time picker


For further reading https://docs.microsoft.com/en-us/windows/win32/controls/date-and-time-picker-control-reference

The following short program demonstrates the date-picker control. Changing the date or time causes the static box to be updated with the selected date and time.


Header Control

A header control is a selectable horizontal child window used to display column headings above rows of data. It is commonly used with controls such as ListView, ListBox, and user-defined list windows to identify the contents of each column. Each header consists of one or more sections (items), with each section representing the title of a column. Users can resize columns by dragging the dividers between sections, allowing the width of individual columns to be adjusted.

header control picture


For further reading https://docs.microsoft.com/en-us/windows/win32/controls/header-control-reference

The following short program creates a simple window with 2 header controls. Clicking either will trigger a message box.


Hot Key Control

A hot key control allows the user to define a keyboard shortcut by pressing a combination of keys directly into the control. The control automatically interprets the key combination and displays it in a standard Windows format, making it easy for users to assign or modify keyboard shortcuts within an application.

A hot key consists of a virtual key code combined with one or more modifier keys such as Ctrl, Alt, Shift, or the Windows key. The control validates the key combination as it is entered and can restrict invalid or undesirable combinations through application-defined rules.

The selected hot key can be retrieved programmatically and stored for later use. Applications commonly register the selected key combination using the Windows RegisterHotKey() API function, allowing the shortcut to invoke commands even when the application window is not active.

Unlike a standard edit control, a hot key control does not accept arbitrary text input. Instead, it captures keyboard input and automatically formats the pressed key combination using

header control picture

The following short program creates a hot key control


IP Address Control

The IP Address Control provides a specialised edit control for entering and displaying IPv4 addresses in the familiar dotted-decimal format.

Unlike a standard edit control, the IP Address control automatically divides the address into four separate numeric fields called octets. Each field accepts values only in the range 0 to 255, preventing invalid IP addresses from being entered. The control automatically moves the keyboard focus between fields as the user types, making address entry quick and intuitive.

Applications typically use the control wherever users must enter IP addresses, such as network configuration utilities, communication programs, router setup software, and server management tools.

The control validates each field as the user types, ensuring that only valid numeric values are entered. When the application needs the address, it simply retrieves the four octets and combines them into a single IP address.

header control picture


The following example creates a simple IP address control


Listview

A List-View control is a common control provided by Windows that displays a collection of items. Unlike a standard ListBox, a List-View can present items in several different visual styles and can display additional information through columns and subitems.

The List-View control supports four main display modes:

Icon View
Small Icon View
List View
Report View

Allows additional information to be shown using subitems.

listview control picture


For further reading https://docs.microsoft.com/en-us/windows/win32/controls/list-view-control-reference

The following example creates a simple listview with 4 items. Changing the selected value will copy the contents of the first column into the static box


Month Calendar Control

The month calendar control provides an intuitive method of entering or selecting a date. The title bar contains two buttons that allow the user to select the previous /next month.

calendar control picture


For further reading https://docs.microsoft.com/en-us/windows/win32/controls/month-calendar-control-reference

 The following example creates a simple calendar control. Changing the date updates the static box


Pager Control

A Pager control is a Windows common control that provides scrolling buttons around a child window when the child window is larger than the available display area. It is commonly used with controls such as toolbars, headers, and tab controls.

The pager control does not scroll the child window itself. Instead, it sends notifications to the parent window and moves the child window when the user presses the scroll buttons.

page scroller control picture


For further reading https://docs.microsoft.com/en-us/windows/win32/controls/pager-control-reference

In the following example, a page controller encloses the toolbar.


Progress Bar

A progress bar is a graphical control used to indicate the progress of a lengthy operation, such as copying files, downloading data, or installing software. It provides visual feedback by displaying a bar that gradually fills as the operation advances. The control can operate in either determinate mode, where the percentage of completion is known, or indeterminate (marquee) mode, where the exact progress is unknown but activity is shown to reassure the user that the application is still working. Progress bars help improve the user experience by providing a clear indication of how much of a task has been completed and how much remains.

progress bar control picture


For further reading https://docs.microsoft.com/en-us/windows/win32/controls/create-progress-bar-controls

In the example below, a timer function increments a progress bar control.


Rebar Control

A rebar control is a container window that organizes one or more child windows into separate sections called bands. Each band can host a single child window, such as a toolbar, combo box, edit box, or other control. The user can reposition or resize these bands by dragging their gripper bars, allowing the interface to be customised. In addition to the child window, each rebar band can optionally display a gripper, a bitmap, a text label, and other visual elements, making the rebar control a flexible way to create movable and dockable user interface layouts.

rebar control picture


For further reading https://docs.microsoft.com/en-us/windows/win32/controls/rebar-controls

The following example demonstrates the rebar control acting as a container for both a button and a textbox.


Rich Edit Control

A Rich Edit control is an enhanced text editing control that allows users to enter, edit, and display formatted text. Unlike a standard edit control, a Rich Edit control supports multiple fonts, font sizes, colours, and text styles such as bold, italic, and underline within the same document. It also provides paragraph formatting, including different alignments, indentation, and tab settings, and can contain embedded objects such as images or OLE objects. Rich Edit controls are commonly used in applications that require basic word-processing capabilities, such as text editors, email clients, and note-taking programs.


For further reading https://docs.microsoft.com/en-us/windows/win32/controls/rich-edit-controls

The following example is a simple rich text box offering italic bold and underline formatting options


Status Bar

A status bar is a horizontal window, typically displayed at the bottom of an application window, that is used to display information about the current application. Status bars are often divided into parts, called panes, with each pane displaying different status information. A status bar can also contain other controls, including buttons and progress bars.

status bar control picture


For further reading https://docs.microsoft.com/en-us/windows/win32/controls/status-bar-reference

The following example demonstrates a simple status bar with 3 cells


SysLink Control

The syslink control provides a convenient way to embed hypertext links in a window. Unlike a standard static text control, a SysLink control recognises hyperlink markup embedded within its text. Multiple hyperlinks may be displayed within the same control, while the surrounding text remains unchanged. When the user activates a hyperlink, the control sends a notification message to its parent window, allowing the application to determine which link was selected and perform the appropriate action.

This example uses the SysLink control, which was introduced with the Common Controls library version 6. As a result, it requires Windows XP or later and must be compiled with Visual Studio 2005 or a later version of Visual C++. Earlier compilers, such as Visual C++ 6.0 (VC98), do not include the necessary header files and definitions required to build SysLink applications without significant modifications.

syslink control picture


For further reading https://docs.microsoft.com/en-us/windows/win32/controls/syslink-overview

The following example displays a simple window with a clickable link.


Tab Control

A tab control is a Windows common control that allows an application to organise related information into separate pages. Each page is selected using a tab at the top of the control. Only one page is normally visible at a time.

tab control picture


For further reading https://docs.microsoft.com/en-us/windows/win32/controls/tab-control-reference

The following example displays a simple adjustable tab control. Pages can be added or deleted by clicking the appropriate button.


Task Dialog

A Task Dialog is a newer Windows common control introduced with Windows Vista. Unlike a conventional message box, which is limited to a title, message, icon, and a small number of predefined buttons, a task dialog can present detailed information and guide the user through more complex decisions. This makes it particularly suitable for configuration wizards, confirmation dialogs, error reporting, and application setup.

Although the TaskDialog() API was introduced with Windows Vista, it can be compiled with Visual Studio 2005, 2008, 2010, 2012, 2013, and newer, provided the Windows SDK being used contains the necessary headers and libraries.

task dialog control picture


For further reading https://docs.microsoft.com/en-us/windows/win32/controls/task-dialogs-overview

The following short program demonstrates a simple task dialog


Toolbar Control

Toolbars can be created using the CreateWindowEx() function, specifying TOOLBARCLASSNAME as the window class name, or by using the deprecated CreateToolbarEx() function. A TBBUTTON structure contains the information describing each toolbar button. These buttons are added to the toolbar by sending the TB_ADDBUTTONS or TB_INSERTBUTTON message using the SendMessage() function. Toolbar images are stored in an image list (HIMAGELIST), which is associated with the toolbar using the TB_SETIMAGELIST message. Each toolbar button references an image in the image list through its iBitmap member. When a toolbar button is clicked, the parent window receives a WM_COMMAND message, with the button identifier stored in the low-order word of wParam.

For in-depth reading on the creation of toolbars
https://docs.microsoft.com/en-us/windows/win32/controls/toolbar-control-reference

The following short program creates a simple toolbar with two buttons using the following two images. Clicking either button will produce a message box.


Tooltip

A tooltip control is a Windows common control that automatically pops up when the user pauses the mouse pointer over an application element and displays a brief message explaining the purpose of a particular feature. Tooltips are part of the help system of an application.

tooltip dialog control picture


For further reading https://docs.microsoft.com/en-us/windows/win32/controls/tooltip-control-reference

The following short program demonstrates a simple tooltip window. Placing the map over the button causes the tooltip to appear


Trackbar Control

A Trackbar control (also called a slider control) allows a user to select a value from a range by moving a selector between its minimum and maximum points. The TrackBar control has two parts: an adjustable thumb or slider, and optional tick marks. When the user moves the slider, using either the mouse or the direction keys, the control sends notification messages to indicate the change.

trackbar control picture


For further reading – https://docs.microsoft.com/en-us/windows/win32/controls/using-trackbar-controls

The following program demonstrates a simple trackbar control with values from 0-100. Changes in value will be reflected in the neighbouring buddy window.


Tree-View Control

A tree-view is a window that displays a hierarchical list of labelled items or nodes. Each item can have an associated number of subitems. The top item in the hierarchy is called the root. If an item has other items below it in the hierarchy, it is referred to as a parent. Items subordinate to parents are called children. The hierarchy may be expanded or collapsed at any level to display or hide child items.

treeview control picture


For further reading – https://docs.microsoft.com/en-us/windows/win32/controls/tree-view-control-reference

The following program demonstrates the Treeview control. Nodes can be added or deleted by clicking the appropriate button.


Updown Control

The Updown or spinner control consists of two buttons displayed as arrows with an optional buddy control. The most common buddy control is an edit box and the combination of the two is called a spinner control. Clicking either of the arrows increments or decrements the value in the edit control.

updown control picture


For further reading https://docs.microsoft.com/en-us/windows/win32/controls/up-down-control-reference

The following short program demonstrates a spinner control. Any changes in the control are reflected in the neighbouring static box.


.

Creating Owner-Drawn Controls

Buttons, menus, static controls, list boxes, and combo boxes can be created using an owner-drawn style. Under normal circumstances, Windows is responsible for drawing the appearance of these controls. However, when a control is created with an owner-drawn style, Windows suppresses its default drawing routine and instead sends WM_DRAWITEM messages to the parent window whenever the control needs to be painted.

For owner-drawn controls that contain variable-sized items, such as certain list boxes and combo boxes, Windows also sends WM_MEASUREITEM messages. These allow the parent window to specify the size of each individual item before it is drawn.

By processing these messages, the parent window assumes responsibility for drawing the control. This enables the developer to create a completely customised appearance, including the use of different colours, fonts, images, icons, gradients, and other graphical effects that are not available with the standard control styles.

Example

The application below consists of customised listbox and a customised static box. The customised listbox displays a small bitmap next to each list item. Selecting any item will copy the Listbox item to the static box

owner drawn control combobox image


Example

The application below displays a customised menu. Clicking the file options displays an user-defined drop-down list

owner drawn control menu image

The Windows Message Box

A message box is a predefined dialog box provided by Windows that displays a message to the user and, optionally, one or more buttons that allow the user to respond. Message boxes are commonly used to provide information, display warnings or error messages, request confirmation before performing an action, or ask the user to make a simple choice.

Message boxes are created using the MessageBox() function, which requires four parameters. The prototype for this function is:

int MessageBox(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);

where
hWnd – is a handle to the owner window of the message box to be created. If this parameter is NULL, the message box has no owner window.
lpText – The message to be displayed.
lpCaption – Contains dialog box title. If this parameter is NULL, the default title is Error
uType – defines the contents and behaviour of the dialog box and will be a combination of several different flag values but some of the more common values are
MB_ABORTRETRYIGNORE- The message box contains three pushbuttons: Abort, Retry, and Ignore.
MB_ICONEXCLAMATION-An exclamation-point icon appears in the message box.
MB_ICONERROR-A stop-sign icon appears in the message box.
MB_ICONINFORMATION – A lowercase letter i in a circle appears in the message box.
MB_ICONQUESTION-A question-mark icon appears in the message box.
MB_ICONSTOP- A stop-sign icon appears in the message box.
MB_OK – The message box contains one pushbutton: OK. This is the default.
MB_OKCANCEL – The message box contains two push buttons: OK and Cancel.
MB_RETRYCANCEL – The message box contains two push buttons: Retry and Cancel.MB_YESNO – The message box contains two push buttons: Yes and No.
MB_YESNOCANCEL – The message box contains three pushbuttons: Yes, No, and Cancel.
The return value will depend on the type of message box selected but will be one of the following: IDABORT, IDCANCEL, IDCONTINUE, IDIGNORE, IDNO, IDOK, IDRETRY, IDYES

For further detailed reading
https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox

The following short program displays a simple ‘hello world’ message box

#include <windows.h>
int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine, int nCmdShow )
{
    MessageBox( NULL, TEXT("Hello, World!"), TEXT("Hi!"), MB_OK );
    return 0;
}

Customising the Windows Message Box

The standard Windows MessageBox() function provides only limited customisation. Although developers can choose the buttons, icons, default button, and modality, they cannot directly modify the layout, fonts, colours, or add additional controls.

For more advanced customisation, a Windows hook procedure can be used to intercept the creation of the message box. One approach is to install a Computer-Based Training (CBT) hook using the WH_CBT hook type. A CBT hook allows an application to receive notifications when a window is created, activated, moved, or destroyed.

By intercepting the message box as it is being created, a CBT hook can be used to modify certain aspects of its appearance or behaviour, such as changing the window title, repositioning the dialog, altering the captions of its buttons, or performing additional initialisation before the message box is displayed.

Although using a WH_CBT hook provides greater flexibility than the standard MessageBox() function, it also increases the complexity of the application. Consequently, hooks are generally reserved for specialised applications. When extensive customisation is required, it is usually preferable to create a custom dialog box instead of modifying a standard message box.

API Hooking and DLL Injection

Hooking is a technique used to intercept events or function calls so that an application can monitor, modify, or suppress their normal behaviour. The code that intercepts these events is called a hook procedure. A hook procedure can examine each event it receives, act on it, modify it, or pass it unchanged to the next hook procedure in the chain.

Windows allows developers to install hooks using the SetWindowsHookEx() API function. When an event such as a key press, mouse action, or window message occurs, Windows calls the appropriate hook procedure before the event reaches its normal destination. A hook chain is a list of application-defined hook procedures. Whenever an event associated with a particular hook type occurs, Windows passes the event to each hook procedure in the chain in turn.

Some types of hooks, particularly global hooks that monitor events in other processes, require the hook procedure to reside in a DLL. Windows loads this DLL into the address space of each target process so that the hook procedure can execute in that process. This mechanism is often referred to as DLL injection. DLL injection can also be performed by other techniques that do not involve Windows hooks and is commonly used by debugging tools, accessibility software, and application extensions, although it can also be misused by malicious software.

The prototype for SetWindowsHookEx is

HOOK SetWindowsHookEx(int idHook,HOOKPROC lpfn,HINSTANCE hmod,DWORD dwThreadId);

Where
idHook – is the type of hook procedure to be installed. This parameter can be one of the following values.
WH_DEBUG – used to monitor messages before the system sends them to the destination window procedure.
WH_CALLWNDPROCRET – used to monitor messages processed by the destination window procedure.
WH_CBT – used to receive notifications useful to a CBT application
WH_DEBUG – used when the application’s foreground thread is about to become idle.
WH_FOREGROUNDIDLE – used for performing low-priority tasks during idle time.
WH_JOURNALPLAYBACK – used to post messages previously recorded by a WH_JOURNALRECORD hook procedure.
WH_JOURNALRECORD – used to record input messages posted to the system message queue.
WH_KEYBOARD – used to monitor keystroke messages.
WH_KEYBOARD_LL – used to monitor low-level keyboard input events.
WH_MOUSE – Installs a hook procedure that monitors mouse messages.
WH_MOUSE_LL – used to monitor low-level mouse input events.
WH_MSGFILTER – used to monitor input events in a dialog box, message box, menu, or scroll bar.
WH_SHELL – used to monitor shell applications
WH_SYSMSGFILTER – used to monitor messages generated by an input event in a dialog box, message box, menu, or scroll bar.
Lpfn – A pointer to the hook procedure.
Hmod – A handle to the DLL containing the hook procedure pointed to by the lpfn parameter.
DwThreadId – The thread identifier with which the hook procedure is associated.

Return value – If the function succeeds, the return value is the handle to the hook procedure. If the function fails, the return value is NULL.

For detailed reading on the SetWindowsHookExA – https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexa

The hook procedure

A hook procedure has the following syntax:

LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam) { return CallNextHookEx(NULL, nCode, wParam, lParam); }

The nCode parameter is used to determine the action to perform. The value of the hook code depends on the type of the hook. The wParam and lParam parameters depend on the hook code, but they typically contain information about a message that was sent or posted

Calling the CallNextHookEx function to chain to the next hook procedure is not necessary, but it is highly recommended. This will enable other applications that have installed hooks to receive hook notifications and behave normally.

For further detailed reading about hooking
https://docs.microsoft.com/en-us/windows/win32/winmsg/about-hooks

Example

The following two examples demonstrate the use of the WH_KEYBOARD_LL hook. Each program installs a low-level keyboard hook, intercepts keyboard events, converts each virtual key into a readable name using GetKeyNameText(), and records the results in a text file. Pressing the Escape key removes the hook and terminates the program.

Both examples are written as Win32 Console Applications. They record keystrokes, not the characters ultimately produced by the keyboard. For example, pressing Shift+A records the individual key events rather than the character ‘A’. When creating the project, select the Console Application template rather than a Windows GUI application.

The first example (below) uses the WH_KEYBOARD hook. The hook procedure resides in a separate DLL, which is loaded using explicit linking. Windows injects the DLL into the address space of processes that receive keyboard input, allowing the hook procedure to monitor keyboard messages. The hook remains active until UnhookWindowsHookEx() is called, which occurs when the Enter key is pressed or when the console application is closed.

The second example (below) uses the WH_KEYBOARD_LL (low-level keyboard) hook. The hook procedure is exported from the executable itself rather than from a DLL. Unlike WH_KEYBOARD, the callback executes in the context of the application that installed the hook and therefore does not require process injection. Because the callback is delivered through the application’s message queue, the program must continue running and maintain a Windows message loop while the hook is active. The hook remains installed until UnhookWindowsHookEx() is called, which occurs when the Escape key is pressed or when the console application is closed.

WH_KEYBOARD versus WH_KEYBOARD_LL

Windows provides two keyboard hook types: WH_KEYBOARD and WH_KEYBOARD_LL. Although both allow an application to monitor keyboard activity, they operate in different ways and are intended for different purposes.

The WH_KEYBOARD hook is a traditional keyboard hook that monitors keyboard messages retrieved from a thread’s message queue. Because the hook procedure executes in the context of the target process, it must be implemented in a separate DLL so that Windows can load it into the address space of each process that receives keyboard input. On 64-bit versions of Windows, separate 32-bit and 64-bit DLLs are required if both types of applications are to be monitored.

The WH_KEYBOARD_LL hook is a low-level keyboard hook introduced with Windows 2000. Unlike WH_KEYBOARD, the hook procedure executes in the context of the application that installed the hook and therefore does not need to reside in a DLL. This makes low-level keyboard hooks significantly easier to implement and debug. However, because the callback executes in the installing process, that process must remain running and continue processing its message loop for the hook to remain active.

In most situations where an application simply needs to monitor or process keyboard input, WH_KEYBOARD_LL is the preferred choice. The older WH_KEYBOARD hook is generally only required when compatibility with legacy code or specialised message-hooking behaviour is needed.

DLLs

A DLL is Microsoft’s way of implementing a code library that multiple programs can use. A DLL can contain almost anything that can be compiled into a normal Windows program, but unlike executable programs, DLL files can’t be run directly and must be called upon by other code. These libraries usually have the file extension DLL, OCX, or DRV. There are several advantages to using DLLs –

  • DLLs can reduce the duplication of code when a different program uses the same code library
  • Easy deployment and installation. For instance, when multiple programs use the same DLL, those programs will all benefit from the same update or fix.
  • DLLs help with modular programming enabling a program to be split into smaller tasks.

Implementing a DLL

Any function or data within a DLL that will be accessed by another program or DLL must be exported. Likewise, any function or data imported from a DLL must be imported. Any code for import or export is declared using the _declspec keyword followed by storage-class attributes in parentheses (dllimport and dllexport) and then the function name.

For example, to export a function from a DLL:

__declspec(dllexport) void functionname()

To import the same function into an application:

__declspec(dllimport) void functionname()

A simple DLL

The example below illustrates a simple DLL file consisting of one function and a MessageBox routine. When a DLL project is compiled, it typically produces two files: a .dll file containing the executable code and a .lib import library used by the linker. The .dll file must be located where Windows can find it at runtime. By default, Windows searches the application’s directory first, followed by the system directories (such as System32), and then other directories included in the DLL search path, such as those specified by the PATH environment variable.

//file name exampleDLL.lib
#include &lt;windows.h&gt;
extern "C" __declspec(dllexport) void msgfunct()
{
MessageBox( NULL, TEXT("Hello World"), TEXT("In a DLL"), MB_OK);
}

The optional declaration extern “C” enables a library to be shared between C and C++. This is necessary so that the C++ compiler does not add any extra mangling information during compilation

Linking to a DLL

There are two ways to load a DLL: implicit linking and explicit linking

Implicit linking is when the operating system automatically loads a DLL when the executable file is loaded. The client program can then call exported functions in the DLL in the same way as functions that are part of the executable. To use implicit linking, the client program must link against the DLL’s import library (.lib file). The .lib file must be placed in a location where the linker can find it, such as the project directory, a library folder configured in the Visual C++ project settings, or a directory specified in the linker’s library search path. The .lib file is only required when building the application and does not need to be distributed with the final executable.

In Visual C++, linking to the import library can be done through Project Properties → Linker → Input → Additional Dependencies, or by adding a #pragma comment(lib, "MyDLL.lib") directive in the source code. The corresponding .dll file must then be placed in a directory where Windows can locate it when the application runs.

The following example illustrates a simple DLL file that contains a simple message box function. When imported and executed, the called function displays a messagebox.

//example console exe
#pragma comment(lib, "exampleDLL.lib")
extern "C" __declspec(dllimport) void msgfunct();
int main(int argc, char* argv[])
{
msgfunct();
return 0;
}


Explicit linking is when the operating system loads a DLL at runtime rather than when the executable is started. The application is responsible for loading the DLL using the LoadLibrary() function and releasing it using FreeLibrary() when it is no longer required. Access to functions inside the DLL is obtained at runtime using GetProcAddress(), which returns the memory address of the exported function. This address is then stored in a function pointer, allowing the program to call the DLL function. Explicit linking does not require the DLL import library (.lib) file because the connection to the DLL is made while the program is running.

The following example illustrates a simple console exe file that imports and calls a simple dll function, from the dll file exampleDLL.dll (above)

#include &lt;windows.h&gt;
typedef VOID (*DLLPROC) ();
DLLPROC HelloWorld;
int main(int argc, char* argv[])
{
DLLPROC HelloWorld;
HINSTANCE hInstLibrary = LoadLibrary("exampleDLL.dll");
if (hInstLibrary)
{
HelloWorld = (DLLPROC) GetProcAddress(hInstLibrary, "msgfunct");
if (HelloWorld != NULL)
HelloWorld ();
FreeLibrary(hInstLibrary);
}
}

DllMain

The DllMain function is an optional entry point for a dynamic-link library (DLL). It is called automatically by the Windows loader whenever a DLL is loaded into or removed from a process, and when threads are created or terminated within that process. It is used to perform simple initialization when the DLL starts and cleanup tasks before the DLL is unloaded. The function receives a reason code (fdwReason) that identifies why it was called.

The syntax is

BOOL WINAPI DllMain(HINSTANCE hinstDLL,    // handle to DLL module
DWORD fdwReason,       // reason for calling function
LPVOID lpReserved )    // reserved
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
// Occurs when a DLL is being loaded into memory for each new process. Return FALSE if DLL failed to load.
break;
case DLL_THREAD_ATTACH:
// occurs when current process is creating a new thread
break;
case DLL_THREAD_DETACH:
// occurs when a thread is exits cleanly
break;
case DLL_PROCESS_DETACH:
// Occurs DLL is being unloaded from memory
break;
}
return TRUE;  // Successful DLL_PROCESS_ATTACH.
}

Return Value

Returns TRUE if it succeeds or FALSE if initialisation fails
For further detailed reading –
https://docs.microsoft.com/en-us/windows/win32/dlls/dllmain

Data Types and Character Sets

Data Types in Win32 API

The Windows API does not rely primarily on the standard C/C++ data types. Instead, it defines its own collection of data types using typedef declarations in the windows.h header file. While many Win32 data types are available, only a relatively small number are used in most Windows applications. The most important of these are listed below.

Basic Integer Types:
BOOL – Boolean value (TRUE or FALSE)
INT – A 32-bit signed integer. Normal C-style integer. Declared as typedef int INT;
UINT – A 32-bit unsigned integer. Declared as typedef unsigned int UINT;
DWORD – A 32-bit unsigned integer. Windows system/hardware terminology
LONG – A 32-bit signed integer
BYTE – The same as unsigned char. Declared as typedef unsigned char BYTE;

Handles:
A handler is an identifier that refers to an internal Windows object.
HINSTANCE – A handle to the application instance.
HDC – A device context handle
HMENU – A handle to a menu.
HFONT – A handle to a font.
HBITMAP – A handle to a bitmap.
HBRUSH – A handle to a brush.

String Types (Modern Usage)
LPCWSTR – pointer to a constant null-terminated UTF-16 string.
LPWSTR – A 32-bit pointer to a string of 16-bit Unicode characters, which may be null-terminated.
LPCTSTR – An LPCWSTR if UNICODE is defined, or an LPCSTR otherwise. Now depreciated still exists for backward compatibility
LPTSTR – An LPWSTR if UNICODE is defined, or an LPSTR otherwise. Now depreciated still exists for backward compatibility.
TCHAR – A WCHAR if UNICODE is specified, or a CHAR otherwise. Now depreciated still exists for backward compatibility

For a full list of Windows data types
https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types

Identifier Constants

Windows programs make extensive use of named constants, often referred to as identifiers, to represent numerical values. These identifiers are usually written in uppercase and consist of a two- or three-letter prefix that identifies the category, followed by an underscore and a descriptive constant name. Some of the most common prefixes and their associated message types are listed below.

Prefix Description Example
CS Class style CS_HREDRAW | CS_VREDRAW
CW Create window CW_USEDEFAULT CW_USEDEFAULT
DT Draw text DT_CENTER DT_LEFT DT_RIGHT
IDI Icon identifier IDI_ASTERISK IDI_ERROR IDI_HAND
IDC Cursor identifier IDC_ARROW IDC_HAND
MB Message box options MB_HELP MB_OK MB_OKCANCEL
SND Sound option SND_ASYNC SND_NODEFAULT
WM Window message WM_NULL WM_CREATE WM_DESTROY
WS Window style WS_OVERLAPPED WS_SYSMENU WS_BORDER

Naming conventions

Microsoft traditionally used a naming convention known as Hungarian notation. In this convention, variables are prefixed with a short, lowercase abbreviation indicating their data type, followed by a descriptive name beginning with a capital letter. Function names do not use type prefixes and instead begin with a capital letter. Although modern C++ code often favours more descriptive naming conventions, Hungarian notation is still widely encountered in Win32 API programming and older Microsoft code.For further reading on MS coding style conventions

https://docs.microsoft.com/en-us/windows/win32/stg/coding-style-conventions

Character sets

Computers store text and numbers as patterns of binary digits called character codes. To ensure that information can be exchanged reliably between different computers and applications, a standard is required to define the code assigned to each character. A complete collection of characters and their corresponding codes is called a character set. The two most common character sets are ASCII and Unicode. While ASCII remains important for compatibility and legacy systems, Unicode has become the standard for modern software because it supports a vastly larger range of characters and writing systems.

ASCII

ASCII is a character encoding system that can represent 128 characters. It uses 7 bits to represent each character since the first bit of the byte is always 0. The code set allows 95 printable characters and 33 non-printable Control characters.

Extended ASCII

Standard ASCII uses 7 bits to represent 128 characters, which is sufficient for the English alphabet, digits, punctuation, and control characters. However, it cannot represent the accented letters and special symbols required by many other languages.

Extended ASCII uses 8 bits, allowing up to 256 characters. Various extended ASCII encodings were developed to include additional accented characters and symbols for different languages. However, because there was no single universal extended ASCII standard, different code pages assigned different characters to the same values, leading to compatibility problems.

Although extended ASCII doubled the number of available characters, it still could not represent all of the world’s writing systems. As a result, it has largely been superseded by Unicode, which provides a universal character encoding capable of representing virtually every written language.

UNICODE

The Unicode Standard is a universal character-encoding standard designed to represent the characters and symbols used in virtually every written language. Each character is assigned a unique numerical value known as a code point.

A Unicode Transformation Format (UTF) defines how Unicode code points are encoded as sequences of bytes for storage and transmission. The two most widely used Unicode encoding formats are UTF-8 and UTF-16.

UTF-8 is a variable-length encoding that uses between 1 and 4 bytes to represent each character. The first 128 Unicode code points are identical to those used by ASCII, making UTF-8 fully backward compatible with ASCII. This compatibility has contributed to UTF-8 becoming the dominant encoding for web pages, e-mail, and many modern applications.

UTF-16 is also a variable-length encoding, using either 2 or 4 bytes to represent a character. Unlike UTF-8, it is not directly compatible with ASCII because even ASCII characters are stored using 16-bit code units. Windows stores Unicode text internally using UTF-16 Little Endian (UTF-16LE), while older Windows applications may still use legacy ANSI code pages for non-Unicode text.

Unicode in the Windows API

Unicode has been the native character encoding used by Windows since Windows NT. Most Windows API functions that accept or return text are provided in three forms:

  • ANSI version, with an A suffix (for example, CreateWindowExA)
  • Unicode version, with a W suffix (for example, CreateWindowExW)
  • Generic version, with no suffix (for example, CreateWindowEx)

The generic function name is a macro defined in the Windows header files. At compile time, it is automatically mapped to either the ANSI or Unicode version, depending on whether the UNICODE preprocessor symbol is defined. In modern Windows applications, UNICODE is normally enabled by default, so generic function names are resolved to their Unicode (W) equivalents.

Working with Strings

C++ provides four built-in character types: char, wchar_t, char16_t, and char32_t.

The char type is an 8-bit character type commonly used to store ASCII text, UTF-8 encoded text, or characters from a system code page. The wchar_t type is intended for wide characters. Its size is implementation-dependent; on Windows it is 16 bits and is used to represent UTF-16 encoded text, whereas on many other platforms it is 32 bits.

C++11 introduced the fixed-width character types char16_t and char32_t to represent UTF-16 and UTF-32 code units respectively. Because these types have a fixed size on all platforms, they are preferable when writing portable Unicode code. However, when programming the Win32 API, wchar_t remains the standard character type used by Unicode functions.

String literals are prefixed to indicate the type of character string they contain:

char *ascii_example = "This is an ASCII string."; wchar_t *Unicode_example = L"This is a wide char string."; char16_t * char16_example = u"This is a char16_t Unicode string."; char32_t * char32_example = U"This is a char32_t Unicode string.";

TCHAR and the TEXT Macro

To simplify the development of applications that could be compiled for either ANSI or Unicode, Microsoft introduced the generic character type TCHAR. When the UNICODE preprocessor symbol is defined, TCHAR maps to wchar_t; otherwise, it maps to char. This allows the same source code to be compiled in either mode without modification.

To complement TCHAR, Microsoft also provides the TEXT() (or _T()) macro. This macro prefixes string literals appropriately so that they are treated as either ANSI or Unicode strings, depending on the compilation settings.

For example:

TCHAR* autoString = TEXT("This message can be either ANSI or Unicode!");

When compiled in Unicode mode, the statement above is equivalent to:

wchar_t* autoString = L"This message can be either ANSI or Unicode!";

When compiled in ANSI mode, it becomes:

char* autoString = "This message can be either ANSI or Unicode!";

Today, TCHAR and the TEXT() macro are generally regarded as legacy features. Modern Windows applications are developed using Unicode (UTF-16), and it is now common practice to use wchar_t and wide-character string literals (L"...") directly. Nevertheless, TCHAR and TEXT() remain fully supported and are still encountered in older Win32 codebases.

For further information on working with strings and character encoding in the Windows API, see:https://docs.microsoft.com/en-us/windows/win32/learnwin32/working-with-strings

Mapping Modes

A mapping mode defines how Windows converts logical coordinates used by an application into device coordinates used for drawing within a device context (DC). Logical coordinates represent the positions specified by the application, while device coordinates represent the corresponding pixel positions on the display or output device.

The selected mapping mode determines:

  • the units used for logical coordinates;
  • the scaling between logical units and device units;
  • the position of the coordinate origin; and
  • the orientation and direction of the X-axis and Y-axis.

In the default mapping mode (MM_TEXT), one logical unit corresponds to one pixel. The coordinate origin is located at the upper-left corner of the client area, the X-axis increases to the right, and the Y-axis increases downward.

Windows provides several predefined mapping modes, allowing applications to work in units such as pixels, inches, millimetres, or arbitrary user-defined units. The available mapping modes are listed below.

Mapping Mode Logical Unit x-axis and y-axis
MM_TEXT Pixel Positive x is to the right; positive y is down
MM_LOMETRIC 0.1 mm Positive x is to the right; positive y is up.
MM_HIMETRIC 0.01 mm Positive x is to the right; positive y is up.
MM_LOENGLISH 0.01 in Positive x is to the right; positive y is up.
MM_HIENGLISH 0.001 in Positive x is to the right; positive y is up.
MM_TWIPS 1/1440 in Positive x is to the right; positive y is up.
MM_ISOTROPIC user-specified user-specified
MM_ANISOTROPIC user-specified user-specified

To select a different mapping mode, use the function SetMapMode()

int SetMapMode(HDC hdc,int iMode);

where

hdc – A handle to the device context.
iMode – The new mapping mode.

If the function succeeds, the return value is the previous mapping mode. If the function fails, the return value is zero.

Programmable Mapping Modes

The MM_ISOTROPIC and MM_ANISOTROPIC mapping modes differ from the predefined mapping modes in that the relationship between logical units and device units is defined by the application rather than by Windows.

The two mapping modes differ in how scaling is applied. With MM_ISOTROPIC, the horizontal and vertical scaling factors are always kept equal, ensuring that one logical unit represents the same distance in both directions. This preserves the aspect ratio of graphics, preventing circles from becoming ellipses.

With MM_ANISOTROPIC, the horizontal and vertical scaling factors are independent. This allows the application to scale the X-axis and Y-axis by different amounts, making it possible to stretch or compress graphics horizontally or vertically.

When either of these mapping modes is selected, the application must define the logical coordinate system by specifying the window extents and viewport extents. The logical extents of the coordinate system are established by calling SetWindowExtEx(), while the corresponding size of the viewport in device units is specified by calling SetViewportExtEx(). Windows then uses these values to convert logical coordinates into device coordinates.

SetWindowExtEx

Sets the horizontal and vertical extents of the window for a device context by using the specified values.

BOOL SetWindowExtEx( HDC hdc, int x, int y, LPSIZE lpsz );

hdc – A handle to the device context.
x – The window’s horizontal extent in logical units.
y – The window’s vertical extent in logical units.
lpsz – A pointer to a SIZE structure that receives the previous window extents, in logical units. If lpSize is NULL, this parameter is not used.

If the function succeeds, the return value is nonzero. Otherwise, the return value is zero.

SetViewportExtEx

Sets the horizontal and vertical extents of the viewport for a device context by using the specified values.

BOOL SetViewportExtEx( HDC hdc, int x, int y,LPSIZE lpsz);

hdc – A handle to the device context.
x – The horizontal extent, in device units, of the viewport.
y – The vertical extent, in device units, of the viewport.
lpsz – A pointer to a SIZE structure that receives the previous viewport extents, in device units. If lpSize is NULL, this parameter is not used.

If the function succeeds, the return value is nonzero. If the function fails the return value is zero.

Moving the Origin

By default, the origin of a device context, regardless of the mapping mode, is located in the upper-left corner of the display. This origin can be changed using the API functions SetWindowOrgEx and SetViewportOrgEx.

The former changes the window origin, while the latter changes the viewport origin. The prototypes for these functions are as follows:

BOOL SetWindowOrgEx(HDC hdc,int x,int y,LPPOINT lppt);
BOOL SetViewportOrgEx( HDC hdc, int x, int y, LPPOINT lppt);

hdc – A handle to the device context.
x – The x-coordinate of the new viewport origin.
y – The y-coordinate of the new viewport origin.
lppt – A pointer to a POINT structure that receives the previous viewport origin, in device coordinates. If lpPoint is NULL, this parameter is not used.

If the function succeeds, the return value is nonzero. If the function fails, the return value is zero.

Example

The following short program draws 5 squares under different mappings to illustrate the different display characteristics of each Mapping Mode in Windows.

mapping mode image

Graphics Device Interface

The Graphics Device Interface (GDI) is the Windows graphics subsystem used to draw graphics and formatted text on display devices such as monitors and printers. One of its primary objectives is to provide a device-independent programming environment, allowing applications to produce the same output on different types of devices without requiring device-specific code.

GDI provides several hundred functions for drawing points, lines, rectangles, polygons, ellipses, bitmaps, and text. It also provides graphics objects, such as pens, brushes, and fonts, which control the appearance of the output. A pen defines the colour, width, and style of lines and outlines, while a brush determines how enclosed shapes are filled.

A device context (DC) always has a pen, brush, font, and other graphics attributes selected into it. When an application needs to change one of these attributes, it must first create the required GDI object and then select it into the device context. Any drawing performed after the new object has been selected uses the new attributes. Previously drawn graphics are unaffected.

Each GDI object created by an application consumes Windows system resources. To avoid resource leaks, applications should delete GDI objects using DeleteObject() when they are no longer required. Before deleting a GDI object, the original object should first be reselected into the device context, as an object that is currently selected into a device context must not be deleted.

Creating Pens

Pens are created and referred to by using the handle type 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 closed graphical objects. A brush has a colour and style, and it can also be defined using a bitmap pattern. Brushes are created and referred to by using the handle type 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 must be selected into the current device context (DC). The new object then replaces the previous graphics object of the same type. The SelectObject() API function prototype 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() returns a handle to the previous object of the same type. This may be useful if the application needs to restore the previous selection later.

The following short code 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 because the system has only a finite amount of resources, and failure to release allocated objects reduces the amount of memory available to the system.

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.

Important Rule

A GDI object must not be deleted while it is still selected into a device context. The original object should first be restored using SelectObject(), and then the created object can be deleted.

HPEN hPen = CreatePen(PS_SOLID, 1, RGB(0,0,255)); HPEN oldPen = (HPEN)SelectObject(hdc, hPen);

/* drawing operations */

SelectObject(hdc, oldPen);
DeleteObject(hPen);

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 include pens, brushes, fonts, and palettes. The API function GetStockObject() 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 the RGB (Red, Green, Blue) additive colour model to represent colours. A computer display forms an image from millions of individual pixels, each of which is created by combining varying intensities of the three primary colours: red, green, and blue. The term additive colour refers to the way these coloured light sources are combined to produce different colours. When all three components are at their maximum intensity, the result is white; when all are zero, the result is black.

Each RGB component is represented by an 8-bit value ranging from 0 to 255. This provides 256 possible intensity levels for each colour component, resulting in a total of 16,777,216 possible colours (256 × 256 × 256), often referred to as 24-bit colour or True Color.

The Windows API represents an RGB colour using the COLORREF data type. A COLORREF is a 32-bit value in which the lower three bytes store the red, green, and blue intensity values, while the highest-order byte is reserved and normally set to zero.

The GDI provides the RGB() macro to combine separate red, green, and blue values into a COLORREF, together with the GetRValue(), GetGValue(), and GetBValue() macros to extract the individual colour 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);

System Information Functions

The Win32 API provides system information data about the environment under which the application is running. This information includes the process environment variables, time, default locale settings for the system and user, system colour settings, drive information, system parameters, OS information, processor type and the computer name. A small selection of these functions are listed below.

For a full description of these functions – https://docs.microsoft.com/en-us/windows/win32/sysinfo/system-information-functions

GetComputerName

Returns the system computer name

BOOL GetComputerName(LPSTR lpBuffer,LPDWORD nSize);

Where
LpBuffer is a pointer to a buffer that receives the computer name or the cluster virtual server name and nSize specifies the size of the buffer. If the function succeeds, the return value is nonzero. If the function fails, the return value is zero.

GetSystemDirectory

Retrieves the path of the system directory.

UINT GetSystemDirectoryA(LPSTR lpBuffer,UINT uSize);

Where
PBuffer is a pointer to the buffer to receive the path and USize is the maximum buffer size. If the function succeeds, the return value is the length. If the function fails, the return value is zero.

GetCurrentDirectory

Retrieves the current directory for the current process.

DWORD GetCurrentDirectory(DWORD nBufferLength,LPTSTR lpBuffer);

Where nBufferLength is the buffer length for the current directory string and lpBuffer is a pointer to the buffer that receives the current directory string. If the function succeeds, the return value specifies the number of characters written to the buffer, not including the terminating null character. If the function fails, the return value is zero.

GetEnvironmentVariable

Retrieves the contents of the specified variable from the environment block of the calling process.

DWORD GetEnvironmentVariable(LPCTSTR lpName,LPTSTR lpBuffer,DWORD nSize);

Where
lpName – The name of the environment variable.
lpBuffer – A pointer to a buffer that receives the contents of the specified environment variable as a null-terminated string.
nSize – The buffer size pointed to by the lpBuffer parameter, including the null-terminating character, in characters.
If the function succeeds, the return value is the number of characters stored in the buffer pointed to by. If the function fails, the return value is zero.

GetLocalTime

Retrieves the current local date and time.

void GetLocalTime(LPSYSTEMTIME lpSystemTime);

where lpSystemTime is a pointer to a SYSTEMTIME structure to receive the current local date and time.

Example

The following short program demonstrates various system information functions

Creating Custom Controls

A custom control is any standard Windows control with additional functionality added to the existing predefined class. Since all windows belonging to the same class use the same default window procedure adding a new windows procedure allows the developer to amend the controls behaviour.

Subclassing

Subclassing the control window classes (buttons, edit boxes, list boxes, combo boxes, static controls, and scrollbars) allows an application to intercept and act on messages before a window has processed them. This allows an application to monitor and modify a window’s behaviour. An application subclasses a window by replacing the address of the window’s original window procedure with the address of a new window procedure called the subclass procedure.

Win32 offers two types of subclassing: instance and global. With an instance subclass, only a single instance of the windows procedure is subclassed. In global subclassing, an application replaces the address of the Windows procedure in the WNDCLASS structure of a window class. All subsequent windows created with that class will then have the address of the subclass procedure.

Instance Subclassing

To subclass an instance of a window, call the API function SetWindowLong() (SetWindowLongPtr for 64-bit compatibility) and specify the handle of the window to subclass together with the name of the new procedure. Use of the instance subclass means that only messages related to a specific window instance will be sent to the new window procedure making it suited to a situation where only a single control needs to be adjusted.

The prototype of the SetWindowLong function is –

LONG SetWindowLong( HWND hWnd, int nIndex, LONG dwNewLong); LONG_PTR SetWindowLongPtr(HWND hWnd,int nIndex,LONG_PTR dwNewLong);

Where
hWnd – Handle to the window.
hIndex – Specifies the zero-based offset to the value to be set.
dwNewLong – Specifies the replacement value.

If the function succeeds, the return value is the previous value of the specified offset.
If the function fails, the return value is zero.

For further detailed reading – https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowlonga

Example

In the example below the command button is subclassed. When the button is clicked the application generates a beep


Global Subclassing

To create a global Windows subclass call the API function SetClassLong() (SetClassLongPtr for 64-bit compatibility). Typically a hidden window of the control class is used to make the global subclass. All windows using that Windows class will be created with the new process address. Global subclassing is better suited to situations where several controls must be adjusted. Any globally subclassed control class will need to remove and then replace the replacement subclass with the original before program termination. This can be done before the application closes by calling SetClassLong with the address of the original procedure as a parameter.

The prototype for the function SetClassLong is

DWORD SetClassLong(HWND hWnd, int  nIndex,LONG dwNewLong); ULONG_PTR SetClassLongPtrA(HWND hWnd,int nIndex,LONG_PTR dwNewLong);

where
hWnd – A handle to the window.
nIndex – The value to be replaced.
DwNewLong – The replacement value.

If the function succeeds, the return value is the previous value of the specified 32-bit integer  If the function fails, the return value is zero.

For further detailed reading https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setclasslonga

Example

The following short program demonstrates a global subclass on a button control. When the button is clicked the application generates a beep


Superclassing

Superclassing means creating a new class based on the behaviour of an existing class. A superclass has its own window procedure. The superclass procedure can then act on the message before returning it to the original window procedure. To superclass, an existing class use the GetClassInfo() function (GetClassInfoEx for 64-bit compatibility) to obtain the existing WNDCLASS structure and then modify its behaviour to point to the new class. The prototype for the GetClassInfo API function is

BOOL GetClassInfo(HINSTANCE hInstance,LPCSTR lpClassName,LPWNDCLASSA lpWndClass); BOOL GetClassInfoExA(HINSTANCE hInstance,LPCSTR lpszClass,LPWNDCLASSEXA lpwcx);

where
HInstance – a handle to the application instance that created the class.
LpClassName – the preregistered class class name.
LpWndClass – A pointer to a WNDCLASS structure that receives the information about the class

If the function finds a matching class and successfully copies the data, the return value is nonzero.  If the function fails, the return value is zero.

For further detailed reading https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getclassinfoa

Example

The following short program subclasses two buttons. The first uses a superclassed procedure and generates a beep. The 2nd button uses the standard Windows procedure to generate an exclamation.