Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Those dang window message dispatcher macros again, too unclean?

125 views
Skip to first unread message

Alf P. Steinbach

unread,
Dec 21, 2016, 11:10:18 PM12/21/16
to
Typical usage in workgin toy program:

auto on( winapi::Message const& m ) noexcept
-> winapi::Lresult
override
{
#define WINAPI_MESSAGE_HANDLER_CLASS Main_window
switch( m.message_id )
{
WINAPI_DISPATCH( m, WM_COMMAND, on_wm_command );
WINAPI_DISPATCH( m, WM_PAINT, on_wm_paint );
WINAPI_DISPATCH( m, WM_SIZE, on_wm_size );
}
return subclassing_.original_processing( m );
#undef WINAPI_MESSAGE_HANDLER_CLASS
}

Definitions:

// These macros dispatch a window message to a member function via
the message
// cracker macros in <windowsx.h>. For example, message name
WM_PAINT yields
// a call via the HANDLE_WM_PAINT message cracker macro. See
<windows.h> for
// the required signatures for handlers; remove the window handle
argument.

// #define WINAPI_CRACKER_MACRO( message_name ) HANDLE_ ## message_name

#define WINAPI_DISPATCH_TO_MEMFN_VIA( message_cracker_macro,
memfunc, m ) \
message_cracker_macro ( \
this, m.wparam, m.lparam, std::mem_fn( &memfunc ) \
)
#define WINAPI_DISPATCH_TO_MEMFN( message_name, memfunc, m ) \
WINAPI_DISPATCH_TO_MEMFN_VIA( HANDLE_ ## message_name, memfunc, m )

#define WINAPI_DISPATCH( m, message_name, handler ) \
case message_name: return WINAPI_DISPATCH_TO_MEMFN_VIA( \
HANDLE_ ## message_name,
WINAPI_MESSAGE_HANDLER_CLASS::handler, m \
)

I've done this so many times in the past, with C++03. But I feel that
there must be some less unclean modern C++-ish way. Ideas?

Cheers!,

- Alf

Richard

unread,
Dec 22, 2016, 3:51:14 PM12/22/16
to
[Please do not mail me a copy of your followup]

"Alf P. Steinbach" <alf.p.stein...@gmail.com> spake the secret code
<o3fjk8$c40$1...@dont-email.me> thusly:

>I've done this so many times in the past, with C++03. But I feel that
>there must be some less unclean modern C++-ish way. Ideas?

My question is:

Why are you reinventing the wheel?

These message cracker macros have already been done in the Windows
headers, MFC and ATL.

ATL is now available with Community Edition, so there is no longer a
dollar cost to selecting ATL for use in your program.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

Alf P. Steinbach

unread,
Dec 22, 2016, 5:22:56 PM12/22/16
to
On 22.12.2016 21:51, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> "Alf P. Steinbach" <alf.p.stein...@gmail.com> spake the secret code
> <o3fjk8$c40$1...@dont-email.me> thusly:
>
>> I've done this so many times in the past, with C++03. But I feel that
>> there must be some less unclean modern C++-ish way. Ideas?
>
> My question is:
>
> Why are you reinventing the wheel?

Well I'm not, but I'm reimplementing my wheels from scratch for
umpteen'th time.


> These message cracker macros have already been done in the Windows
> headers, MFC and ATL.

The macros above delegate the cracking (de-serialization, so to speak)
to the Windows C API macros.

MFC and as I recall also ATL/WTL use message maps: they're ungood.

MFC and ATL do not really ease anything except the basic window
creation, which is a single little job to put together. In exchange for
providing a default implementation of window creation (and at one time,
providing print preview and COM boiler plate code) they impose a steep
programmers' time overhead: one has to do detective work for every other
little detail. MFC suffered from being deliberately dumbed down from the
original AFX framework goals, and from being a 1990's design, while
ATL/WFC suffers from being designed by incompetents, including the goal
of running ActiveX controls in a browser (imagine that idea! shudder!),
even though there's some modern C++ stuff like templating.


> ATL is now available with Community Edition, so there is no longer a
> dollar cost to selecting ATL for use in your program.

I think maybe you mean WTL, which was derived from ATL.

Unless they've rebranded, which they sometimes do?


Cheers!,

- Alf

Richard

unread,
Dec 22, 2016, 6:59:57 PM12/22/16
to
[Please do not mail me a copy of your followup]

"Alf P. Steinbach" <alf.p.stein...@gmail.com> spake the secret code
<o3hjkv$966$1...@dont-email.me> thusly:

>> ATL is now available with Community Edition, so there is no longer a
>> dollar cost to selecting ATL for use in your program.
>
>I think maybe you mean WTL, which was derived from ATL.

WTL was always free, but it built on ATL which wasn't free until the
recent versions of VS Community Edition.

Tim Rentsch

unread,
Dec 23, 2016, 2:02:08 AM12/23/16
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:

> Typical usage in workgin toy program:
>
> auto on( winapi::Message const& m ) noexcept
> -> winapi::Lresult
> override
> {
> #define WINAPI_MESSAGE_HANDLER_CLASS Main_window
> switch( m.message_id )
> {
> WINAPI_DISPATCH( m, WM_COMMAND, on_wm_command );
> WINAPI_DISPATCH( m, WM_PAINT, on_wm_paint );
> WINAPI_DISPATCH( m, WM_SIZE, on_wm_size );
> }
> return subclassing_.original_processing( m );
> #undef WINAPI_MESSAGE_HANDLER_CLASS
> }
>
> Definitions:
>
> // These macros dispatch a window message to a member function
> // via the message cracker macros in <windowsx.h>. [...]
>
> I've done this so many times in the past, with C++03. But I feel
> that there must be some less unclean modern C++-ish way. Ideas?

I share your reaction, but what is it you hope to accomplish? The
definition for WINAPI_DISPATCH can be simplified fairly easily I
think (and get rid of the others), which also could make it possible
to write

switch( m.message_id ){
WINAPI_DISPATCH( m, WM_COMMAND, Main_window, on_wm_command );
WINAPI_DISPATCH( m, WM_PAINT, Main_window, on_wm_paint );
WINAPI_DISPATCH( m, WM_SIZE, Main_window, on_wm_size );
}

so the surrounding #define/#undef would not be needed. But what is
it you are looking for?

Manfred

unread,
Dec 23, 2016, 9:35:34 AM12/23/16
to
On 12/22/2016 11:22 PM, Alf P. Steinbach wrote:
>
> The macros above delegate the cracking (de-serialization, so to speak)
> to the Windows C API macros.
>
> MFC and as I recall also ATL/WTL use message maps: they're ungood.
>
> MFC and ATL do not really ease anything except the basic window
> creation, which is a single little job to put together. In exchange for
> providing a default implementation of window creation (and at one time,
> providing print preview and COM boiler plate code) they impose a steep
> programmers' time overhead: one has to do detective work for every other
> little detail. MFC suffered from being deliberately dumbed down from the
> original AFX framework goals, and from being a 1990's design, while
> ATL/WFC suffers from being designed by incompetents, including the goal
> of running ActiveX controls in a browser (imagine that idea! shudder!),
> even though there's some modern C++ stuff like templating.
>
>
I agree on all of your critics to MFC/ATL, but I haven't find a good
dispatch method either.
Basically the problem is to map a (HWND, WM_PAINT) pair to a
window->on_wm_paint() handler.
I am no fan of switch or maps for this, and it looks to me too that
there should be a better way to accomplish this - in the end, it is what
a virtual method call would be for.

If I remember correctly, from a long time ago, Borland's Turbo C++ used
the extra window bytes to store the window object pointer, and used some
tweaking of the vtable in place of the switch statement (at least this
is what it looked like from the sintax I remember). Both of which were
rather non-portable, but in my memory would be in the direction to a
better dispatching - obviously if it were done with the facilities
offered by nowadays's standard.

>
> Cheers!,
>
> - Alf
>

Alf P. Steinbach

unread,
Dec 23, 2016, 9:50:38 AM12/23/16
to
On 23.12.2016 08:02, Tim Rentsch wrote:
> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>
>> Typical usage in workgin toy program:
>>
>> auto on( winapi::Message const& m ) noexcept
>> -> winapi::Lresult
>> override
>> {
>> #define WINAPI_MESSAGE_HANDLER_CLASS Main_window
>> switch( m.message_id )
>> {
>> WINAPI_DISPATCH( m, WM_COMMAND, on_wm_command );
>> WINAPI_DISPATCH( m, WM_PAINT, on_wm_paint );
>> WINAPI_DISPATCH( m, WM_SIZE, on_wm_size );
>> }
>> return subclassing_.original_processing( m );
>> #undef WINAPI_MESSAGE_HANDLER_CLASS
>> }
>>
>> Definitions:
>>
>> // These macros dispatch a window message to a member function
>> // via the message cracker macros in <windowsx.h>. [...]
>>
>> I've done this so many times in the past, with C++03. But I feel
>> that there must be some less unclean modern C++-ish way. Ideas?
>
> I share your reaction, but what is it you hope to accomplish?

Something ... less macro-ish, I guess. :)

