Ask the Delphi Pro 10-Minute Solutions

Trapping Messages Sent to an Application
By Brendan Delumpa

If you've written code for the OnMessage event handler of Application object to trap all Windows messages sent to your application, it may not fire on all messages. This is because OnMessage will only fire when there's something in the Application object's message queue. Messages sent directly to a window using SendMessage bypass the Application object's message queue, and as a result OnMessage doesn't fire in those situations. An amazingly simple way to trap all messages sent to the Application object's window is to use a method called HookMainWindow, which is included in TApplication. HookMainWindow allows you to insert your own message handler at the top of WndProc to intercept messages sent to your application before they're handled by the Application object. This solution is convenient for all developers, and solves the problem of trapping any message sent to your application. Before I go into trapping messages at the application level, I'll discuss some mechanics.

TApplication's "Hidden" Window
It's not commonly known that the default Application object creates a hidden window when your application is started. But you can see evidence of this behavior by creating a new application, saving it, and then running it (make sure you don't rename anything--just keep the main form as "Form1" and the project as "Project1"). When you run the application, you'll notice that the caption bar for your main form says, "Form1" while the icon displayed on the task bar says "Project1." That icon represents the application's hidden window, and it affects your program in many ways, especially when you're trying to handle messages sent to your application.

Delphi surfaces the OnMessage event for the Application object. The OnMessage event handler is supposed to allow you trap every message sent to your application. But there's a problem with this: OnMessage will only fire when there's something in the Application object's message queue. These messages are typically window management messages such as WM_PAINT, or messages sent to the application from Windows through PostMessage, Broadcast, or SystemMessage. However, messages sent directly to a window using SendMessage bypass the Application object's message queue, so OnMessage doesn't fire for those types of situations.

Some of you that are more familiar with handling windows messages might think that a solution to the problem could be to override the WndProc method for the Application object. Unfortunately, that solution is not possible because TApplication's WndProc method is not only private, it's also declared as a static method, which means it's not overrideable. So the WndProc method is not only invisible, but you also can't create a TApplication subclass to override WndProc (not that you'd want to either). But that doesn't mean that you can't get to the WndProc method using alternative means.

"Hooking" All Messages
Even though WndProc is all but closed to direct subclassing, TApplication does include a method called HookMainWindow that allows you to insert your own message handler at the top of WndProc to intercept messages sent to your application before they're handled by the Application object. HookMainWindow is declared under TApplication as follows:


procedure HookMainWindow(Hook : TWindowHook);
Notice that HookMainWindow takes one parameter, Hook of type TWindowHook. TWindowHook is a method pointer type that's defined like so:

type
  TWindowHook = function(var Message : TMessage) : Boolean of object;
Since TWindowHook is a method pointer, you can define your own method as the hook function as long as it follows the nomenclature defined for TWindowHook. Notice that the return value of the function is of type Boolean, which is the equivalent of the "Handled" parameter of OnMessage. If your function handles a particular message, you'd return true. This result will be passed back to the Application's WndProc and processing for that message will be terminated. Otherwise, you'd return False. Here's an example method:

function TForm1.AppHookFunc(var Message : TMessage) : Boolean;
begin
  Result := False; //I just do this by default
  if Message.Msg = WM_<SomethingOrOther> then begin
    ...DoSomething...
    Result := True;
  end;
end; 
Okay, now that we've set up everything, we need to make the application hook the messages. You can do this step in the main form's OnCreate method:

function TForm1.FormCreate(Sender : TObject);
begin
  HookMainWindow(AppHookFunc);
end; 
I should mention that after you're done using the hook, you need to clear it using--you guessed it--UnHookMainWindow. You can clear it up in the OnDestroy for the main form:

function TForm1.FormDestroy(Sender : TObject);
begin
  UnHookMainWindow(AppHookFunc);
end; 
Okay, it's a disgustingly simple solution. But I feel the best things in life are those that give maximum satisfaction for the least amount of cost. So, now you've got the tools to perform your own message "hooking."

 
Other 10-Minute Solutions
 Trapping Messages Sent to an Application
 Getting the Number of Records From a Fixed-Length ASCII File
 Performing Incremental Searches with a TListbox
 Resizing the Drop-down List of a TComboBo
 Disabling the System Keys from Your Application
 Making A Secondary Form Independent of the Main Form
 Creating a System Tray Application
 Opening and Closing a CD Tray
 Hiding an Application from Windows
 Make a List Box Track the Mouse
 Running a Program at Startup
 Creating A Skin Component
 Dynamically Load Components From Packages at Run Time
 Obtain All Values from Multivalue Input Fields in WebBroker Applications
 Migrate Your BDE Applications to Linux with dbExpress
 Create a Multiline Button Component
 Update and Maintain dbExpress's Unidirectional, Read-Only Datasets
 Use ActionBands to Enable End Users to Customize Your Delphi Applications
 Produce HTML Reporting Output with WebBroker Components
  Convert XML Documents into Different Formats with the XSL Template Language


Ask the Delphi Pro | Who is the Pro? | Usage Policies | Ask a Question | Search | Feedback


Sponsored Links


Advertising Info  |   Member Services  |   Contact Us  |   Help  |   Feedback  |   Site Map
Jupiterweb networks

internet.comearthweb.comDevx.comClickZ

Search Jupiterweb:

Jupitermedia Corporation has four divisions:
JupiterWeb, JupiterResearch, JupiterEvents, and JupiterImages

Copyright 2004 Jupitermedia Corporation All Rights Reserved.
Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

Jupitermedia Corporate Info | Newsletters | Tech Jobs | E-mail Offers