Registering Window Messages
There are several problems with constant messages.
- You can't send them between processes reliably. If you accidentally send
a message to a process that has never heard of your message, it could crash.
If you receive a message that you think you understand, you might crash.
- You can't create a DLL that notifies its clients via messages. This is because
you might choose (WM_APP+7) as your desired message, and some other DLL
writer you never heard of might have also chosen (WM_APP+7) as his or
her desired message. The poor programmer who is trying to use both DLLs is in
deep trouble, because of the conflict.
- You can't even think of sending one of these messages down through
your window hierarchy by using SendMessageToDescedants, because some
window you never heard of may be using that message. Consider the example in
the previous section where a message to paint the view purple and a message
to reset the view were the same code. If you sent this message to all descendants
of your main frame, some would reset and some would change to purple, which
is not a particularly desired outcome.
The way this is solved is by using a Registered Window Message. This
is a message which is guaranteed to be unique. Only those windows or processes
or DLLs that create it, and those which specifically use it, will actually have
the same message number.
How is this done?
There is a range of messages, 0xC000 through 0xEFFF, which is reserved for
use by registered window messages. When you call the API function ::RegisterWindowMessage
you pass it a string. It looks up the string in an internal table. If it finds
the string, it returns the integer which has been assigned. If it does not find
the string, it creates a new entry in the table, assigns it a new integer value
from the range 0xC000 through 0xEFFF, and returns that integer value. The table
in which these strings are kept is global to all processes on the machine, so
if two completely different programs register the same string, they both get
the same integer. They may now communicate with each other via these messages.
No, you can't "unregister" a message. You don't need to.
So a simple form of the user-defined message would be to declare a variable,
which I usually just make static in each module that uses it:
static const UINT UWM_RESET_VIEW =
::RegisterWindowMessage(_T("UWM_RESET_VIEW"));
I'll tell you later why this still isn't quite adequate, but take it as a working
example for the moment.
The way you handle a registered message is just like you handle a constant
user-defined message. The macro is slightly different, but the rest of the handling
is the same. Add the line to your MESSAGE_MAP:
ON_REGISTERED_MESSAGE(UWM_RESET_VIEW, OnReset)
As with the constant messages, you will need to define the OnReset handler
by adding a declaration to the handler section of your class in the .h
file:
afx_msg LRESULT OnReset(WPARAM, LPARAM);
The handlers for a registered window message and for a constant user-defined
message are absolutely identical. In fact, in the handler, you can't really tell
if the programmer has rewritten the code to use one or the other.