Or if you mean what these macros do (i.e. message cracking is not a
familiar term to you, it is after all very Windows API-level specific),
they take 64 bits of information in a specific packed message, unpacks
that into 0 to about 4 argument values depending on the message, and
calls a specified handler function with those unpacked arguments.

The problem is the knowledge of how to pack/unpack specific messages: it
is of course documented, but the only API level support for packing, the
only /code/ for that that can be leveraged, is as far as I know provided
by the macros from <windowsx.h>.


> The
> definition for WINAPI_DISPATCH can be simplified fairly easily I
> think (and get rid of the others), which also could make it possible
> to write
>
> switch( m.message_id ){
> WINAPI_DISPATCH( m, WM_COMMAND, Main_window, on_wm_command );
> WINAPI_DISPATCH( m, WM_PAINT, Main_window, on_wm_paint );
> WINAPI_DISPATCH( m, WM_SIZE, Main_window, on_wm_size );
> }
>
> so the surrounding #define/#undef would not be needed.

Oh, thanks. :) But I added the #define/#undef mechanism to avoid having
to repeat the class name. Mostly for convenience and the DRY principle,
Don't Repeat Yourself, but also because conceivably the class name could
in some instance be a template expression with commas in it.

(There is a simple workaround for comma in a macro argument, namely
always enclose that argument in parentheses, and unpack it in the macro,
but that adds some dirtyness again. Another workaround is to define a
macro symbol as comma, but that's really dirty.)


> But what is it you are looking for?

I don't know.

Some really out-of-the-box idea, I guess.

Or maybe there is a library somewhere that (just) provides unpacking of
most all defined window messages, like that.

Hm, now you me thinking.


Cheers!,

- Alf

Tim Rentsch

unread,
Dec 23, 2016, 3:29:50 PM12/23/16
to
Yes, I read up on those and looked up the definitions in
windowsx.h.

> The problem is the knowledge of how to pack/unpack specific messages:
> it is of course documented, but the only API level support for
> packing, the only /code/ for that that can be leveraged, is as far as
> I know provided by the macros from <windowsx.h>.

If you want to use the supplied support for message cracking, and
that support exists only the form of macros, then I think you're
pretty much stuck with macros. You can make your own macro
definitions prettier, and maybe do something so that you get
better flow for function/method calls, but unless you're willing
to re-implement (some of) the HANDLE_xxx macro functionality, it
seems like using macros is basically inevitable.


>> The
>> definition for WINAPI_DISPATCH can be simplified fairly easily I
>> think (and get rid of the others), which also could make it possible
>> to write
>>
>> switch( m.message_id ){
>> WINAPI_DISPATCH( m, WM_COMMAND, Main_window, on_wm_command );
>> WINAPI_DISPATCH( m, WM_PAINT, Main_window, on_wm_paint );
>> WINAPI_DISPATCH( m, WM_SIZE, Main_window, on_wm_size );
>> }
>>
>> so the surrounding #define/#undef would not be needed.
>
> Oh, thanks. :) But I added the #define/#undef mechanism to avoid
> having to repeat the class name. Mostly for convenience and the DRY
> principle, Don't Repeat Yourself, but also because conceivably the
> class name could in some instance be a template expression with commas
> in it.

Yes, I thought something like that might be true. However a
similar comment still applies, as for example (disclaimer: not
compiled):

switch( m.message_id ){
#define TAKE( E, M ) WINAPI_DISPATCH( m, E, Main_window, M )
TAKE( WM_COMMAND, on_wm_command );
TAKE( WM_PAINT, on_wm_paint );
TAKE( WM_SIZE, on_wm_size );
#undef TAKE
}

This way at least you won't have hidden dependencies in your
macro definitions.

> (There is a simple workaround for comma in a macro argument, namely
> always enclose that argument in parentheses, and unpack it in the
> macro, but that adds some dirtyness again. Another workaround is to
> define a macro symbol as comma, but that's really dirty.)

Roger that. I believe the above technique still applies, with a
parenthesized comma needed in only one macro call.


>> But what is it you are looking for?
>
> I don't know.
>
> Some really out-of-the-box idea, I guess. [...]

My sense is there is something to be done here, depending on what
it is you hope to achieve.

One idea (which I haven't worked out in any detail) is to re-do
the functionality of whatever HANDLE_xxx macros you need (and I
don't mean as macros necessarily), in such a way that you can
check your implementation against the macros in <windowsx.h>.
That would let you get away from using the HANDLE_xxx macros,
but not have to worry about some sort of version skew/drift.

One question I have is, what does the message flow look like,
and/or what would you like it to look like? The idea of bundling
up pointer-to-member-functions (assuming I'm understanding that
right), and passing 'this' as a parameter, is one I find somewhat
repugnant. But I'm hampered by not understanding what message
flow is being used, and what message flow is ultimately desired.

Alf P. Steinbach

unread,
Dec 23, 2016, 5:06:54 PM12/23/16
to
On 23.12.2016 21:29, Tim Rentsch wrote:
> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>
>> [snip]
>> Oh, thanks. :) But I added the #define/#undef mechanism to avoid
>> having to repeat the class name. Mostly for convenience and the DRY
>> principle, Don't Repeat Yourself, but also because conceivably the
>> class name could in some instance be a template expression with commas
>> in it.
>
> Yes, I thought something like that might be true. However a
> similar comment still applies, as for example (disclaimer: not
> compiled):
>
> switch( m.message_id ){
> #define TAKE( E, M ) WINAPI_DISPATCH( m, E, Main_window, M )
> TAKE( WM_COMMAND, on_wm_command );
> TAKE( WM_PAINT, on_wm_paint );
> TAKE( WM_SIZE, on_wm_size );
> #undef TAKE
> }
>
> This way at least you won't have hidden dependencies in your
> macro definitions.

I tried roughly that approach at first. But it turned out to be
difficult to avoid macro expansion of a name like WM_PAINT. Each message
name expands to some hex number, e.g. 0x000F for WM_PAINT, which would
generate a macro invocation like HANDLE_0x000F instead of HANDLE_WM_PAINT.

As a language extension Visual C++ supports writing ##WM_PAINT as actual
macro argument, which prevents expansion. However g++ will have none of
that.


>> (There is a simple workaround for comma in a macro argument, namely
>> always enclose that argument in parentheses, and unpack it in the
>> macro, but that adds some dirtyness again. Another workaround is to
>> define a macro symbol as comma, but that's really dirty.)
>
> Roger that. I believe the above technique still applies, with a
> parenthesized comma needed in only one macro call.
>
>
>>> But what is it you are looking for?
>>
>> I don't know.
>>
>> Some really out-of-the-box idea, I guess. [...]
>
> My sense is there is something to be done here, depending on what
> it is you hope to achieve.
>
> One idea (which I haven't worked out in any detail) is to re-do
> the functionality of whatever HANDLE_xxx macros you need (and I
> don't mean as macros necessarily), in such a way that you can
> check your implementation against the macros in <windowsx.h>.
> That would let you get away from using the HANDLE_xxx macros,
> but not have to worry about some sort of version skew/drift.

I think I can maybe add a layer on top, like an extensible collection of
message-specific dispatcher, starting with ones that can be expressed in
terms of Microsoft's HANDLE_... macros.


> One question I have is, what does the message flow look like,
> and/or what would you like it to look like? The idea of bundling
> up pointer-to-member-functions (assuming I'm understanding that
> right), and passing 'this' as a parameter, is one I find somewhat
> repugnant. But I'm hampered by not understanding what message
> flow is being used, and what message flow is ultimately desired.

Oh, the flow.

The Windows API's support for windowing – GUI stuff – was a sort of
early 1980's rewrite in C of the GUI ideas from the Xerox PARC Smalltalk
project, I think (but I'd have to google it to be sure of this claim) at
least in large part via Apple's participation in Xerox' technology
transfer program. So it's like a dynamic language OO design, except
everything is down at the nitty gritty C level, and with Microsoft
“let's do the entirely unexpected and unpredictable” twists.

Each window object has a single C function that does its message
processing; the first argument is a handle value that identifies the
window object. This function is called its “window procedure” (I think
this may be a terminology transfer from use of Pascal over at Apple). A
call of a window's window procedure with a given message, corresponds to
a call of virtual function on a C++ class type object – or a message in
Smalltalk (I think definitely the “message” terminology here transferred
from the use of Smalltalk at Xerox PARC and at first over at Apple, with
Apple's Smalltalk-based Lisa machine, before the Mac).

The window procedure can be invoked directly by Windows, and by the
application code for messages that it retrieves from a message queue.

The general problem that the API design doesn't directly support in a
practical way, is to associate a window object with /state/. The design
only supports uninterpreted raw bytes as state, then accessed in an
inefficient way as bytes via OS calls. A C++ class type object is much
more practical as state, then with processing of each message in a
member function, so every C++ /GUI framework/ replaces the window
procedure of each window, with one that forwards each call (message
processing) to a corresponding general window-procedure like member
function on a C++ object, where ideally the message is unpacked, and a
corresponding message-specific member function is called with the args.

Cheers!,

- Alf

PS: I have wrapped this thing earlier and in many different ways, but
it's all been based on re-implementing the message unpacking. I'd rather
use Microsoft's macros, their own code, which in essence /defines/ the
proper unpacking. Except it's so ugly. :)

Tim Rentsch

unread,
Dec 29, 2016, 5:31:51 PM12/29/16
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:

> On 23.12.2016 21:29, Tim Rentsch wrote:
>> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>>
>>> [snip]
>>> Oh, thanks. :) But I added the #define/#undef mechanism to avoid
>>> having to repeat the class name. Mostly for convenience and the DRY
>>> principle, Don't Repeat Yourself, but also because conceivably the
>>> class name could in some instance be a template expression with commas
>>> in it.
>>
>> Yes, I thought something like that might be true. However a
>> similar comment still applies, as for example (disclaimer: not
>> compiled):
>>
>> switch( m.message_id ){
>> #define TAKE( E, M ) WINAPI_DISPATCH( m, E, Main_window, M )
>> TAKE( WM_COMMAND, on_wm_command );
>> TAKE( WM_PAINT, on_wm_paint );
>> TAKE( WM_SIZE, on_wm_size );
>> #undef TAKE
>> }
>>
>> This way at least you won't have hidden dependencies in your
>> macro definitions.
>
> I tried roughly that approach at first. But it turned out to be
> difficult to avoid macro expansion of a name like WM_PAINT. Each
> message name expands to some hex number, e.g. 0x000F for WM_PAINT,
> which would generate a macro invocation like HANDLE_0x000F instead of
> HANDLE_WM_PAINT. [...]

(Before I start, thank you for the later explanation of message
flow. I think I was able to figure out what I was looking for.)

Well, that is annoying. Normally I would expect those would be
enumeration constants, but I guess they are macros instead.

After seeing this message, I looked into this more deeply.
Basically, if you want to handle cracking "automatically" rather
than by hand, I think you're stuck with some sort of macro
solution. (Disclaimer: I know essentially nothing about the
newer variadic template stuff.) However, and here is the good
news, I think a macro solution can be constructed that is a lot
simpler than the earlier ones. Here is my example file,
including some minor warts (partly because the environment is
linux but with a -I to get the MS windows header files, and also
I dummied up a 'winapi' since I didn't discover one otherwise),
which compiles.

The definition of SELF_ON() is the key item to look at - does
this approach seem cleaner to you? I would be inclined to
use something like this.

=============================================================================
#define __i686__ 1
#include <windows.h>
#include "generated/crackit.h"

struct winapi {
struct Message {
UINT message_id;
WPARAM wParam;
LPARAM lParam;
};
typedef LRESULT Lresult;
};

struct Base {
virtual winapi::Lresult on( winapi::Message const& m ) = 0;
};

#define SELF_ON( type, m ) \
case type: return CRACK_##type( this->on_##type, (m).wParam, (m).lParam )

struct Sample : Base {
auto on( winapi::Message const& m ) noexcept
-> winapi::Lresult
override
{
switch( m.message_id ){
SELF_ON( WM_COMMAND, m );
SELF_ON( WM_SIZE, m );
SELF_ON( WM_PAINT, m );
}
return 0; //subclassing_.original_processing( m );
}

winapi::Lresult on_WM_COMMAND( ULONG a, HWND b, ULONG c ){ return 0; }
winapi::Lresult on_WM_SIZE( ULONG a, ULONG b, ULONG c ){ return 0; }
winapi::Lresult on_WM_PAINT(){ return 0; }
};

=============================================================================

The definitions for the CRACK_... macros (ie, in the generated
file "generated/crackit.h") are produced programmatically from
the HANDLE_... macros in <windowsx.h>, using a short awk script:

#! /bin/awk -f

$0 ~ /#define HANDLE_WM_/ {
gsub( /[(]hwnd,/, "(fn," );
gsub( /,fn[)]/, ")" );
gsub( /[(][(]hwnd[)],/, "(" );
gsub( /[(]fn[)][(]hwnd[)]/, "(fn)()" );
gsub( / HANDLE_/, " CRACK_" );
print
}

So, for what it's worth, that is now the best suggestion I have
to offer.

Alf P. Steinbach

unread,
Dec 29, 2016, 7:57:22 PM12/29/16
to
Oh, thanks! I need to really fasten that with duct tape back of my
skull, because it's not the first time! Some years ago I was enquiring
here about another difficult-for-me thing, a scheme for generating
extensions of options classes in a class derivation hierarchy
(essentially to do the same thing as passing named option values in e.g.
Python, especially for GUI stuff), and James Kanze suggested, hey, why
don't you just preprocess using a script?

Somehow the thought didn't enter my mind.

I ended up doing a different all C++ complicated template thing, which I
subsequently wrote a DDJ article about, but I think that was mostly
because I had such a momentum in that direction, not really a free
choice. The preprocessing is the rational thing to do. Thanks!


Cheers!,

- Alf

Tim Rentsch

unread,
Dec 29, 2016, 11:31:22 PM12/29/16
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:

> On 29.12.2016 23:31, Tim Rentsch wrote:
>> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>>
>> [C++ stuff]
>>
>> The definitions for the CRACK_... macros (ie, in the generated
>> file "generated/crackit.h") are produced programmatically from
>> the HANDLE_... macros in <windowsx.h>, using a short awk script:
>>
>> #! /bin/awk -f
>>
>> $0 ~ /#define HANDLE_WM_/ {
>> gsub( /[(]hwnd,/, "(fn," );
>> gsub( /,fn[)]/, ")" );
>> gsub( /[(][(]hwnd[)],/, "(" );
>> gsub( /[(]fn[)][(]hwnd[)]/, "(fn)()" );
>> gsub( / HANDLE_/, " CRACK_" );
>> print
>> }
>>
>> So, for what it's worth, that is now the best suggestion I have
>> to offer.
>
> Oh, thanks! I need to really fasten that with duct tape back of my
> skull, because it's not the first time! Some years ago I was enquiring
> here about another difficult-for-me thing, a scheme for generating
> extensions of options classes in a class derivation hierarchy
> (essentially to do the same thing as passing named option values in
> e.g. Python, especially for GUI stuff), and James Kanze suggested,
> hey, why don't you just preprocess using a script?

You are most welcome sir. It's always nice to hear that a
suggestion is found to be both helpful and appreciated. :)

Manfred

unread,
Dec 31, 2016, 12:34:26 PM12/31/16
to
On 12/23/2016 04:30 PM, Stefan Ram wrote:
> Manfred <non...@invalid.add> writes (sentence order modified):
>> Basically the problem is to map a (HWND, WM_PAINT) pair to a
>> window->on_wm_paint() handler.
> ...
>> I agree on all of your critics to MFC/ATL, but I haven't find a good
>> dispatch method either.
>
> What is bothering you most about the dispatch methods that
> you have been using so far?
>
I still had to answer to this.
MFC uses message maps, which substantially work, but they are buried
within MFC, so they come with all of its burden (which Alf summarized well).
Moreover, from the language point of view, I think they substantially
are not C++. They are C with classes at best, IMHO - no object
connection, no polymorphism.
It results in the oddity (also IMHO), as per their functionality, that
in the era of C++17 they still use two map lookup: the window object and
the handler function. Microsoft has gone to considerable extent in
optimizing such lookup, but still every single message has to go through
them.
From the coding point of view, it is a minor issue but I find it
somewhat suboptimal that a handler for a single message has to be
declared twice: in the class and in the map.

Paavo Helde

unread,
Jan 1, 2017, 1:31:21 PM1/1/17
to
On 31.12.2016 19:34, Manfred wrote:
> On 12/23/2016 04:30 PM, Stefan Ram wrote:
>> Manfred <non...@invalid.add> writes (sentence order modified):
>>> Basically the problem is to map a (HWND, WM_PAINT) pair to a
>>> window->on_wm_paint() handler.
>> ...
>>> I agree on all of your critics to MFC/ATL, but I haven't find a good
>>> dispatch method either.
>>
>> What is bothering you most about the dispatch methods that
>> you have been using so far?
>>
> I still had to answer to this.
> MFC uses message maps, which substantially work, but they are buried
> within MFC, so they come with all of its burden (which Alf summarized
> well).
> Moreover, from the language point of view, I think they substantially
> are not C++. They are C with classes at best, IMHO - no object
> connection, no polymorphism.
> It results in the oddity (also IMHO), as per their functionality, that
> in the era of C++17 they still use two map lookup: the window object and
> the handler function. Microsoft has gone to considerable extent in
> optimizing such lookup, but still every single message has to go through
> them.

MFC could have used virtual functions instead of message maps. However,
they decided to go with message maps which are more compact in memory
than vtables (this was in the 16-bit era). Message maps might be a bit
slower, but in a GUI framework this is not important because the user is
not able to generate the events very rapidly.

The resulting macro mess is the direct result. At the same time MFC is
using virtual functions as well, which does not make things better.

> From the coding point of view, it is a minor issue but I find it
> somewhat suboptimal that a handler for a single message has to be
> declared twice: in the class and in the map.

I think the idea was that one should use the Visual Studio wizards which
were supposed to generate all pieces for the event handler in one go.
However, I recall the wizards had massive problems with namespaces and
generally ceased to work in non-trivial projects.

Jerry Stuckle

unread,
Jan 1, 2017, 4:17:55 PM1/1/17
to
It does use virtual functions - but it still requires a message map.

> The resulting macro mess is the direct result. At the same time MFC is
> using virtual functions as well, which does not make things better.
>

The message maps are required as a result of how Windows message
handling works. Remember - C++ is not the only language used with Windows.

>> From the coding point of view, it is a minor issue but I find it
>> somewhat suboptimal that a handler for a single message has to be
>> declared twice: in the class and in the map.
>
> I think the idea was that one should use the Visual Studio wizards which
> were supposed to generate all pieces for the event handler in one go.
> However, I recall the wizards had massive problems with namespaces and
> generally ceased to work in non-trivial projects.
>

I've used it in some very large projects, even before namespaces were
commonly used. It's all in how you structure your program.

--
==================
Remove the "x" from my email address
Jerry Stuckle
jstu...@attglobal.net
==================

Richard

unread,
Jan 1, 2017, 7:47:09 PM1/1/17
to
[Please do not mail me a copy of your followup]

Manfred <non...@invalid.add> spake the secret code
<o48q6m$1pft$1...@gioia.aioe.org> thusly:

>I still had to answer to this.
>MFC uses message maps, which substantially work, but they are buried
>within MFC, so they come with all of its burden (which Alf summarized well).

...which is why I pointed out ATL/WTL, which doesn't come with that
burden.

This whole thing just feels like reinventing the wheel. It's fine as
a learning exercise, but I remain unconvinced that it's worth the
effort at this point. Too much work for too little gain.

Chris M. Thomasson

unread,
Jan 2, 2017, 10:34:38 PM1/2/17
to
IIRC, there was a way to use a thunk to store the this pointer in a
window, removing the need for a map lookup.

Jerry Stuckle

unread,
Jan 2, 2017, 10:58:43 PM1/2/17
to
How is this going to help? How are you going to equate the hundreds of
Windows messages to the appropriate functions without a message map?
Maybe a switch statement with hundreds of case clauses? Hundreds of
if/else statements?

Alf P. Steinbach

unread,
Jan 20, 2017, 1:10:10 PM1/20/17
to
On 29.12.2016 23:31, Tim Rentsch wrote:
[snip]
> The definitions for the CRACK_... macros (ie, in the generated
> file "generated/crackit.h") are produced programmatically from
> the HANDLE_... macros in <windowsx.h>, using a short awk script:
>
> #! /bin/awk -f
>
> $0 ~ /#define HANDLE_WM_/ {
> gsub( /[(]hwnd,/, "(fn," );
> gsub( /,fn[)]/, ")" );
> gsub( /[(][(]hwnd[)],/, "(" );
> gsub( /[(]fn[)][(]hwnd[)]/, "(fn)()" );
> gsub( / HANDLE_/, " CRACK_" );
> print
> }
>
> So, for what it's worth, that is now the best suggestion I have
> to offer.

Sorry for being very slow about things.

Anyway I've started on this road now, though not with AWK, which I just
barely remember from “The UNIX Programming Environment” long long ago…

Instead of macros I've resurrected, that is, I've reimplemented, an old
dispatching scheme of mine where a class that represents a kind of
window, inherits for example the interface

public wm::Paint::Handler

and just implements

auto on( wm::Paint const& )
-> Void
override

from that interface, in order to handle WM_PAINT, say. The curious
`Void` return type instead of plain `void` is in order to be able to
wrap calls of the handlers in a single general dispatcher.

I once ditched this scheme because it has abstraction costs, in
particular the `public` inheritance necessary for `dynamic_cast`, which
as far as I can see can only be avoided by a costly indirection.

I've just implemented the `wm::Paint` class and two others by hand, to
sound out the requirements for generating them automatically from
`<windowsx.h>`, and also as a proof of concept.

The current AWKward (?) C++ <windowsx.h> analysis code, that so far
only extracts the API level handler signatures from the <windowsx.h>
comments, looks like this:

[code]
#include <p/cppx/hopefully_and_fail.hpp> // cppx::(hopefully, fail)
#include <p/cppx/basic_type_aliases.hpp> // cppx::(Byte, Size)

#include <assert.h>
#include <ctype.h> // isspace
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <stdexcept>
#include <stdlib.h>
#include <vector>
using namespace std;
namespace cppx = progrock::cppx;

using cppx::hopefully;
using cppx::fail;
using cppx::Byte;
using cppx::Size;

auto starts_with( string const& prefix, string const& s )
-> bool
{ return s.substr( 0, prefix.length() ) == prefix; }

auto is_whitespace( char const ch )
-> bool
{ return !!::isspace( static_cast<Byte>( ch ) ); }

auto is_alphabetic( char const ch )
-> bool
{ return !!::isalpha( static_cast<Byte>( ch ) ); }

auto is_digit( char const ch )
-> bool
{ return !!::isdigit( static_cast<Byte>( ch ) ); }

auto is_identifier_char( char const ch )
-> bool
{ return is_digit( ch ) or is_alphabetic( ch ) or ch == '_'; }

class Tokenizer
{
private:
string s_;
int i_;
int n_;

static auto ends_token( char const start_ch, char const ch )
-> bool
{
assert( not is_whitespace( start_ch ) );
if( start_ch == '(' or start_ch == ')' )
return true;
else if( start_ch == '/' )
return ch != '*';
else if( start_ch == '*' )
return ch != '/';
else if( start_ch == '0' )
return ch != 'L';
else if( is_alphabetic( start_ch ) )
return not is_identifier_char( ch );
else
return true;
}

public:
auto finished() const
-> bool
{ return n_ == 0; }

void advance()
{
int const i_beyond = s_.length();
i_ += n_;
if( i_ == i_beyond )
{
n_ = 0;
return;
}

// Skip whitespace at start.
while( i_ < i_beyond and is_whitespace( s_[i_] ) ) { ++i_; }

// Find end of token.
int i2 = i_ + 1;
while( i2 < i_beyond and not ends_token( s_[i_], s_[i2] ) ) {
++i2; }
n_ = i2 - i_;
}

auto current() const
-> string
{ return s_.substr( i_, n_ ); }

Tokenizer( string const& s )
: s_( s )
, i_( 0 )
, n_( 0 )
{ advance(); }
};

struct Argument
{
string name;
string type;
};

struct Function
{
string base_name;
string result_type;
vector<Argument> arguments;

auto str() const
-> string
{
string result = base_name + '(';
int const n = arguments.size();
if( n > 0 ) { result += ' '; }
for( int i = 0; i < n; ++i )
{
if( i >= 1 ) { result += ", "; }
auto const& arg = arguments[i];
result += arg.type + ' ' + arg.name;
}
if( n > 0 ) { result += ' '; }
result += ')';
return result_type == "void"
? "void " + result
: "auto " + result + " -> " + result_type;
}
};

auto pointer_notation( string const& typespec )
-> string
{ return starts_with( "LP", typespec )? typespec.substr( 2 ) + "*" :
typespec; }

void cpp_main()
{
ifstream in( "windowsx_part.txt" );
hopefully( not in.fail() )
|| fail( "Failed to open input file" );
string line;
while( getline( in, line ) )
{
if( starts_with( "/* ", line ) )
{
Function f;
Tokenizer t{ line };
t.advance(); // Skip "/*".
f.result_type = pointer_notation( t.current() );
t.advance();
f.base_name = t.current().substr( 6 );
t.advance();
hopefully( t.current() == "(" )
|| fail( "Expected `(` in `" + line + "`" );
t.advance(); // Skip "("
for( bool more_arguments = true; more_arguments; t.advance() )
{
string arg_name;
string arg_type;
string last_token;
for( ;; )
{
hopefully( not t.finished() )
|| fail( "Unexpected end of line in `" + line +
"`" );
string current = t.current();
if( current == "," or current == ")" )
{
arg_name = last_token;
more_arguments = (current == ",");
break;
}
else
{
if( arg_type.length() != 0 and last_token !=
"*" ) { arg_type += " "; }
arg_type += pointer_notation( last_token );
last_token = current;
}
t.advance();
}
f.arguments.push_back( Argument{ arg_name, arg_type } );
}
cout << f.str() << endl;
}
}
}

auto main()
-> int
{
try
{
cpp_main();
return EXIT_SUCCESS;
}
catch( exception const& x )
{
cerr << "!" << x.what() << endl;
}
return EXIT_FAILURE;
}
[/code]


It works on a copy of the relevant part of Microsoft's `<windowsx.h>`,
with the two comments that are real comments changed manually from `/*`
to `/***`, and it then produces this list of API level handler functions:


[output]
void Compacting( HWND hwnd, UINT compactRatio )
void WinIniChange( HWND hwnd, CTSTR* lpszSectionName )
void SysColorChange( HWND hwnd )
auto QueryNewPalette( HWND hwnd ) -> BOOL
void PaletteIsChanging( HWND hwnd, HWND hwndPaletteChange )
void PaletteChanged( HWND hwnd, HWND hwndPaletteChange )
void FontChange( HWND hwnd )
void SpoolerStatus( HWND hwnd, UINT status, int cJobInQueue )
void DevModeChange( HWND hwnd, CTSTR* lpszDeviceName )
void TimeChange( HWND hwnd )
void Power( HWND hwnd, int code )
auto QueryEndSession( HWND hwnd ) -> BOOL
void EndSession( HWND hwnd, BOOL fEnding )
void Quit( HWND hwnd, int exitCode )
void SystemError( HWND hwnd, int errCode )
auto Create( HWND hwnd, CREATESTRUCT* lpCreateStruct ) -> BOOL
auto NCCreate( HWND hwnd, CREATESTRUCT* lpCreateStruct ) -> BOOL
void Destroy( HWND hwnd )
void NCDestroy( HWND hwnd )
void ShowWindow( HWND hwnd, BOOL fShow, UINT status )
void SetRedraw( HWND hwnd, BOOL fRedraw )
void Enable( HWND hwnd, BOOL fEnable )
void SetText( HWND hwnd, CTSTR* lpszText )
auto GetText( HWND hwnd, int cchTextMax, TSTR* lpszText ) -> INT
auto GetTextLength( HWND hwnd ) -> INT
auto WindowPosChanging( HWND hwnd, WINDOWPOS* lpwpos ) -> BOOL
void WindowPosChanged( HWND hwnd, const WINDOWPOS* lpwpos )
void Move( HWND hwnd, int x, int y )
void Size( HWND hwnd, UINT state, int cx, int cy )
void Close( HWND hwnd )
auto QueryOpen( HWND hwnd ) -> BOOL
void GetMinMaxInfo( HWND hwnd, MINMAXINFO* lpMinMaxInfo )
void Paint( HWND hwnd )
auto EraseBkgnd( HWND hwnd, HDC hdc ) -> BOOL
auto IconEraseBkgnd( HWND hwnd, HDC hdc ) -> BOOL
void NCPaint( HWND hwnd, HRGN hrgn )
auto NCCalcSize( HWND hwnd, BOOL fCalcValidRects, NCCALCSIZE_PARAMS*
lpcsp ) -> UINT
auto NCHitTest( HWND hwnd, int x, int y ) -> UINT
auto QueryDragIcon( HWND hwnd ) -> HICON
void DropFiles( HWND hwnd, HDROP hdrop )
void Activate( HWND hwnd, UINT state, HWND hwndActDeact, BOOL fMinimized )
void ActivateApp( HWND hwnd, BOOL fActivate, DWORD dwThreadId )
auto NCActivate( HWND hwnd, BOOL fActive, HWND hwndActDeact, BOOL
fMinimized ) -> BOOL
void SetFocus( HWND hwnd, HWND hwndOldFocus )
void KillFocus( HWND hwnd, HWND hwndNewFocus )
void Key( HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags )
void Key( HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags )
void Char( HWND hwnd, TCHAR ch, int cRepeat )
void DeadChar( HWND hwnd, TCHAR ch, int cRepeat )
void SysKey( HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags )
void SysKey( HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags )
void SysChar( HWND hwnd, TCHAR ch, int cRepeat )
void SysDeadChar( HWND hwnd, TCHAR ch, int cRepeat )
void MouseMove( HWND hwnd, int x, int y, UINT keyFlags )
void LButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
keyFlags )
void LButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
keyFlags )
void LButtonUp( HWND hwnd, int x, int y, UINT keyFlags )
void RButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
keyFlags )
void RButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
keyFlags )
void RButtonUp( HWND hwnd, int x, int y, UINT flags )
void MButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
keyFlags )
void MButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
keyFlags )
void MButtonUp( HWND hwnd, int x, int y, UINT flags )
void MouseWheel( HWND hwnd, int xPos, int yPos, int zDelta, UINT fwKeys )
void NCMouseMove( HWND hwnd, int x, int y, UINT codeHitTest )
void NCLButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
codeHitTest )
void NCLButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
codeHitTest )
void NCLButtonUp( HWND hwnd, int x, int y, UINT codeHitTest )
void NCRButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
codeHitTest )
void NCRButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
codeHitTest )
void NCRButtonUp( HWND hwnd, int x, int y, UINT codeHitTest )
void NCMButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
codeHitTest )
void NCMButtonDown( HWND hwnd, BOOL fDoubleClick, int x, int y, UINT
codeHitTest )
void NCMButtonUp( HWND hwnd, int x, int y, UINT codeHitTest )
auto MouseActivate( HWND hwnd, HWND hwndTopLevel, UINT codeHitTest, UINT
msg ) -> int
void CancelMode( HWND hwnd )
void Timer( HWND hwnd, UINT id )
void InitMenu( HWND hwnd, HMENU hMenu )
void InitMenuPopup( HWND hwnd, HMENU hMenu, UINT item, BOOL fSystemMenu )
void MenuSelect( HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup,
UINT flags )
auto MenuChar( HWND hwnd, UINT ch, UINT flags, HMENU hmenu ) -> DWORD
void Command( HWND hwnd, int id, HWND hwndCtl, UINT codeNotify )
void HScroll( HWND hwnd, HWND hwndCtl, UINT code, int pos )
void VScroll( HWND hwnd, HWND hwndCtl, UINT code, int pos )
void Cut( HWND hwnd )
void Copy( HWND hwnd )
void Paste( HWND hwnd )
void Clear( HWND hwnd )
void Undo( HWND hwnd )
auto RenderFormat( HWND hwnd, UINT fmt ) -> HANDLE
void RenderAllFormats( HWND hwnd )
void DestroyClipboard( HWND hwnd )
void DrawClipboard( HWND hwnd )
void PaintClipboard( HWND hwnd, HWND hwndCBViewer, const PAINTSTRUCT*
lpPaintStruct )
void SizeClipboard( HWND hwnd, HWND hwndCBViewer, const RECT* lprc )
void VScrollClipboard( HWND hwnd, HWND hwndCBViewer, UINT code, int pos )
void HScrollClipboard( HWND hwnd, HWND hwndCBViewer, UINT code, int pos )
void AskCBFormatName( HWND hwnd, int cchMax, TSTR* rgchName )
void ChangeCBChain( HWND hwnd, HWND hwndRemove, HWND hwndNext )
auto SetCursor( HWND hwnd, HWND hwndCursor, UINT codeHitTest, UINT msg )
-> BOOL
void SysCommand( HWND hwnd, UINT cmd, int x, int y )
auto ICreate( HWND hwnd, const MDICREATESTRUCT* lpmcs ) -> HWND
void IDestroy( HWND hwnd, HWND hwndDestroy )
void IActivate( HWND hwnd, BOOL fActive, HWND hwndActivate, HWND
hwndDeactivate )
void IRestore( HWND hwnd, HWND hwndRestore )
auto INext( HWND hwnd, HWND hwndCur, BOOL fPrev ) -> HWND
void IMaximize( HWND hwnd, HWND hwndMaximize )
auto ITile( HWND hwnd, UINT cmd ) -> BOOL
auto ICascade( HWND hwnd, UINT cmd ) -> BOOL
void IIconArrange( HWND hwnd )
auto IGetActive( HWND hwnd ) -> HWND
auto ISetMenu( HWND hwnd, BOOL fRefresh, HMENU hmenuFrame, HMENU
hmenuWindow ) -> HMENU
void ChildActivate( HWND hwnd )
auto InitDialog( HWND hwnd, HWND hwndFocus, ARAM* lParam ) -> BOOL
auto NextDlgCtl( HWND hwnd, HWND hwndSetFocus, BOOL fNext ) -> HWND
void ParentNotify( HWND hwnd, UINT msg, HWND hwndChild, int idChild )
void EnterIdle( HWND hwnd, UINT source, HWND hwndSource )
auto GetDlgCode( HWND hwnd, MSG* lpmsg ) -> UINT
auto CtlColor( HWND hwnd, HDC hdc, HWND hwndChild, int type ) -> HBRUSH
void SetFont( HWND hwndCtl, HFONT hfont, BOOL fRedraw )
auto GetFont( HWND hwnd ) -> HFONT
void DrawItem( HWND hwnd, const DRAWITEMSTRUCT* lpDrawItem )
void MeasureItem( HWND hwnd, MEASUREITEMSTRUCT* lpMeasureItem )
void DeleteItem( HWND hwnd, const DELETEITEMSTRUCT* lpDeleteItem )
auto CompareItem( HWND hwnd, const COMPAREITEMSTRUCT* lpCompareItem ) -> int
auto VkeyToItem( HWND hwnd, UINT vk, HWND hwndListbox, int iCaret ) -> int
auto CharToItem( HWND hwnd, UINT ch, HWND hwndListbox, int iCaret ) -> int
void QueueSync( HWND hwnd )
void CommNotify( HWND hwnd, int cid, UINT flags )
void DisplayChange( HWND hwnd, UINT bitsPerPixel, UINT cxScreen, UINT
cyScreen )
auto DeviceChange( HWND hwnd, UINT uEvent, DWORD dwEventData ) -> BOOL
void ContextMenu( HWND hwnd, HWND hwndContext, UINT xPos, UINT yPos )
void HotKey( HWND hwnd, int idHotKey, UINT fuModifiers, UINT vk )
[/output]


