A custom control is any standard window control that has additional functionality added to the existing predefined class. Since all windows belonging to the same class use the same default window procedure then adding a new windows procedure allows the developer to amend the controls behaviour.
Subclassing the control window classes (buttons, edit boxes, list boxes, combo boxes, static controls, and scroll bar) allows an application to intercept and process messages posted to a particular window before that window has a chance to process them. This allows an application to monitor and modify a windows 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.
To subclass an instance of a window, call the API function SetWindowLong() (now superseded by SetWindowLongPtr for 64 bit compatability) 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 process which makes it suited to a situation where only a single control needs to be adjusted.
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.
In the example below the command button is subclassed. When the button is clicked the application generates a beep
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 the windows using that windows class will be created with this new process address. Global subclassing is better suited to situations where a number of controls need to be adjusted. Any globally subclassed control class will need to remove and then replace the replacement subclass with the original prior to 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.
The following short program demonstrates how to set up a global subclass on a button control. When the button is clicked the application generates a beep
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 instance of the application 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
The following short program subclasses two buttons. The first uses a superclassed procedure and generates a beep and the 2nd button uses the standard windows procedure to generate an exclamation.