Let child process messages that would be otherwise sent to parent?

Most child controls send messages to parent such as WM_DRAWITEM or WM_COMMAND.

Is there a standard way to not send *specific* messages (ie. these 2 above) but to be instead handled by child directly? (I still want parent to receive some messages, but not all, which ones it depends on design)

I have a class hierarchy where 80% of the message processing is done by childs directly, but at the expense of parent window sending back received messages to child to let child process them instead of parent. (this allows for better object oriented approach and new inheritance for the purpose of class customization).

Basically I want to avoid writing procedures whose only purpose is to send messages from parent back to child.

Any help, insights or links to docs on this matter is much appreciated!
Last edited on
Look up 'Window Subclassing'.
thank you for input, I already extensively use both superclassing and subclassing, but I don't see any options to disable parent notification? either partially or fully.
There's a humorous term used in subclassing known as 'eating the message'. Are you familiar with that term and how to implement it? In a subclass procedure you can run what code you want, then at exit from the function you can fail to call the window procedure of the parent - in which case you've 'ate the message', i.e., not passed it on, or you can call the parent's window procedure, in which case that procedure can run whatever code is written for that message. I believe 'eating the message' is what you are wanting to do or am I failing to understand your question, which is a possibility I suppose?
sorry I was away bcs. my SSD on dev PC died, I had to reconfigure everything which took 2 days on my other crappy laptop with only 4GB of memory, and due to corona hazard I can't even go to buy another one because stores are closed :(

thanks God most of the stuff was backed up on another HDD haha.

I'll check out your suggestion about "eating the message" although google doesn't seem to show any straight results.
Last edited on
I'm retired and not doing much coding now, but I have voluminous code on this topic. I'll try to dig up some examples for you.
Thanks, examples are always welcome!, it looks like what I'm trying to do is not the standard way to do things.
I'll make a compilable example app. Its fun for me to do these things. Should be able to post it in a day or two.
Sounds great! looking forward to see code.
thanks again.
Discussion and explanation next post (no room here - almost 8k

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//Form3.h
#ifndef Form3_h
#define Form3_h
#define BUTTON_1             1500
#define BUTTON_2             1505
#define BUTTON_EXIT          1510
#define dim(x)               (sizeof(x) / sizeof(x[0]))

struct WndEventArgs
{
 HWND                         hWnd;
 WPARAM                       wParam;
 LPARAM                       lParam;
 HINSTANCE                    hIns;
};

long fnWndProc_OnCreate       (WndEventArgs& Wea);
long fnWndProc_OnCommand      (WndEventArgs& Wea);
long fnWndProc_OnDestroy      (WndEventArgs& Wea);

struct EVENTHANDLER
{
 unsigned int                 iMsg;
 long                         (*fnPtr)(WndEventArgs&);
};

const EVENTHANDLER EventHandler[]=
{
 {WM_CREATE,                  fnWndProc_OnCreate},
 {WM_COMMAND,                 fnWndProc_OnCommand},
 {WM_DESTROY,                 fnWndProc_OnDestroy}
};
#endif 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// Form3.cpp
// cl Form3.cpp Kernel32.lib User32.lib /FeForm3 /O1 /Os /MT /GA  - 88,064 Bytes With MS C Runtime Lib
// cl Form3.cpp /O1 /Os /GS- TCLib.lib kernel32.lib user32.lib    -  5,120 bytes with my custom C Runtime
// g++ Form3.cpp -oForm3_MinGW64.exe -mwindows -m64 -s -Os
//#define DEBUG
//#define TCLib
#include <windows.h>
#ifdef TCLib
   #include "stdio.h"
   #include "tchar.h"
#else
   #include <stdio.h>
   #include <tchar.h>
#endif   
#include "Form3.h"
#ifdef DEBUG
   FILE* fp = NULL;
#endif   


LRESULT CALLBACK fnBtnSubClass(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)  // This procedure 'hooks' the
{                                                                                  // internal Window Procedure for
 HWND hParent=GetParent(hwnd);                                                     // the "button" class.  It executes
 int iCtrlId= GetDlgCtrlID(hwnd);                                                  // before executiion enters the
 switch(msg)                                                                       // "button" class Window Procedure.
 {                                                                                 // API Function CallWindowProc() in
   case WM_LBUTTONDOWN:                                                            // return statement passes execution
    {                                                                              // to internal "button" class WndProc.
        #ifdef DEBUG                                                               // Note however that if the button
        fprintf(fp,"  Entering fnBtnSubClass() With msg==WM_LBUTTONDOWN\n");       // with Control ID 1505 (BUTTON_2)
        fprintf(fp,"    iCtrlId == %u\n",iCtrlId);                                 // receives a WM_LBUTTONDOWN or
        fprintf(fp,"  Leaving fnBtnSubClass() With msg==WM_LBUTTONDOWN\n\n");      // WM_LBUTTONDBLCLK, the WndProc for
        #endif                                                                     // the "button" class is not called -
        if(iCtrlId==BUTTON_2)                                                      // this procedure 'eats' the message.
           return 0;                                                               // the function exits or 'short circuits'
        break;                                                                     // with a return statement - and
    }                                                                              // CallWindowProc() doesn't get called.
   case WM_LBUTTONDBLCLK:                                                          
    {
        #ifdef DEBUG
        fprintf(fp,"  Entering fnBtnSubClass() With msg==WM_LBUTTONDBLCLK\n");
        fprintf(fp,"    iCtrlId == %u\n",iCtrlId);
        fprintf(fp,"  Leaving fnBtnSubClass() With msg==WM_LBUTTONDBLCLK\n\n");
        #endif
        if(iCtrlId==BUTTON_2)
           return 0;
    }
 }
     
 return CallWindowProc((WNDPROC)GetWindowLongPtr(hParent,0), hwnd, msg, wParam, lParam);
}    
    

long fnWndProc_OnCreate(WndEventArgs& Wea)
{
 WNDPROC btnWndProc=NULL;  // Holds address of internal Window Procedure for "button" Class
 HWND    hBtn      =NULL;  // HWND of "button"
 
 #ifdef DEBUG
 fprintf(fp,"  Entering fnWndProc_OnCreate()\n");
 #endif
 Wea.hIns=((LPCREATESTRUCT)Wea.lParam)->hInstance;
 #ifdef DEBUG
 fprintf(fp,"    Wea.hIns = %u\n",Wea.hIns);
 fprintf(fp,"    Wea.hWnd = %u\n",Wea.hWnd);
 #endif
 hBtn=CreateWindowEx(0,_T("button"),_T("Button #1"),WS_CHILD|WS_VISIBLE,105,70,90,25,Wea.hWnd,(HMENU)BUTTON_1,Wea.hIns,0);  // Create Button #1
 btnWndProc=(WNDPROC)SetWindowLongPtr(hBtn,GWLP_WNDPROC,(LONG_PTR)fnBtnSubClass);                                           // Subclass "button"
 SetWindowLongPtr(Wea.hWnd,0,(LONG_PTR)btnWndProc);
 hBtn=CreateWindowEx(0,_T("button"),_T("Button #2"),WS_CHILD|WS_VISIBLE,105,110,90,25,Wea.hWnd,(HMENU)BUTTON_2,Wea.hIns,0); // Create Button #2
 btnWndProc=(WNDPROC)SetWindowLongPtr(hBtn,GWLP_WNDPROC,(LONG_PTR)fnBtnSubClass);                                           // Subclass "button"
 SetWindowLongPtr(Wea.hWnd,0,(LONG_PTR)btnWndProc);                                                                         // Store address in Window's .cbWndExtra bytes
 CreateWindowEx(0,_T("button"),_T("Exit"),WS_CHILD|WS_VISIBLE,105,150,90,25,Wea.hWnd,(HMENU)BUTTON_EXIT,Wea.hIns,0);        // Exit Button Not Subclassed
 #ifdef DEBUG
 fprintf(fp,"  Leaving fnWndProc_OnCreate()\n\n");
 #endif
 
 return 0;
}


long fnWndProc_OnCommand(WndEventArgs& Wea)
{
 #ifdef DEBUG
 fprintf(fp,"  Entering fnWndProc_OnCommand()\n");
 fprintf(fp,"    Wea.hWnd = %u\n",Wea.hWnd);
 #endif
 switch(LOWORD(Wea.wParam))
 {
   case BUTTON_1:
    {
        MessageBox(Wea.hWnd, _T("Got Click From Button #1."), _T("Click Report"), MB_OK);
        break;
    }
   case BUTTON_2:
    {
        MessageBox(Wea.hWnd, _T("You'll Never See This Message.  It Was Eaten By fnBtnSubClass!"), _T("Click Report"), MB_OK);
        break;
    }
   case BUTTON_EXIT:
    {
        #ifdef DEBUG
        fprintf(fp,"    Got Click Of Exit Button!\n");
        #endif
        PostMessage(Wea.hWnd, WM_CLOSE, 0, 0);
        break;
    }
 }
 #ifdef DEBUG
 fprintf(fp,"  Leaving fnWndProc_OnCommand()\n\n");
 #endif
 
 return 0;
}


long fnWndProc_OnDestroy(WndEventArgs& Wea)
{
 #ifdef DEBUG
 fprintf(fp,"  Entering fnWndProc_OnDestroy()\n");
 fprintf(fp,"    Wea.hWnd = %u\n",Wea.hWnd);
 fprintf(fp,"  Leaving fnWndProc_OnDestroy()\n");
 #endif
 PostQuitMessage(0);
 return 0;
}


LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 WndEventArgs Wea;

 for(unsigned int i=0; i<dim(EventHandler); i++)
 {
     if(EventHandler[i].iMsg==msg)
     {
        Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;
        return (*EventHandler[i].fnPtr)(Wea);
     }
 }

 return (DefWindowProc(hwnd, msg, wParam, lParam));
}


int WINAPI WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 TCHAR szClassName[]=_T("Form3");
 WNDCLASSEX wc;
 MSG messages;
 HWND hWnd;

 #ifdef DEBUG
 fp=fopen("Output.txt","w");
 fprintf(fp,"Entering WinMain()\n");
 #endif
 wc.lpszClassName=szClassName;                wc.lpfnWndProc=fnWndProc;
 wc.cbSize=sizeof (WNDCLASSEX);               wc.style=0;
 wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);     wc.hInstance=hIns;
 wc.hIconSm=NULL;                             wc.hCursor=LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW;    wc.cbWndExtra=sizeof(void*);            // Extra bytes for button WNDPROC address
 wc.lpszMenuName=NULL;                        wc.cbClsExtra=0;
 RegisterClassEx(&wc);
 hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,75,75,320,305,HWND_DESKTOP,0,hIns,0);
 #ifdef DEBUG
 fprintf(fp,"  hIns = %u\n",hIns);
 fprintf(fp,"  hWnd = %u\n\n",hWnd); 
 #endif 
 ShowWindow(hWnd,iShow);
 while(GetMessage(&messages,NULL,0,0))
 {
    TranslateMessage(&messages);
    DispatchMessage(&messages);
 }
 #ifdef DEBUG
 fprintf(fp,"Leaving WinMain()\n");
 fclose(fp);
 #endif
 
 return (int)messages.wParam;
}
Don't let it blow your mind! I've some unusual coding habits developed over a lifetime of doing this stuff!

