Those message maps in MFC do help tidy up a program, but they pose a problem for an SDK developer coming new to MFC - how to send my own program a message? This used to be easy in the old days - you just posted yourself a message value in the range WM_USER + N, and handled the message in your WndProc in the normal way. In this brave new world however, there are a few changes.
First of all, the value to be used. WM_USER messages have always caused some subtle bugs, because Windows itself uses a few messages in this range for dialog management (duh ?!?!). So, Microsoft added the new range beginning with WM_APP, which was guaranteed to be outside the range used by Windows itself: but not outside the range that might be used by another app - we'll come to that in a minute.
Well, that's fine if you're writing an SDK app, but what about MFC message maps ? Well, the special ON_MESSAGE macro was invented for this. Let's say we want to send ourselves a message of WM_APP+1000.
We have to add the macro to the message map, being careful to put it outside the markers for ClassWizard message handlers:
ON_WM_INITMENU() ON_WM_INITMENUPOPUP() //}}AFX_MSG_MAP ON_MESSAGE (WM_APP+1000, OnMyMessage) END_MESSAGE_MAP()
Then we add a prototype for the message to our class header:
afx_msg LRESULT OnMyMessage (WPARAM wParam, LPARAM lParam);
Then we can create a body for the handler, and invoke it by simply posting ourselves the message with whatever parameters we want:
PostMessage (WM_APP+1000, 1, 27);
This is all fine and dandy. But there's a fly in this ointment - a fly that's been around since the earliest days of Windows and messages. It is perfectly possible for one app to broadcast a message to all Windows, and therefore it is possible for another app to broadcast the same carefully-chosen WM_APP value to you. Thereby invoking your lovely handler when the event you're looking for has not happened at all. Oh calamity! This is especially likely if you choose a nice round number like I did above...
The solution is to use REGISTERED messages. I moved ALL my self-messaging code to registered messages a long time ago, and haven't suffered as a result. This requires a slightly different technique. First we have to "register" the message with windows using the Windows api call RegisterWindowMessage. This takes a textual name for the message, and returns an ID in a special range, which is guaranteed to be unique UNLESS another app calls RegisterWindowMessage with the same textual key. To lower this already low probability I use GUIDGEN.EXE (gui) or UUIDGEN.EXE (command line), which ship with the Platform SDK, to generate a GUID - Globally Unique IDentifier - value, then use this string with RegisterWindowMessage. I usually add a readable prefix to the GUID just for my own convenience. By the way, yes, these are the same GUID values that COM uses for identifying its classes.
static UINT g_uAppBarSlide = 0; .... g_uAppBarSlide = RegisterWindowMessage ("APPBAR_da725800-71f1-11d4-8437-00c04f9d75f4");
The next thing to note is that the variable used to store the message value is a module global, NOT a class member. This is because the ON_REGISTERED_MESSAGE macro requires that. You declare the handler to the system much as we did before, but now using this new macro:
ON_REGISTERED_MESSAGE (g_uAppBarSlide, OnSlide) END_MESSAGE_MAP()
Our prototype looks much like it did before:
afx_msg LRESULT OnSlide (WPARAM, LPARAM);
Note that in this case I'm not using the parameters, so I use the type-only notation. So all I have to do now is to use the value stored in our global to send the message: