Working with Windows Messages in .NET - ' I Spy ' (
Page 2 of 4 )
You might not be familiar with messages, but they're extremely important,
especially when you need to perform tasks outside of the range of tasks that
Microsoft programmed into the .NET Framework. All communication in Windows
relies on messages.
This article reveals Windows messages to you, shows you how to capture messages that
a .NET application doesn't normally capture, and demonstrates how to generate messages that .NET
applications don't normally generate. In short, by the time you finish this article,
you'll know about an entirely different world: the one that the .NET Framework hides
from view.
ADVERTISEMENT
Before you begin, you need to install a special tool named Spy++. You use Spy++
to reveal all kinds of information about the tasks that Windows performs in the
background. In fact, this tool is so useful that you'll probably want to add it
to your toolkit even when you aren't performing low-level programming.
If you
have the full version of Visual Studio .NET, you can install Spy++ simply by
installing the Win32 Platform SDK Tools found in the Visual C++ Tools folder, as
shown in Figure 1. You can also obtain this tool as part of the Platform SDK.
The Visual Studio version normally appears in the \Program Files\Microsoft
Visual Studio 8\Common7\Tools folder on your hard drive.
Figure 1: You can easily install the needed tools using the Win32 Platform
SDK Tools option.
You might wonder why we're using a Visual C++ tool. Actually, Spy++ is a tool
that anyone can use. Visual Studio comes with a wealth of useful tools that some
developers might relegate to Visual C++ use. This article only looks at Spy++,
but I wish I had room to explore them all. If you haven't explored these tools
in the past, you might want to check out the list.
Seeing the Windows Messages
Windows applications of all types generate so many messages that you really don't
want to look at them all. Spy++ can help you see 1,013 different
message types, many of which have subtypes. You can also view
custom messages that your application creates (which is a topic for another article). In
short, Spy++ doesn't place any actual limit on the number of messages you can
view, so the trick is to view the correct messages. Spy++ makes it easy to
choose precisely what you want to monitor and how you monitor it.
I built a simple application for this portion of the article. It consists of
a standard Windows form application that has two buttons. The first button
displays a message box (for now) and the second causes the program to exit. I
expand this simple beginning as the article progresses.
For now, you should create a similar application. Start the application. (It doesn't matter whether you use
debug or release versions and you can start it inside or outside of the IDE; the
results are the same no matter which approach you use.)
Start Spy++. You should find it in the Start | Programs | Microsoft Visual
Studio 2005 | Visual Studio Tools folder. When you first start Spy++, you see
a list of open windows. You can actually find out a lot about an
application by looking at the windows it generates, but for now, use the Spy |
Log Message command to display the Message Options dialog box shown in Figure 2.
Figure 2: Use the Message Options dialog box to determine what to monitor,
when to monitor it, and how much to monitor.
You can drag and drop the Finder Tool, shown in Figure 2, onto any window, which includes all controls.
In this case, drag it onto your test application. When you see the outside of the application highlighted, you know
that you've selected the correct item. Drop the tool, and the
Selected Object information changes to reflect the test application.
We want to monitor everything going on with this application, but nothing going
on outside of it, so check the "Windows of Same Process" option.
You can monitor just the parent or just the child as well. You can also
differentiate between threads in a multi-threaded application, or monitor Windows as a whole.
Select the Messages tab. This is where you select individual messages or message
groups. An example of a message group is Button, which are the messages that a
button window generates. It doesn't matter what .NET calls a control; Windows
considers any pushbutton a button window. It's also possible to choose
individual messages. You seldom want to see every message that Spy++ can monitor,
so begin by clicking Clear All. Since we want to monitor button clicks, select
the Button group. In addition, locate the WM_COMMAND message in the Messages to
View list and highlight it. You should have nine messages selected.
Select the Output window. Generally, the options that you see selected work fine
for native Windows applications. To ensure you get all of the right information
for .NET applications, however, you want to check the "Raw Message Parameters"
and "Raw Return Values" options. You can optionally check the remaining two
options when time and mouse position are important (they aren't in this case).
Click OK. You now see a blank window for monitor specific application messages.
Click one of the buttons in your test application. You'll see a series of five
messages, similar to those shown in Figure 3.
Figure 3: Monitoring messages can help you better understand how Windows
applications really work.
Let's go over this sequence quickly. The first message is from the button window
to the application; it tells the application that it's true that someone has
depressed the button. The application responds with a value of 0, or S_OK, an
indicator that this action is fine. The third message says that someone has
released the button and the application responds with a 0 again. The fifth
message is an event indication that the application generates. It tells anyone
who is listening for the WM_COMMAND message that someone has clicked a specific
button (the BN_CLICKED message). The button identifier is IDCANCEL, which doesn't
have anything to do with the identifier you assign in your code; this is the
Windows identifier. Finally, the WM_COMMAND message provides a handle to the
window that generated the message.