Its an SDK program using Windows Api directly with no class frameworks, although your first look at it might lead you to believe some class framework is involved.

It doesn't use the typical switch construct in the Window Procedure to map code execution to Windows messages, but rather a for loop which iterates through an array of struct EVENTHANDLER like so...

1
2
3
4
5
struct EVENTHANDLER
{
 unsigned int                 iMsg;
 long                         (*fnPtr)(WndEventArgs&);
};


See Form3.h. The array is constructed like so in Form3.h....

1
2
3
4
5
6
const EVENTHANDLER EventHandler[]=
{
 {WM_CREATE,                  fnWndProc_OnCreate},
 {WM_COMMAND,                 fnWndProc_OnCommand},
 {WM_DESTROY,                 fnWndProc_OnDestroy}
};


The for loop in fnWndProc(...) iterates through the array comparing the message received with the EVENTHANDLER::iMsg member, and when a match is made the eventhandler is called through the function pointer member (don't know if you are familiar with function pointers - more a C thing than a C++ thing maybe).

In any case, what the program does is create a main form with three buttons on it. The top two buttons (Button #1 and Button #2) are subclassed, and the subclass procedure is at top of Form3.cpp and is fnBtnSubClass(....). In that procedure a test is made for the Control ID of the button clicked. 1500 is Button #1 and 1505 is Button #2 (see Form3.h).

A switch construct in the subclass proc tests for WM_LBUTTONDOWN and WM_LBUTTONDBLCLK messages. If one of those messages is received for Button #2 then there is a return statement executed and the subclass procedure is early exited without calling CallWindowProc() at the termination of the function. In this way the internal Window Procedure for the button class is never called for a click of Button #2 and nothing happens when that button is clicked. I have a MessageBox() in the WM_COMMAND event handler for the main window, and of course you'll never see that if Button #2 is clicked. Noted that button #1 works fine - if you click Button #1 you'll see the message box.

The workings here really aren't complicated or hard to understand. When you subclass a control your subclass procedure executes before the internal Window Procedure for the control. If you do anything in your subclass proc to not pass on control to the internal window procedure (by not calling CallWindowProc()), then it 'breaks' the control. However, if your intention is to break the control for whatever reason, then that's fine too.

If this is all too much to comprehend what with my bizarre coding style I'll convert it to typical switch logic for you.

Oh! If you run the DEBUG version (uncomment #define DEBUG), here is what the output of "Output.txt" looks like on a program run where one 1st clicks the top button, then Button #2, and finally the Exit button....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Entering WinMain()
  Entering fnWndProc_OnCreate()
    Wea.hIns = 2124939264
    Wea.hWnd = 1050142
  Leaving fnWndProc_OnCreate()

  hIns = 2124939264
  hWnd = 1050142

  Entering fnBtnSubClass() With msg==WM_LBUTTONDOWN
    iCtrlId == 1500
  Leaving fnBtnSubClass() With msg==WM_LBUTTONDOWN

  Entering fnWndProc_OnCommand()
    Wea.hWnd = 1050142
  Leaving fnWndProc_OnCommand()

  Entering fnBtnSubClass() With msg==WM_LBUTTONDOWN
    iCtrlId == 1505
  Leaving fnBtnSubClass() With msg==WM_LBUTTONDOWN

  Entering fnWndProc_OnCommand()
    Wea.hWnd = 1050142
    Got Click Of Exit Button!
  Leaving fnWndProc_OnCommand()

  Entering fnWndProc_OnDestroy()
    Wea.hWnd = 1050142
  Leaving fnWndProc_OnDestroy()
Leaving WinMain()


Finally, about the conditional compilation statements and #ifdef TCLib.....

I don't use the typical MS build environment involving the C Runtime and LIBC - it creates executables that are much too large and bloated to suit my sensibilities (I learned programming in simpler times when binaries were small and not bloated). So I use my own custom and homemade C Runtime which creates small exes.

The command line compilation strings are at top. I only do command line compiling.

This is what you are looking for in terms of the subclass procedure, isn't it?

PS

I used the C++ compiler from VStudio 2015.
Last edited on
Hi and first thank you a lot for sharing your knowledge!

the API, C style syntax and function pointers are well known and not new to me, however I must admit the way you write window procedure and handle messages is absolutely alien to me :)
In a positive way of course, I've learned something new!

I for sure understand what the code does, basically you go low level by handling individual messages which which would otherwise be handled by default button procedure which would in turn send more high level messages to parent via WM_COMMAND, such as BN_CLICKED

I see now why I didn't come to this idea, it's because I made a base class (button in this case) which doesn't override these low level messages, but only adds it's own logic on top of existing logic implemented by default button procedure.

The reason for this was to reuse default painting and visual styles which I didn't need to modify beyond system defaults.

I understand from your code that, for any high level message (those sent to parent) I want to "eat" I'll have to handle all the individual logic which is behind that message.

And in the case of buttons it looks like eating the message also means I'll have to eat the painting?

I do have plans for adding real world custom controls to my project ex. for game interfaces, and when I do so I'll have your post in my mind!


Thank you friend a lot for help!.

EDIT:
Oh, I only don't understand, did you people really write window procedures that way in your times?

I mean, for loop can't be more efficient than switch statement, because in for loop you have to loop until there is a match for a message while switch statement acts something like a jump table from my understanding. so its a log(1) compared to for loop.

But maybe I'm wrong on that?
Last edited on

I mean, for loop can't be more efficient than switch statement, because in for loop you have to loop until there is a match for a message while switch statement acts something like a jump table from my understanding. so its a log(1) compared to for loop.


Funny you should ask that. Many years ago I asked myself the same question and spent at least a week writing all kinds of code to test it and I couldn't come up with much of a difference in execution speeds. Its tricky business making speed tests of things like that. The for loop technique if anything seemed a bit faster, but if I recall correctly it was real close. One thing to consider is speed sensitive message handlers can be put at the top of the switch, or in the case of the for loop situation as the first entry of the array.

I have the impression that not many coders use that technique I use. I first learned about it in my Windows CE coding through books by Douglas Boling who was kind of the 'Charles Petzold' of Windows CE coding writing such books as "Programming Windows CE". He ascribed the technique as belonging to a popular coding magazine author Ray Duncan - from 80s or 90s I think.

I think what happens to folks learning low level Windows Api coding is that they start with the switch construct and after they understand what's going on they try to write major programs using that design. What one ends up with are thousands of lines of code and only two procedures - a small WinMain() and a massive sprawling Window Procedure with a massive switch construct with thousands of lines of code. It becomes unwieldly and bugs creep in and pretty soon they give up and move on to some class framework or other.

For myself I never liked the class frameworks because I saw them as wrappers on a very object oriented API system written in C. I use classes a lot in my work and consider myself to be a C++ coder, but I respect and admire the C based Api for what it is - C based OOP. Note that most Api functions take a HWND as the 1st parameter of the function call. That is equivalent to the 'this' pointer in C++. Anyway, I have a tutorial on the use of the for loop technique here...

http://www.jose.it-berater.org/smfforum/index.php?topic=3391.0

Somewhere there on my board in Jose's Forum I have tutorials on custom controls too, i.e., how to make them, etc. Making custom controls and ActiveX controls was one of my main interests years ago. I guess my pride and joy was an ActiveX Grid Control I built using all low level code, that, when built with my custom C Runtime comes in at a whooping 13 k or something like that.

Glad I was able to help. I answered your question because I was pretty familiar with subclassing. I coded a lot of custom data entry routines, and it always seemed one needed to subclass edit controls to get just the behaviour one wanted. I'm glad you were able to follow the code. I really didn't feel like recoding it with a switch.
I would certainly attempt to not have to 'eat the painting'. God only knows (and maybe a few retired MS coders from long ago) how the painting works. I imagine if one 'eats' enough of the wrong messages, the control may soon become useless.

Of course, if some standard control can't seem to be modified or cajoled into doing what you need/want, then that puts one in the situation of having to write one's own control from scratch.
What one ends up with are thousands of lines of code and only two procedures - a small WinMain() and a massive sprawling Window Procedure with a massive switch construct with thousands of lines of code.

Haha, I've seen such procedures, and definitely agree with you such approach is ugly to see and maintain, but anyone with at least little xp, will write separate message handlers (functions) which are then called from window procedure.

Basically, the same approach as in your code sample except that windows procedure has a switch, with each case calling a handler instead of handling messages inline, and the switch become nice looking and easy to maintain.

for example here is my window procedure for MDI child window:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
LRESULT MdiWindow::HandleMessage(UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_SIZE:
		OnResize(wParam, lParam);
		break;

	case WM_PAINT:
		OnPaint();
		return 0;

	case WM_CLOSE:
		OnClose();
		return 0;

	case WM_DESTROY:
		return OnDestroy();

	case WM_NCDESTROY:
		OnNcDestroy(msg, wParam, lParam);
		return 0;

	case WM_GETMINMAXINFO:
		OnGetMinMaxInfo(lParam);
		break;

	case WM_SETTEXT:
		OnSetCaption(lParam);
		break;

        // etc...

	default:
		break;
	}

        return DefMDIChildProcW(mhWnd, msg, wParam, lParam);
}


Compared to window procedure which directly handles messages and doesn't invoke any handler I think this is easy to maintain, doesn't look ugly and efficiency isn't questionable either.

I would certainly attempt to not have to 'eat the painting'. God only knows (and maybe a few retired MS coders from long ago) how the painting works. I imagine if one 'eats' enough of the wrong messages, the control may soon become useless.


I will definitely investigate how it works, but I assume painting the button clicked message is directly tied to mouse messages, so if I eat them then the price is I'll have to do the painting as well.

Oh and thank for the link, I'll read the forums as needed, added into bookmarks :)
Last edited on
What happened to Sam123? He kind of raked me across the coals for my programming style - among other things. About that...I didn't make up that for loop setup for looking up messages in an array myself. As I mentioned, it came from Douglas Boling, who further credits Ray Duncan of PC Magazine for first developing it. These references can be found in "Programming Windows CE" by Douglas Boling published by Microsoft Press, and on the cover of that book it states that it is a 'Core Reference'. On the back of the first page of the book where the dates and copyrights are located it states that Microsoft Press is a division of Microsoft Corporation. The copyright of the 2nd edition, which is the one I have, is 2001. So the book was edited by technical editors from the Microsoft Windows CE team (it states that in the acknowledgements), and the author worked extensively with the Microsoft Windows CE development team on the sample programs in the book. This is from page 16 of the above referenced book by Douglas Boling...


My Programming Style

One criticism of the typical SDK style of Windows programming has always been the huge switch statement in the window procedure. The switch statement parses the message to the window procedure so that each message can be handled independently. This standard structure has the one great advantage of enforcing a similiar structure across almost all Windows applications, making it much easier for one programmer to understand the workings of another programmer's code. The disadvantage is that all the variables for the entire window procedure typically appear jumbled at the top of the procedure.

Over the years I've developed a different style for my Windows programs. The idea is to break up the WinMain and WinProc procedures into manageable units that can be easily understood and easily transferred to other Windows programs. WinMain is broken up into procedures that perform application initialiation, instance initialization, and instance termination. Also in WinMain is the ubiquitous message loop that's the core of all Windows programs.

I break the window procedure into indiviodual procedures, with each handling a specific message. What remains of the window procedure itself is a fragment of code that simply looks up the message that's being passed to see whether a procedure has been written to handle that message. If so, that procedure is called. If not, the message is passed to the default window procedure.

This structure devides the handling of messages into individual blocks that can be more easily understood. Also, with greater isolation of one message handling code fragment from another, you can more easily transfer the code that handles a specific message from one program to the next. I first saw this structure described a number of years ago by Ray Duncan in one of his old "Power Programming" columns in PC Magazine. Ray is one of the legends in the field of MS-DOS and OS/2 programming. I've since modified the design a bit to fit my needs, but Ray should get the credit for this program structure.


In case readers don't know, Windows CE was a really, really neat operating system developed by Microsoft which ran on small handheld devices. Where I worked for a large forestry land management organization we used it on our handheld data recorders which we used to record voluminous field data, i.e., timber and vegetation information. I did all the coding and development for that.

I'm just stating this further information to debunk Sam123's bogus claim that only a switch construct in the window procedure is 'sanctioned' by Microsoft for the parsing of Windows messages in the window procedure. There really is more to this though. I don't know for sure, but I really suspect that the various Windows programming class frameworks use this technique or something similiar in lieu of the switch construct for parsing messages in the window procedure. If one knows anything about .NET, look up the concept of 'delegates' in the .NET documentation. Part of their description is 'type safe function pointers'. They are most often used, it seems, in the calling of event/message handling routines - just as seen in my example program above. In fact, the one modification I made to the code from estemmed author Douglas Boling I borrowed from Microsoft's .NET framework, and that you can see in my WndfEventArgs struct from Form3.h...

1
2
3
4
5
6
7
struct WndEventArgs
{
 HWND                           hWnd;
 WPARAM                         wParam;
 LPARAM                         lParam;
 HINSTANCE                      hIns;
};


continued....
Where I got that idea from is .NET's proclivity to make a unique class as the single parameter pertaining to each event that can occur relating to an object, for example, painteventargs for an 'OnPaint' event...

https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.painteventargs?view=netcore-3.1

...or mouseeventargs for a mouse activity event....

https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.mouseeventargs?view=netcore-3.1

My adaptation of .NET's usage was somewhat more modest in that I simply amalgamate the four parameters of the window procedure into one simple struct I pass by reference (as in .NET) to all event procedures.

In terms of the possibility of the complicated looking affair slowing down the processing of messages, I have not seen that in any of the tests that I have run. I'm trying to find that old code I worked on something like almost 20 years ago but so far I have not been able to find it. I'll keep looking though. I've killed about four laptops between then and now and sometimes code gets lost :).

I'll tell you what I remember about the results though. I was mostly using PowerBASIC at the time and with that language one can code SDK style exactly like Petzold's C. What I seem to recall I did was try to time painting a screen pixel by pixel in a way that really worked the Window Procedure hard, and of course I timed it with GetTickCount or that other more precise version of it - I forget the name. So I compared the speeds of a program with the switch construct against one with Boling's for loop based function pointer setup. My original guess is that the for loop approach would be a bit slower. I'd do like 10 runs with each program then average the results. What I recall about it was that the averages were about the same. But interestingly, some of the fastest individual runs were with the for loop / function pointer approach. It was at that point I seriously considered adopting the approach into my coding style.

On a more personal note, malibor, when I first saw Boling's technique in his book I was somewhat appalled. At that point in my coding development I was somewhat proficient in C (not C++), and barely proficient in Petzold style C Win Api coding. In the previous year I had barely managed to get some SDK style Petzold type programms in my work domain working. They were really ugly with Window Procedures running on for thousands of lines. But at that point in my development I wasn't worried about such esoteric questions as overarching coding style as I was just simply comprehending how to get d*** code working! When I saw Boling's seemingly complicated message parsing code I pretty quickly understood what it was doing in general, but I realized that I would have to expend copious amounts of scarse mental calories into fully understanding it and 'making it my own'. So I never really adopted it as my own at that time. The simple switch construct worked for me.

But it worked on my mind year after year and eventually I took a stab at it. Over a period of about 10 years, in various stages, I incorporated it into my work. The very first thing I did was exactly as the code you posted where in a switch for WM_CREATE I called an OnCreate() function, in WM_PAINT an OnPaint() function, etc. But I kept the switch. In that first step I at least had a workable and simple code modularization design - and gone were the multi-thousand line window procedures. I think I flew with that for a couple years. But Boling's code still worked on my mind and played with me.

So the next step was to create the EVENTHANDLER Type/struct....

1
2
3
4
5
struct EVENTHANDLER
{
 unsigned int                   iMsg;
 LRESULT                        (*fnPtr)(WndEventArgs&);
};


... and get an array of them initialized. I think at first I used a pointer to an WndEventArgs instead of a C++ reference, but in any case I got that working and ran with it for a couple more years. I hadn't been doing it exactly like Boling though. Instead of this....

1
2
3
4
5
6
const EVENTHANDLER EventHandler[]=
{
 {WM_CREATE,                    fnWndProc_OnCreate},
 {WM_COMMAND,                   fnWndProc_OnCommand},
 {WM_DESTROY,                   fnWndProc_OnDestroy}
};


...I was doing something like so....

1
2
3
4
5
6
7
8
EVENTHANDLER EventHandler[2];

void AttachMessageHandlers()
{
 EventHandler(0).iMsg = WM_CREATE,   EventHandler(0).fnPtr = fnWndProc_OnCreate;
 EventHandler(1).iMsg = WM_COMMAND,  EventHandler(1).fnPtr = fnWndProc_OnCommand;
 EventHandler(2).iMsg = WM_DESTROY,  EventHandler(2).fnPtr = fnWndProc_OnDestroy;
}


And I'd call that function at the top of WinMain(). So that was like step 2. The final step was to finally adopt what Boling had with an array of EVENTHANDLER objects declared as const and the initializations performed all in one fell swoop as seen above and stuck/off loaded to an include file - the final elegant solution. And it likely took me 10 years to get there. So believe me, your initial astonishment at my presentation of that technique is understood. Long about 2000 when I first saw that code it was really important to me to get good at Windows CE and Windows SDK style coding, and my initial thought was 'Just how much pain am I going to have to endure to learn this stuff? But alls well that ends well I guess.

Finally, regarding Sam123's idea of creating an intermediate window between a control and the main window to somehow solve the problem we have been concerned with (intercepting events from a control's internal window procedure so as to modify the behavior of the control), I really fail to see how that will help. That's kind of like putting controls on a 'Group Box' - a Windows 'Common Control'. In that case the control's parent is the Group Box and the Group Box's parent is the main window, and the control sends WM_COMMAND messages (or whatever) to the Group Box (its parent). Maybe I'm not understanding what he was saying (I actually only got to read his post once before it was removed), but that idea doesn't seem to me to solve anything. Stuff is still happening in the internal and hidden window procedure of the control which we have no access to. So I'm a bit lost there.
Last edited on
Hi Freddie, I did drill into google a lot these days, because I was really stuck on how to reuse common controls provided by system in a way where I both retain full functionality of common controls such as painting, visual styles and and mouse processing and also be able to force them do the job which common controls want their parent to do (which made my design go questionable)

