Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Double Subclassing (Runtime Form Editor)

0.00/5 (No votes)
21 May 2003 1  
An article that describes a way to subclass controls that are already subclassed (double), The example includes a runtime form editor

Introduction

This article explains how a to subclass already subclassed controls. It includes a simple Runtime form editor.

Introduction

I had a project in the company I work in that needed different forms for different customers, so the team decided to create a runtime form editor that can enable editing the forms for each customer. In order to do that I needed a way to control all the Controls on a formview or on a dialog; enabling me to resize the controls, move them, or hide them. I wanted to subclass the Controls on a dialog/formview in order to control them, however the major problem was that most controls were already subclassed. I wrote a class (CDblSubclassWnd) that can subclass controls even if they are already subclassed.

Explanation

The way it works is, the messages first go into a function called PreWndProc and then they continue to the original WndProc of the Control, and after it finishes from there it goes into a function called PostWndProc.

The class is simple to use. The demo in the article contains a very simple form editor that allows you to simply move the controls on the form while you are in edit mode. Using the class is very simple. You have three methods of the class CDblSubclassWnd that you will work with. All methods are static

  • The first thing to do is give to the class two pointers to functions, that the CDblSubclassWnd class will call to pass by the messages of the subclassed controls.

    The method signature is:

    static void SetDblSubclassWndProc(
                    DBLSUBCLASS_WNDPROC *pPREPointer = NULL, 
                    DBLSUBCLASS_WNDPROC *pPOSTPointer = NULL
                );
    
    The first parameter would be a pointer to the function (PreWndProc) that will be called prior to passing on the message to the main WndProc of the control (or another Proc if it is subclassed). This function would give you the option of changing messages before they reach their control. The second parameter would be a pointer to the function that will be called after the control processed the message (PostWndProc) You can use this to inspect the values changed (or returned) by the Control.

    The DBLSUBCLASS_WNDPROC function pointer is defined as such:

    typedef LRESULT CALLBACK DBLSUBCLASS_WNDPROC(
                                 CWnd*,
                                 HWND,
                                 UINT,
                                 WPARAM,
                                 LPARAM,
                                 bool &
                             );
    

    The first parameter is a pointer to the Control Window class that the current message belongs to. The second parameter is the Handle to the Window. The third parameter (UINT) is the Message Number itself, and the following two parameters (WPARAM, LPARAM) are the two parameters that are passed with every Window Message, their meaning depend on the actual message. The last parameter (a reference to a bool) is used to indicate whether you want the DblSubclassed Engine to discontinue routing the message and return the return value returned by one of your two functions (pPREPointer, pPOSTPointer). To explain this point more by an example, if you have a button and you clicked on this button, the clicking message BN_CLICKED would first go to the PRE function pointer you assigned, if you do not want this message to continue to the WndProc of the control, you can stop this by setting the the boolean (last parameter to the function DBLSUBCLASS_WNDPROC) to false, this way the message will be dropped and will not reach the control.

  • Now that you have your PreWndProc and PostWndProc set, it is time to actually call the methods to subclass the Controls.
    void CDblSubclassWnd::SubclassChildsRecurs(
                  HWND hWnd, 
                  DBLSUBCLASS_RECURSIVECALLBACKPROC *pFunc
              )
    
    You call this method giving it (for example) the handle to the dialog you are working in. The function will traverse all the Controls on the dialog and for each control will call the function pointed to by the second parameter of the function, DBLSUBCLASS_RECURSIVECALLBACKPROC. This function will be called by the engine for each control that is going to be subclassed, its job is to decide whether the control is to be subclassed or not.

    For example, if you want to subclass all the Buttons on your dialog and not all the controls, in your RecursiveCallBack function, you would test for the control for being a button or not (control's class) and you would return true only for the button controls. The RecursiveCallBack simply takes a HWND parameter (to do your testing on the control) and returns a boolean value to indicate whether to subclass the specified control or not.

  • After you subclass the controls the messages will start flowing into your PRE and POST WindowProc assigned in the call to SetDblSubclassWndProc (in the first step). When you want to end this effect, then you unsubclass the doubly subclassed controls by using UnSubclassChildsRecurs. Its use is straight forward, you give it the Handle to the main window (the dialog in our example) and it will go through the Controls belonging to it and unsubclass all the Controls that were subclassed before.

I hope you will find this article useful to you.

History

Date Posted: May 22, 2003

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here