Message Management

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.

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“The first 90% of the code accounts for the first 90% of the development time. The remaining 10% of the code accounts for the other 90% of the development time.” - Tom Cargill