Basically the answer lies in OleCtl.h header which defines constants for message reflection!

You may already know this, but for the sake of future readers, these constants are in range
of WM_USER + some number up to WM_USER + some other number, meaning these do not clash with system messages.

Another advantage is that one doesn't need to define and maintain it's own constants.

I'll provide reference links where I harvested this knowledge later, but for now here is how it works:

I have a ParentWindow class which defines logic common to all windows that are parents,
and that even includes common controls such as groupbox common control which is both parent and child.

Here is how the parent sends messages back to it's childs (who ever these chids are) with comments on how it works:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// Message Reflection constants
#include <OleCtl.h>

// ParentWindow class is inherited by all windows that are parents
// This method reflects all messages that come from childs back to childs
LRESULT ParentWindow::ReflectMessage(UINT msg, WPARAM wParam, LPARAM lParam) noexcept
{
	switch (msg)
	{
	case WM_NOTIFY:
	{
		// Sent by a common control to its parent window when an event has occurred or
		// the control requires some information.
		NMHDR* nmhdr = reinterpret_cast<NMHDR*>(lParam);

		if (nmhdr && (nmhdr->hwndFrom != NULL))
			return SendMessageW(nmhdr->hwndFrom, msg + OCM__BASE, wParam, lParam);
		break;
	}

	// All of these provide the control's HHWND in LPARAM
	case WM_COMMAND:
	case WM_CTLCOLORBTN:
	case WM_CTLCOLOREDIT:
	case WM_CTLCOLORDLG:
	case WM_CTLCOLORLISTBOX:
	case WM_CTLCOLORMSGBOX:
	case WM_CTLCOLORSCROLLBAR:
	case WM_CTLCOLORSTATIC:
	case WM_VKEYTOITEM:
	case WM_CHARTOITEM:
		if (lParam != 0)
			return SendMessageW(reinterpret_cast<HWND>(lParam), msg + OCM__BASE, wParam, lParam);
		break;

		// All of these provide ID of the control in WPARAM:
	case WM_DRAWITEM:
	case WM_MEASUREITEM:
	case WM_DELETEITEM:
	case WM_COMPAREITEM:
		if (wParam != 0)
		{
			HWND hwndControl = GetDlgItem(mhWnd, static_cast<int>(wParam));

			if (IsWindow(hwndControl))
				return SendMessageW(hwndControl, msg + OCM__BASE, wParam, lParam);
		}
		break;

		// NOTE: we do not reflect WM_PARENTNOTIFY -> OCM_PARENTNOTIFY as that 
		// usually does not make much sense.
	default:
		break;
	}

        // Pure virtual calls derived class default proc. override
        // can be Subclass, MDI, normal Window, Dialog, FrameWidnow...
        // this is universal/generic parent!
	return CallDefaultProc(msg, wParam, lParam);
}


