Stats

Using PreSubclassWindow

PreSubclassWindow is a very nice handler to use for certain effects in dialogs.

One of the lesser-understood handlers is the PreSubclassWindow
handler. It turns out this is a very nice handler to use for certain effects in
dialogs.

There are a couple problems in interfacing MFC and dialogs. I have often
stated that MFC is a triumph of brute force over common sense. What I mean by
this is that the object model of C++ is so completely different from the object
model of Windows that the two are almost incompatible. In spite of this, some very
clever programming makes the integration almost seamless. But there is a
substantial difference between "seamless" and "almost
seamless".

In normal window handling, you will have an OnCreate handler that is
invoked just as the window is created. In normal MFC window handling, you have
have the PreCreateWindow virtual method which lets you change the CREATESTRUCT
values, such as style parameters.

These are not accessible in dialogs. The reason is that the members of your
subclass can be invoked only when the window is mapped into MFC, that is, its
handler has been changed to be the AfxWnd handler. But dialog controls
are created long before the subclassing, which takes place on the first DoDataExchange
handler, which happens during the OnInitDialog processing. This is far
too late.

I have found that the PreSubclassWindow is an ideal place to make
certain modifications, such as changing styles. This applies only to those
styles which have an effect after the window has been created (many styles
cannot be changed once the window is created. You can change the style bits, but
the window itself is oblivious to these changes). This is useful when the styles
you want to change are not part of the styles presented by the dialog editor.

Another place I use it is when I want to set a font. For example, in this
particular class, I needed to set a font that was 80% of the height of the
window. The code is shown below. This creates a font which is a member variable
of my class which uses the font that will be set during the OnPaint
handler. I want to use the same font as the parent window, but 80% of the size
of the current window.

There are some things you cannot do in a PreSubclassWindow handler;
for example, I found that doing a ShowWindow would cause NT 4.0 SP6 to
bluescreen immediately. I have not tried the experiment on Win2K.

However, PreSubclassWindow is a much-neglected method, having little
documentation to show its utility. In writing this article, I found precisely
one useful reference in the MSDN, to an article Paul DiLascia wrote in the
Microsoft System Journal in December, 1999, where he actually says pretty much
the same thing. But having written this article, I might as well post it to my
Web site.

Several people have pointed out that "You aren't doing anything in PreSubclassWindow
that could not be done in OnInitDialog. They are absolutely right. The
difference is one of encapsulation. If you force the user of your class (which
is often yourself) to do the initialization in OnInitDialog, you must
remember what to initialize, even if it is independent of the dialog. And if you
change what needs to be done in the initialization, everyone who uses the class
(and in every place they use the class), must add or modify the initialization
in OnInitDialog. By putting it in PreSubclassWindow, the
initialization "follows" the changes you make, and the clients of the
class do not need to be concerned about this at all. This is good
modularization.

You might also want to check out my essay on self-registering
windows, another useful technique to know about if you are doing custom
controls and want to put them in a dialog.

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.

I read very carefully your two articles. Realy we have not chance to handle WM_CREATE, WM_SIZE ... in our custom controls when they are created in doalog templates. Why?
Besacuse of when we initialize WNDCLASS structure we initialize lpWndProc member with ::DefWindowProc.
When custom controls are created from dialog template first messages are sent to ::DefWindowProc not to the window procedure of custom control.
The messages that ::DefWindowProc handle are:

WM_NCCREATE
WM_NCCALCSIZE
WM_CREATE
WM_SIZE
WM_MOVE
WM_SHOWWINDOW
WM_SETFONT
WM_GETDLGCODE
364h - I could not find what is the message with this ID

Next custom controls is subclassed and the first message it receive is:

WM_INITIALUPDATE

Unfortunately WM_INITIALUPDATE is a MFC defined message.

And so what about when we initialize WNDCLASS structure, initialize lpWndProc member not point to ::DefWindowProc and to point to our defined window procedure. Then all messages above will be send to our window procedure not to ::DefWindowProc and we will have the chanse to handle message such as WM_CREATE, WM_SIZE ...

There are some other problems with custom control such as child controls in custom control and HINSTANCE value when the custom contro is created fron DLL resource.

Yes, this is one of the problems of MFC. Presumably if you are using MFC, the WM_INITIALUPDATE should suffice (I thought this was only sent to top-level view windows, but it isn't a message I worry about too much). However, if you want the custom controls to work in C, as you point out you have to use other than DefWindowProc as the registered handler. This is a bit painful as you have to unpack the messages yourself, or, alternatively, call AfxWndProc yourself after the handle is in the permanent map (I'm not sure when this actually happens, but I know it is fairly late in the sequence)