template fn replacements for msg macros

This is a discussion on template fn replacements for msg macros within the Windows Programming forums, part of the Platform Specific Boards category; I've been toying with template functions as a first step/ exploration/attempt to devise a c++ replacement for message macros from ...

template fn replacements for msg macros

I've been toying with template functions as a first step/ exploration/attempt to devise a c++ replacement for message macros from mainly windowsx.h. I've read some stuff on line - comparisons of different templatised techniques, functors etc and am using Stroustrup's C++ and Josuttis for reference.

In general: I have a base wnd class (C++) from which is derived various windows and controls, the hierarchy is something like BaseWnd::Wnd::MainWnd where MainWnd is a 'container' or frame for just about everything else. Currently I use a static wndproc which forwards messages to a virtual class wndproc which is overridden in descendant classes as required. I use msg macros in these virtual wndprocs as follows, eg:

When I speak of failure what I mean is that the handler called is always the one currently in scope ie MainWnd::OnEraseBkGrd.

So, if anyone has been there and done that could you please give me some hint as to how I might coerce the template to call any handler in the class hierarchy I might explicitly choose or perhaps an explanation of why it's not possible to do so. Note that the handler functions (C++), in this case OnEraseBkgrd, are virtual.

...where each class may have defined f(), and you now want object of type classD use classB's f() ?

I had the same problem, but never ended up solving it due to other issues[ templates<can suck sometimes> ]

BUT I may be working on that problem in the next few,
if I stumble upon anything I'll PM or EM you....

One thing, though. From the looks of it, you are passing the MainWin's "this" to every handler. Am I wrong? Or is it that you just have a WindProc for every object? Confused there...FYI, I have discarded the WindProc in favor of a simpler method. In fact, I'll just tell you about it real quick Ok. Basically, a class simply "registers" a message it's interested in and at the same time, passes in the handler. The handler is cast to a pointer to the very lowest base-class type, and it and the message are added to a list that every object builds up. A sort of internalized message loop.

Now that may not lend itself to your coding preferences very much (void functions, etc...) but the message mapping facility is handy. Also, the lack of a visible WindProc makes coding move quicker. The above program compiles and runs as is, and although simple, is a hundred lines shorter than the straight API version. Again, I realize you are close to finishing that framework, but there are crumbs that can be scavanged here.. I would really like to see what route you're taking, in more detail, if you don't mind. I've revised mine so much I don't know which I'm working on at the moment, and I always seem to be yearning for better ideas =)

First off, thanks very much for your thoughtful and detailed reply,Sebastiani - much appreciated.

>>...where each class may have defined f(), and you now want object of type classD use classB's f() ?<<

Yes; although, realistically, I would probably only want the facility for 'completeness' and debugging purposes.

>>One thing, though. From the looks of it, you are passing the MainWin's "this" to every handler. Am I wrong? Or is it that you just have a WindProc for every object?<<

Yes, I am passing this to each global inline template function msg cracker. This is a first pass using templates so before I start encapsulating their functionality with c++ classes I want to see how the syntax works and the processes resolve themselves: in short it's experimental. As I said previously I have a static wndproc that works pretty much the same as your own with the GetWindowLong/SetWindowLong for retrieval and setting of a 'window c++ class object' pointer. This then calls a virtual WndProc (called 'MsgProc') which is overriden in derived classes. The top level class is the only one that really does any handling/cracking of messages, those lower in the hierarchy exist simply for default msg handling.

This is the reason for my interest in templates: I want to purge all macros (if possible). Otherwise i'm very happy with using HANDLE_MSG macros as they do everything I require (apparently safely), when I require and where I require. I have examined similar techniques of using message 'registration' fns with or without look-up tables but am currently of the opinion that they are an unnecessary complication - that view may change.

>>Again, I realize you are close to finishing that framework, but there are crumbs that can be scavanged here<<

Actually the 'framework' was complete a couple of years ago, the only new thing is the experiment with templates. Previously i've been reluctant to even consider dropping HANDLE_MSG macros but I keep reading that macros in c++ are the devil's work..

>>I would really like to see what route you're taking, in more detail, if you don't mind.<<

I will pm you.

>>I've revised mine so much I don't know which I'm working on at the moment<<

Mine is fairly stable and only minor tweaks to test newer notions from time to time.

>>and I always seem to be yearning for better ideas<<

OK. Here's a possible one, if you haven't already investigated to circumvent the hassle of this being unavailable through GetWindowLong until the arrival of the WM_NCCREATE msg: using a CBTProc hook procedure, setting the hook before the call to CreateWindowEx and unhooking on return from the CreateWindowEx. By registering your app as a computer based training app, you get the wnd handle and therefore access to lpCreateParams(?) before any message is dispatched to your window procedure. There are two downsides, one minor the other major. The minor downside is that the hook procedure is slower but since it is active only during window creation the very tiny performance hit is negligible. The second downside is a major pain (unless you maybe use global variables which will impact on thread safety): mdi windows can't easily be tamed by this method and cause horrible crashes that vary in seriousness between win98 and win2k. Of course, if you're not using mdi's then this technique is the way to go. I'm sure there is probably a way to avoid the troubles I have had with mdi's too.