So, I've made some progress on this, taking your advice – perhaps taking
it more far than you intended. :)


- Alf

Dombo

unread,
Jan 23, 2017, 3:27:53 PM1/23/17
to
Op 22-Dec-16 om 5:09 schreef Alf P. Steinbach:

> I've done this so many times in the past, with C++03. But I feel
> that there must be some less unclean modern C++-ish way. Ideas?

The question is what your main issue with the macros is. If you want to
avoid macros at all cost you could consider using variadic templates so
you can do something along the lines of:

class MyWindow
: public MessageDispatcher<WM_PAINT, WM_COMMAND, WM_DESTROY>
{
protected:
virtual void OnPaint() override
{
// ...
}

virtual bool OnCommand(WORD cmd, WORD evt, HWND hWndControl) override
{
// ...
}

virtual void OnDestroy() override
{
::PostQuitMessage(0);
}

// ...
};


Instead of using message cracker macro's you would have to provide
specialized template classes for every message to translate the message
into a virtual function call:

#include <windows.h>

template<UINT TMessage>
class MessageHandler;

template<>
class MessageHandler<WM_PAINT>
{
public:
LRESULT HandleMessage(HWND hWnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
OnPaint();
return 0;
}

virtual void OnPaint() = 0;
};


template<>
class MessageHandler<WM_COMMAND>
{
public:
LRESULT HandleMessage(HWND hWnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
return OnCommand(LOWORD(wParam), HIWORD(wParam),
reinterpret_cast<HWND>(lParam))
? 0
: ::DefWindowProc(hWnd, message, wParam, lParam);
}

virtual bool OnCommand(WORD commandId, WORD eventId,
HWND hWndControl) = 0;
};