What happened to Sam123? He kind of raked me across the coals for my programming style - among other things.


Finally, regarding Sam123's idea of creating an intermediate window between a control and the main window to somehow solve the problem we have been concerned with (intercepting events from a control's internal window procedure so as to modify the behavior of the control), I really fail to see how that will help.


I have no idea what he was talking about and I'm glad I'm not the only one who disagrees with him.

Anyway regarding sam's "an intermediate window between a control and the main window", well faced the same problem with group box common control because group box is both parent and child, and if I want to handle messages that are coming from both parent and child and also from Windows system that doesn't mean I need separate handlers for same message (ex: WM_COMMAND may come from child but it may also come from parent)
because parent reflects those messages back to child control, GroupBox in this case.

Here is how window procedure for GroupBox look like in my case with above parent window message reflection:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// GroupBox class procedure both reflects messages to childs and also
// handles reflected messages from parent.
// Derives from CommonControl class and also ParentWindow class above
LRESULT GroupBox::HandleMessage(UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
		// Following messages are coming from child controls obviously
                // and what we do is reflect them back by calling ParentWindow::ReflectMessage
	case WM_COMMAND:
	case WM_CTLCOLORSTATIC:
	case WM_DRAWITEM:
                // this method virtually calls handlers from child, which have same signature
                // as this class own handlers, so not ambigous and pretty simple to maintain.
		return ReflectMessage(msg, wParam, lParam);


                 // Following messages are coming from parent,
                 // these are reflected and we can tell this from OCM_ prefix
                 // those sample handlers are protected for all sorts of windows
	case OCM_CTLCOLORSTATIC:
		return OnCtlColorStatic(msg, wParam, lParam);

	case OCM_COMMAND:
		return OnCommand(msg, wParam, lParam);

	case OCM_DRAWITEM:
		return OnDrawItem(msg, wParam, lParam);

	default:
              break;
	}

        // Call base class for common controls
	return CommonControl::HandleMessage(msg, wParam, lParam);
}