The various strategies people use to tame win32 API to c++ classes is a minor obsession of mine, so I fully understand and share your 'yearning' in this area.

So you want to emulate the macros of windows API with templates because macros are gross. hmmmm... I've always been fine with just a virtual int CallBack(UINT message, WPARAM wParam, LPARAM lParam); in the top base class. I usually don't look to hide the way the API works when I write my code. a class with an HWND, a CallBack(), a CreateWindow(), etc... should get the job done nicely. Do you just not like seeing the switch?

edit: I just realized what you're doing. I don't however see the need for the HANDLE_MSG macro and I usually remove it from code where I see it. I would rather see what's going on behind that macro in the code in front of me. That's just me though.

I vaccilate between two extremes: Liking the "look" of straight code ( it looks complex and sophisticated ) and wanting the most expedient method to accomplish something ( looks like Java, ugh! ). To be honest, I can't make up my mind! What I should do is write a program that will expand the latter into the former and condense the former into the latter, on command. /*strikes head: "doh! no more projects!"*/ In a way, C++ is a sickness because it encourages profuse abstraction, and at the end of the day you find yourself writing programs you loved to hate as a C programmer:

really, I'm not saying abstraction is bad. But using templates as if they are macros gives you all the bad things we hate about macros! obvious exceptions include being able to step through the thing in the debugger.

I like the abstraction/structure that C++ gives you but I believe templates serve a much bigger purpose than just a glorified or C++ macro. That's all I'm saying. I think abstraction should live behind the boundaries of class interface, that's all. The code should be straight forward and macro free. My angle is not one of disliking abstraction but one of not obuscating my code. U C ?

Where are you getting the impression that anyone thinks that you have said so? ::surprised::

>>FYB:But using templates as if they are macros<<

>>KenF: as a first step/ exploration/attempt to devise a c++ replacement for message macros<< and >>KenF: in short it's experimental.<<

>>FYB: obvious exceptions include being able to step through the thing in the debugger.<<

>>KenF: I would probably only want the facility for 'completeness' and debugging purposes.<<

>>FYB: That's all I'm saying.<<

Yep. Got that. Twice now.

>>FYB: not obuscating my code.<<

What's obfuscating to one is crystal clear to another. For instance:

Code:

HANDLE_MSG(hwnd,WM_ERASEBKGND,OnEraseBkGrd);

is a lot clearer to me personally than:

Code:

OnEraseBkGrd(hwnd,(HDC)wParam);

or:

Code:

OnEraseBkGrd(hwnd,reinterpret_cast<HDC>(wParam));

or even:

Code:

OnEraseHandler(this,&MainWnd::OnEraseBkGrd,hwnd,wParam,lParam);

I'm in good company too: J. Richter of Programming Apps for Ms Windows (4th ed.) fame uses msg macros - in c++ too - and has even gone so far as to devise macros to ensure the correct return type for dialogprocs (ie BOOL). As another example, I am not content to use 'int CallBack(UINT message, WPARAM wParam, LPARAM lParam);' because the API lists LRESULT as the correct return type for a wndproc and indeed, the definitions for LRESULT are different in the aug2001psdk windef.h than in previous versions; using the ms defined LRESULT ensures better future proofing, in my view anyway.

So, once more, each to their own, eh?

>>FYB: The code should be straight forward and macro free.<<

I agree, but straight forward, like obfuscation, appear to be fairly subjective.

>>FYB: UC?<<

Good Lord! Subtlety? At cprog? Surely not. I've a good mind to report you to the mods for that one.

No disrespect intended to your good self, but what you're really saying, FYB, getting back to my original question of:

>>KenF: please give me some hint as to how I might coerce the template to call any handler in the class hierarchy I might explicitly choose or perhaps an explanation of why it's not possible to do so.<<

is that you don't know?

While your opinions are always most welcome and interesting to consider, major appreciation points are there to be won if you can actually answer the question.

You should research "the command pattern" first documented in the Gang of Four book Design patterns:Elements of reuseable object-oriented software.
You should invest in the Andrei Alexandrescu book Modern c++ design. This devotes a whole chapter to generalising "the command pattern" with functors.

woah, KF. I wasn't being nearly as confrontational as it seems I appeared. sorry chief. I just was trying to understand the rational behind what you're doing.

Good Lord! Subtlety? At cprog? Surely not. I've a good mind to report you to the mods for that one.

I'm probably just slow but I don't get this. (plus I didn't get much sleep last night)

not having read the entire set of Sebastiani responses I don't know that you've come to a conclusion but your template function's T and W are being set to the base class. so you are getting a function pointer to the base class handler. You are bypassing C++'s built in polymorphism by using the passed in function. Why not use non-global methods on the ObjPtr instead? that would not bypass the polymorphism you're trying to obtain. The only other alternative is to pass in the proper T and W instead at the inherited class.

Then it would expand to the proper handlers by sending in T as the class for the handler functions as well. Then you'd get the right class's handler functions. This way you can keep your inline and pretend to be polymorphic at the same time (which I assume is one of the goals).