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() (now superseded by 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.

Example

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

Display Download

Global Subclassing

To create a global Windows subclass call the API function SetClassLong() (now superseded by 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. Specify one of the following values.
GCL_CBCLSEXTRA - Sets the size, in bytes, of the extra memory associated with the class. Setting this value does not change the number of extra bytes already allocated.
GCL_CBWNDEXTRA - Sets the size, in bytes, of the extra window memory associated with each window in the class. Setting this value does not change the number of extra bytes already allocated. For information on how to access this memory, see SetWindowLong.
GCL - Replaces a handle to the background brush associated with the class.
GCL_HCURSOR - Replaces a handle to the cursor associated with the class.
GCL_HICON - Replaces a handle to the icon associated with the class.
GCL_HICONSM - Replace a handle to the small icon associated with the class.
GCL_HMODULE - Replaces a handle to the module that registered the class.
GCL_MENUNAME - Replaces the address of the menu name string. The string identifies the menu resource associated with the class.
GCL_STYLE - Replaces the window-class style bits.
GCL_WNDPROC - Replaces the address of the window procedure associated with the class.
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.

Example

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

Display Download

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 (now superseded by 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.

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.

Display Download