And finally what happens if child control didn't handle the message?
Parent window must have the result even if reflected message was not handled
Well if it's not handled simply call parent's default procedure, which is the same thing as if
parent didn't reflect the message at all haha :D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Indicates that window message is not reflected message
constexpr UINT WM_APP_NOT_REFLECTED = WM_APP + 1;

// Base class for all common controls
LRESULT CommonControl::HandleMessage(UINT msg, WPARAM wParam, LPARAM lParam)
{
        // check if we are dealing with reflected message
	const UINT reflected = TranslateReflected(msg);

	if (reflected != WM_APP_NOT_REFLECTED)
	{
		// Reflected message was not handled by child
                // call perent's default procedure, could be Dialog, MDI, Frame or whatever
		return mParent->CallDefaultProc(reflected, wParam, lParam);
	}
	break;

        // common controls are subclassed
	return SubClassWindow::HandleMessage(msg, wParam, lParam);
}


Major issue with OCM_BASE reflection messages defined in OleCtl.h header is that their values are not linear, so I had to write helper method for this:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// BaseWindow which is base for all window defines this since we have no clue
// which component may need message reflection
UINT BaseWindow::TranslateReflected(UINT msg) const noexcept
{
	switch (msg)
	{
	case OCM_COMMAND:
	case OCM_CTLCOLORBTN:
	case OCM_CTLCOLOREDIT:
	case OCM_CTLCOLORDLG:
	case OCM_CTLCOLORLISTBOX:
	case OCM_CTLCOLORMSGBOX:
	case OCM_CTLCOLORSCROLLBAR:
	case OCM_CTLCOLORSTATIC:
	case OCM_DRAWITEM:
	case OCM_MEASUREITEM:
	case OCM_DELETEITEM:
	case OCM_VKEYTOITEM:
	case OCM_CHARTOITEM:
	case OCM_COMPAREITEM:
	case OCM_HSCROLL:
	case OCM_VSCROLL:
	case OCM_PARENTNOTIFY:
	case OCM_NOTIFY:
                // simply substract to get original message back
		return msg - OCM__BASE;
	default:
		return WM_APP_NOT_REFLECTED;
	}
}


And that's it, common controls are now pwned haha :)

Of course this applies only to common controls, for custom made controls there is no point to reflect anything since you already handle all by yourself for each custom control anyway.

I understand your style doesn't involve switches in window procedure, but I just can't image to implement all this stuff with Window CE code style.

Well we all have our own style, and should use what ever works best for us.

Oh and of course here is how I learned about message reflection after fighting google for some hours:

https://www.codeproject.com/Articles/744603/Custom-Controls-in-Win-API-Encapsulation-of-Cust

Last edited on

Hi Freddie, I did drill into google a lot these days, because I was really stuck on how to reuse common controls provided by system in a way where I both retain full functionality of common controls such as painting, visual styles and and mouse processing and also be able to force them do the job which common controls want their parent to do (which made my design go questionable)

Basically the answer lies in OleCtl.h header which defines constants for message reflection!


Haven't posted in a couple days, but just had a brainstorm about it.

Been thinking about something I said earlier about the Windows Api being an example of C based OOP and all that - a view also expressed by Charles Petzold many years ago in the 90s when I first started learning to code this way. I still think its largely true, and I could go on and on about it, as I've a wont to do sometimes to the dismay of my readers, but this situation you are working on here is the exception I believe. In the case of a control sending WM_XXXXXXXX messages to its parent, and the parent having to fiddle with wParam/lParam to set properties of its child - I don't believe I'd personally qualify that as very good OOP. It looks like a failure of encapsulation, and private properties are leaking out all over the place like a sieve to me.

