Win32 API

Windows Subclassing

Introduction#

Window subclassing is a way to hook up into standard window procedure and to modify or extend its default behavior. An application subclasses a window by replacing the the window’s original window procedure with a new window procedure. This new window procedure receives any messages sent or posted to the window.

Syntax#

  • BOOL SetWindowSubclass(HWND hWnd, SUBCLASSPROC SubclassProc, UINT_PTR SubclassId, DWORD_PTR RefData);
  • BOOL RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC SubclassProc, UINT_PTR SubclassId);
  • BOOL GetWindowSubclass(HWND hWnd, SUBCLASSPROC SubclassProc, UINT_PTR SubclassId, DORD_PTR* RefData);
  • LRESULT DefSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

Parameters#

Parameter Detail
hWnd The handle of the window to subclass.
SubclassProc The subclass callback procedure.
SubclassId User specified ID to identify the subclass, together with the subclass procedure uniquely identifies a subclass. It can simply be an arbitrary consecutive number.
RefData User specified data. The meaning is determined by the application. It is passed to the subclass callback in unmodified way. It could be an object pointer to a class instance for example.
## Remarks#
MSDN Documentation

Subclassing windows button control within C++ class

This example shows how to manipulate button ideal size by specifying a fixed size.

class ButtonSubclass {
public:

    ButtonSubclass(HWND hWndButton) {
        SetWindowSubclass(hWndButton, MyButtonSubclassProc, 1, (DWORD_PTR) this);
    }
    ~ButtonSuclass() {
        RemoveWindowSubclass(hWndButton, MyButtonSubclassProc, 1, (DWORD_PTR) this);
    }

protected:

    static LRESULT CALLBACK MyButtonSubclassProc(
           HWND hWnd, UINT Msg, WPARAM w, LPARAM l, DWORD_PTR RefData) {

        ButtonSubclass* o = reinterpret_cast<ButtonSubclass*>(RefData);

        if (Msg == BCM_GETIDEALSIZE) {
            reinterpret_cast<SIZE*>(lParam)->cx = 100;
            reinterpret_cast<SIZE*>(lParam)->cy = 100;
            return TRUE;
        }
        return DefSubclassProc(hWnd, Msg, w, l);
    }
}

Installing and removing subclass procedure

The following methods installs or removes the subclass callback. The combination of SubclassId and SubclassProc uniquely identifies a subclass. There is no reference counting, calling SetWindowSubclass multiple times with different RefData only updates that value but will not causes the subclass callback to be called multiple times.

BOOL SetWindowSubclass(HWND hWnd, SUBCLASSPROC SubclassProc, UINT_PTR SubclassId, DWORD_PTR RefData);
BOOL RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC SubclassProc, UINT_PTR SubclassId);

To retrieve the reference data that was passed in the last SetWindowSubclasscall, one can use the GetWindowSubclass method.

BOOL GetWindowSubclass(HWND hWnd, SUBCLASSPROC SubclassProc, UINT_PTR SubclassId, DORD_PTR* RefData);
Parameter Detail
hWnd The handle of the window to subclass.
SubclassProc The subclass callback procedure.
SubclassId User specified ID to identify the subclass, together with the subclass procedure uniquely identifies a subclass. It can simply be an arbitrary consecutive number.
RefData User specified data. The meaning is determined by the application. It is passed to the subclass callback in unmodified way. It could be an object pointer to a class instance for example.

The subclass callback is responsible to call the next handler in window’s subclass chain. DefSubclassProc calls the next handler in window’s subclass chain. The last handler calls the original window procedure. It should be called in any subclassing callback procedure unless the message is completely handled by the application.

LRESULT DefSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
Parameter Detail
hWnd Window handle where the message originates from
Msg Window message
wParam WPARAM argument, this value depends on specific window message
lParam LPARAM argument, this value depends on specific window message

SUBCLASSPROC

It is similar to WINDOWPROC callback but contains an additional argument RefData.

typedef LRESULT (CALLBACK *SUBCLASSPROC)(
    HWND hWnd,
    UINT Msg,
    WPARAM wParam,
    LPARAM lParam,
    UINT_PTR SubclassId,
    DWORD_PTR RefData
);

Handling common controls notification messages within C++ class

class MyToolbarControl {
public:
    MyToolbarControl(HWND hWndToolbar, HWND hWndNotifyParent = nullptr) : _Handle(hWndToolbar) {
        if (hWndNotifyParent == nullptr) {
            hWndNotifyParent = GetAncestor(hWndToolbar, GA_ROOTOWNER);
        }
        SetWindowSubclass(
            hWndNotifyParent , SubclassWindowProc, reinterpret_cast<UINT_PTR>(this), reinterpret_cast<DWORD_PTR>(this)
        );
    }
    ~MyToolbarControl() {
        RemoveWindowSubclass(
            hWndNotifyParent , SubclassWindowProc, reinterpret_cast<UINT_PTR>(this), reinterpret_cast<DWORD_PTR>(this)
        );
    }

protected:
    HWND _Handle;

    static LRESULT CALLBACK SubclassWindowProc(
        HWND hWnd, UINT Msg, WPARAM w, LPARAM l, UINT_PTR SubclassId, DWORD_PTR RefData) {
        MyToolbarControl * w = reinterpret_cast<MyToolbarControl *>(RefData);
        if (Msg == WM_NOTIFY) {
            NMHDR* h = reinterpret_cast<NMHDR*>(l);
            if (h->hwndFrom == w->_Handle) {
                // Handle notification message here...
            }
        }
        return DefSubclassProc(hWnd, Msg, w, l);
    }
};

This modified text is an extract of the original Stack Overflow Documentation created by the contributors and released under CC BY-SA 3.0 This website is not affiliated with Stack Overflow