template<>
class MessageHandler<WM_DESTROY>
{
public:
LRESULT HandleMessage(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
OnDestroy();
return 0;
}

virtual void OnDestroy() = 0;
};


class MessageHandlerDefault
{
protected:
virtual LRESULT ProcessUnhandledMessage(HWND hWnd, UINT message,
WPARAM wParam,
LPARAM lParam)
{
return ::DefWindowProc(hWnd, message, wParam, lParam);
}
};


template<UINT ...TMessages>
class MessageDispatcher : protected virtual MessageHandlerDefault
{
protected:
LRESULT DispatchMessage(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam)
{
return ProcessUnhandledMessage(hWnd, message, wParam, lParam);
}
};


template<UINT TMessage, UINT ...TMessages>
class MessageDispatcher<TMessage, TMessages...>
: protected MessageDispatcher<TMessages...>
, protected virtual MessageHandler<TMessage>
{
public:
LRESULT DispatchMessage(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
return message == TMessage
? MessageHandler<TMessage>::HandleMessage(hWnd, message,
wParam, lParam)
: MessageDispatcher<TMessages...>::DispatchMessage(hWnd,
message,
wParam,
lParam);
}
};


As much as I dislike macros I doubt that the above hack is better than
just accept that macros are sometimes the way to go.