But what to do about it? Message Reflection looks like one answer (I learned about it from you - hadn't ever worked with it myself). But I think I'd personally tackle the problem in another way.

In the mid 90s I just loved the old deprecated pre - .NET Visual Basic. That language came out around 1991 or so as VB1 and finally ended with VB6 around 1998. It built to native executables and was not an interpreted language like .NET. It was completely COM (Component Object Model) based and worked off a drag and drop visual designer interface. One could drag a control from the 'toolbox' onto a visual representation of a Form/Window/Dialog - position it there and size it, then set properties in a 'Property Window'.

Alternatively, one could open up the 'code' window and set properties in code. It was OOP through and through. I recall how easy it was, for example, to set the ForeColor and BackColor of any control. Take a simple static control, for example. Visual Basic called them 'labels'. One could drag one onto a Form/Window/Dialog and it would be named 'label1'. To set the BackColor property and the ForeColor property in code one would open up the Code window to the Form_Load() event handler and do something like so....

1
2
3
4
5
6
Option Explicit

Private Sub Form_Load()
  label1.BackColor = &HFF   ' Red Back Color
  label1.ForeColor = &HFFFFFF  ' White Text
End Sub


Form_Load() event is about equivalent to a WM_CREATE message handler.

Have you ever tried to change the Back Color of any of the Windows 'Standard Controls' or 'Common Controls'? That's done with the WM_CTLCOLORSTATIC (and related) messages sent from the child to the parent. I'd describe the experience as something as pleasant as a root canal. One creates a BRUSH and stores it. The data transfer is through the wParam and lParam. Everything needs casting in one form or another. You seem to be a pretty experienced coder so I've a feeling you know what I'm talking about. It was kind of a shock to me to see how difficult that simple operation was after experiencing how easy that was to do in old Visual Basic. I never got into .NET much (I did some though), but they have the same setup there more or less as old pre .NET Visual Basic.

The reason I'm telling you all this is that I'd personally be more inclined to do what old Visual Basic did with all the controls if modifying their intrinsic behaviors was something I was going to make a habit of doing. In that old COM/OLE based Visual Basic, all the Standard Controls and Common Controls were made into COM/OLE Objects, and the interface they presented to the world (to their clients) were of the Object.Property type syntax. And of course there were ActiveX Controls. Actually, I think it would be safe to say that all the Controls were essentially ActiveX Controls. The ActiveX COM/OLE architecture 'wrapped' the underlying Standard and Common Controls.

Of course, COM/OLE could be avoided by simply making 'Custom Controls' out of everything. There could be an edit control for example, wrapped within a custom control - maybe named 'MyEdit', so on and so forth. But with Custom Controls the interface presented to the outside world is still kind of procedural and funky, and properties are set wit equates/defines or'ed together in the dwStyle parameter of the CreateWindow() call. With ActiveX one has a true OOP syntax.

Philosophically, I'm a COM guy and strongly believe in component architectures. I guess my experience with VB in the 90s had a big effect on me. I can't help thinking how difficult it would be incorporating all this stuff into a C++ Class Framework - Base Classes, inheritance - the works. One time years ago I spent about a month or two fooling around with building C++ based Class Frameworks and it kind of left me cold. That's why I use the Win Api 'streight' like I do, and save C++ Classes for 'business objects'. The other side of the issue though is that if you are needing to modify the behavior of the wrapped control, you still might have to code that message reflection stuff in the Custom Control or ActiveX Control. But at least the 'grunge code' would be out of your hair and safely tucked away in a dll never to be seen again - encapsulated away into seeming nonexistance.

I'm retired now and really don't have to deal with any of this, but coding still interests me. Maybe I ought to tackle a project like that for fun!

I'm just kind of brainstorming here malibor. Be interested in your thoughts though. And if you don't mind my asking, was there a specific thing you wanted a control to be able to do that precipitated your original question?
Last edited on
was there a specific thing you wanted a control to be able to do that precipitated your original question?

The major reason for all this is that, ie. any parent window can have any amount of controls attached to it's client area, it can also detach and attach new controls/windows on it's client area at any time, and if you want to write a reusable library then how do you know how to handle child messages such as WM_CTLCOLORSTATIC or WM_COMMAND if you have no clue what this child is or represents?

For example one child may need to paint it's background with parents background color, other child may need some other color.

If you hard code all this stuff into parent window, (as it is the design of Win32) then your parent window isn't reusable window. (but concrete object that does the default stuff for all his childs)

I want each window/control/dialog/menu item etc... to do things in dynamic way, and according to how these components are programmed, not on how it's parent window wants or does by default.

One parent can have many controls, but all those controls do their own predefined job independently of other childs and regardless who their parent is.

Parent window job is only to resize or move his childs and invoke events to which child windows respond again how ever child windows (that is it's invertor/user) want.

Ofc. Parent window can tell who is their child by looking at WPARAM and LPARAM, but these are just hardcoded integers defined by some coder and we have no clue what numbers will he assign to his controls, and you can't predefine those ID's yourself either, therefore not generic and not reusable at all.

Philosophically, I'm a COM guy and strongly believe in component architectures. I guess my experience with VB in the 90s had a big effect on me. I can't help thinking how difficult it would be incorporating all this stuff into a C++ Class Framework - Base Classes, inheritance - the works. One time years ago I spent about a month or two fooling around with building C++ based Class Frameworks and it kind of left me cold.


Agree with you on that, it's not easy but I've gotten so far already it would be mistake to give up xD, also I'm doing all this as a hobby, I have no bos sitting on my head and telling me how what to do/not to do, so it's pretty fun experience when you do it your own way.

Alternatively, one could open up the 'code' window and set properties in code. It was OOP through and through. I recall how easy it was, for example, to set the ForeColor and BackColor of any control.

...

The reason I'm telling you all this is that I'd personally be more inclined to do what old Visual Basic did with all the controls if modifying their intrinsic behaviors was something I was going to make a habit of doing. In that old COM/OLE based Visual Basic, all the Standard Controls and Common Controls were made into COM/OLE Objects, and the interface they presented to the world (to their clients) were of the Object.Property type syntax.


I'm not really a fan of the NET framework, it's indeed easy and quick to do things, and API looks much nicer than C, Win32 or C++ etc.
Primary reason is limitations which get to the surface sooner or later and then what?, and overall it doesn't fit my style of coding.

A lot of people seem to be recommending to do things in a simple way and to avoid reinventing the wheel, expressing development productivity which you gain by using .NET, but, I'm just not one of those people :)

Again thank you for your recommendations, will be definitely useful for making own controls from scratch.
Last edited on
Topic archived. No new replies allowed.