이수안 데이터 연구실

검색 :
RSS 구독 : 글 / 댓글 / 트랙백 / 글+트랙백

글 검색 결과

Message Management

Introduction

There are two kinds of messages which you, as a programmer, can defined. The first kind is the compile-time-constant variety. I have found, after years of experience, These Are Not Your Friend. I'll nonetheless describe them as many people still prefer them, but as a matter of opinion I avoid them as much as I can. The second kind are messages which are guaranteed to be unique within a system. I much prefer these, and use them exclusively.

WM_USER and WM_APP

WM_USER: obsolete

Older books on Windows programming tell about how to define user-defined messages using the symbol WM_USER. This technique is obsolete. There were too many problems with WM_USER-based symbols conflicting with messages that Microsoft was using. The new method is to use WM_APP as the base. If you have something that uses WM_USER, the usage is identical to the usage of messages based on WM_APP. Therefore, I will not reproduce the discussion here.

WM_APP: constant messages

If you are comfortable with the idea of compile-time constant messages--and after you read the next section, you may not be--then you can use definitions based on the symbol WM_APP, which Microsoft now specifies as the desirable symbol to use. The correct form of the definition of such a symbol is

where n is some integer, typically a small integer like 1, 2, 3, etc. This defines a value which identifies the message. While strictly speaking the parentheses are not mandatory, good programming practice demands their presence.

I prefer a naming convention that does not conflict with the Microsoft naming convention. For one thing, it makes your code difficult for someone else to read and understand; for another, it makes it hard for you to read and understand. My preference is to use a UWM_ prefix (User Window Message); other people have used WMU_ (Window Message, User), and you can pick any convention you want, but do not use prefixes that conflict with those already in use by Microsoft.

Note that there is absolutely no requirement that every user-defined message be unique. Messages are always interpreted in the context of a particular window. Thus, you can have messages like

These are perfectly valid providing that the view that accepts the purple request is never sent a reset request, and vice-versa.

To create an entry in the table to dispatch on these messages, you make an entry

This requires that you define the handler OnReset. In the message handler part of your .h file, you add the declaration

When your window class receives the UWM_RESET_VIEW message, it will call the OnReset handler.

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:

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:

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:

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.

Guaranteeing uniqueness

You may have already discovered a problem that is identical for both constant messages and registered messages. What if you choose a nice, obvious name like "UWM_RESET_VIEW" as the string name of the message, and some other programmer has also chosen another nice, obvious, simple name for his or her DLL, such as "UWM_RESET_VIEW". Have we really made progress?

No.

But there is a way around it. There is a program which is part of the SDK, called GUIDGEN. What this program does is create a unique 128-bit binary value. Each time you create a new Globally Unique IDentifier, a GUID, you can be sure that it is really, truly, unique. It is not only unique for you, it is unique for everyone, everywhere, all the time. It incorporates the time and date, the MAC address from your network card (and if you don't have a network card, it uses another method, which has something like one chance in 263 of conflicting with another GUID), and a bunch of other information. Therefore, there is no way, short of explicit collusion between two programmers, that they will use the same GUID.

All my registered window messages use a GUID as part of their name.

When you run GUIDGEN, you get a screen that looks like this:

[##_1C|1123168230.gif|width="375" height="339" alt="?ъ

이올린에 북마크하기(0) 이올린에 추천하기(0)
"Win32 API" 카테고리의 다른 글
2007/04/29 11:18 2007/04/29 11:18

맨 위로