Mr Flibble

unread,
Jan 23, 2017, 5:34:37 PM1/23/17
to
On 23/01/2017 20:30, Dombo wrote:
[horrid Windows code snipped]
>
> As much as I dislike macros I doubt that the above hack is better than
> just accept that macros are sometimes the way to go.

Yes there is: use a portable widget toolkit. The least worst one at the
moment is Qt but I am working on changing that with neoGFX:

http://neogfx.org/

Coming soon!

/Flibble

Tim Rentsch

unread,
Jan 27, 2017, 2:37:25 AM1/27/17
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:

> On 29.12.2016 23:31, Tim Rentsch wrote:
> [snip]
>> The definitions for the CRACK_... macros (ie, in the generated
>> file "generated/crackit.h") are produced programmatically from
>> the HANDLE_... macros in <windowsx.h>, using a short awk script:
>>
>> #! /bin/awk -f
>>
>> $0 ~ /#define HANDLE_WM_/ {
>> gsub( /[(]hwnd,/, "(fn," );
>> gsub( /,fn[)]/, ")" );
>> gsub( /[(][(]hwnd[)],/, "(" );
>> gsub( /[(]fn[)][(]hwnd[)]/, "(fn)()" );
>> gsub( / HANDLE_/, " CRACK_" );
>> print
>> }
>>
>> So, for what it's worth, that is now the best suggestion I have
>> to offer.
>
> Sorry for being very slow about things.

