Working with Windows Messages in .NET - ' Generating Windows Messages ' (
Page 4 of 4 )
Generating Windows Messages
Windows provides a number of ways to generate messages. The method you use
depends on the kind of message that you want to send.
ADVERTISEMENT
This article won't discuss
all of the messages, but it does examine the most common method, PostMessage().
You use the PostMethod Win32 API function to send a message to a particular
window, to the current thread, or to all of the top-level windows (generally,
applications and background processes such as services) in the current session.
Here's the definition for the PostMessage() method:
// Define the external function for posting a message.
[DllImport("User32.DLL", SetLastError = true)]
public static extern Boolean PostMessage(
IntPtr hWnd, UInt32 Msg, Int32 wParam, Int32 lParam);
Of course, you need to decide on a reason for posting a message instead of
simply using the functionality that the .NET Framework provides. The WM_QUIT
message can be an important message when you have multiple applications that
cooperate or rely on each other. This message tells other applications that the
current application is ending. The .NET Framework provides three methods of
ending the application:
Close();
Application.Exit();
Environment.Exit(0);
None of these three methods generates the WM_QUIT message, so no one knows that
the application is terminating. Fortunately, you can create the WM_QUIT message
by using the PostMessage() approach like this.
PostMessage(this.Handle, WM_QUIT, 1, 0);
You always want to provide the application handle so that other applications
know which application is ending. The WM_QUIT message has a value of 0x0012. One
handy way to find this value is to open a command prompt at the \Program Files\Microsoft
Visual Studio 8 folder. Use the FindStr /s "WM_QUIT" *.h command to locate the
value of WM_QUIT in the C++ header files that you installed to use the
techniques described in this article. The WParam argument contains the exit code
for this application, making this technique similar to the Environment.Exit()
method. In this case, the application exits with a code of 1.
Interestingly
enough, all you have to do is post the WM_QUIT message, and your .NET application
will exit, just as if you had used one of the standard .NET Framework methods.
However, if you watch the application from Spy++, you'll see that it now
generates the WM_QUIT message so that other applications can trap it.
Sometimes you can post messages without using a function such as PostMessage()
or SendMessage(). For example, the PostQuitMessage() function is an alternative
for using the PostMessage() function. Listing 3 shows the same exit code using
PostQuitMessage().
Listing 3: Exiting a .NET Application Using PostQuitMessage()
// Define the PostQuitMessage() function.
[DllImport("User32.DLL")]
public static extern void PostQuitMessage(Int32 nExitCode);
private void btnQuit_Click(object sender, EventArgs e)
{
// Output a WM_QUIT message and exit the application.
PostQuitMessage(1);
}
Unfortunately, using this approach has three limitations for .NET applications.
First, the handle you see isn't the application handle; it's the CLR handle.
Consequently, you know that something had posted a WM_QUIT message, but may not
know what. Second, the visibility of the message is different. You can see it in
Spy++ only if you choose to view all of the windows that are currently running
in Windows. Third, the exit code gets lost. This function always posts a value
of 0 as the exit code.
Consequently, I recommend testing all alternatives before
you use them to verify that they'll work as anticipated with .NET. In this case,
you should probably use the PostMessage() function instead of the
PostQuitMessage() shortcut to ensure you get the desired results.
A Final Spy++ Trick
Every time you start your application, Windows assigns the windows it creates a
different handle. Consequently, the message logging you set up won't work,
because the window handle is wrong. You can overcome this problem for simple
setups by tracking all of the windows. However, you also have access to a simple
method for changing the message logging options. Click Start | Stop Logging (the
button that has the stoplight icon) on the toolbar. Select the Messages |
Logging Options command to display the Message Options dialog box. Use the
Finder Tool to locate the new window and click OK. You're ready to monitor the
new instance of the application.
Messages are an essential part of working with Windows. However, the .NET
Framework hides the entire concept of messages from view because Microsoft
deemed them too difficult for many developers to understand and use. The system
of objects and events does work very well and you generally don't need to worry
about messages at all. However, some situations require that you work with
messages directly because the .NET Framework (understandably) doesn't monitor them
all. This article demonstrates just two of many cases where knowing about
messages can be useful.
This is the first in a series of articles that explore the concepts of windows
and messages as they apply to Windows. You might be surprised at some of the
extreme programming tasks you can perform by understanding these two concepts.
Of course, you need to have those C++ tools available to make working with
windows and messages easy.