No worries!

> Anyway I've started on this road now, though not with AWK, which I
> just barely remember from ?The UNIX Programming Environment? long long
> ago?

Yes, personally I find awk quite a handy tool, but it is
no doubt cryptic for those who aren't used to it. Here
is the same conversion program (with a small fix) done
using grep and sed in a shell script:

#! /bin/sh

cat "$@" | \
grep HANDLE_WM_ | \
sed 's/(fn)((hwnd),/(fn)(/' | \
sed 's/(fn)(hwnd,/(fn)(/' | \
sed 's/(fn)(hwnd)/(fn)()/' | \
sed 's/(hwnd,/(fn,/' | \
sed 's/,fn)/)/' | \
sed 's/ HANDLE_/ CRACK_/' | \
cat


> Instead of macros I've resurrected, that is, I've reimplemented, an
> old dispatching scheme of mine where a class that represents a kind of
> window, inherits for example the interface
>
> public wm::Paint::Handler
>
> and just implements
>
> auto on( wm::Paint const& )
> -> Void
> override
>
> from that interface, in order to handle WM_PAINT, say. The curious
> Void` return type instead of plain `void` is in order to be able to
> wrap calls of the handlers in a single general dispatcher.
>
> [snip elaboration, ~200 lines of C++, and ~150 lines of output]

I think I follow what you're doing, well, sort of. I'm not sure
how it connects to the original problem.


> So, I've made some progress on this, taking your advice ? perhaps
> taking it more far than you intended. :)

My sense is you are taking a different approach, and at a higher
level, to solve a more general problem statement. It's hard for
me to give a useful response, what with not being sure about what
the problem statement is, and also not understanding the proposed
solution. :) But as long as you're happy with the direction
you're going I am glad to have been of help.
0 new messages