Trapping Messages Sent to an Application

http://www.delphicorner.f9.co.uk/articles/apps7.htm

I wrote code for the OnMessage event handler of Application object

to trap all Windows messages sent to my application,

but it doesn‘t seem to fire on all messages.

Is there a way to trap all messages sent to my application?

There sure is. And the answer to this "problem"  is amazingly simple.

But before I go into trapping messages at the application level,

I should probably discuss some mechanics.

TApplication‘s "Hidden" Window

It‘s not a commonly known fact that the default Application object creates a hidden window

when your application is started.

But you can seen evidence of this by creating a new application saving it,

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 more familiar with handling windows messages

might think that a solution to the problem above

might be to override the WndProc method for the Application object.

Unfortunately, that‘s 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 it‘s not only invisible, you can‘t create a TApplication subclass

to override WndProc (not that you‘d want 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.

This is convenient for all developers, and solves the problem

of trapping any message sent to your application.

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.

This is the equivalent of the "Handled" parameter of OnMessage.

If your function handles a particular message, you‘d return true.

This will be passed back to the Application‘s WndProc and

message 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.

This can be done in the main form‘s OnCreate method:

function TForm1.FormCreate(Sender : TObject);
begin
  HookMainWindow(AppHookFunc);
end; 

I should mention that you need to clear the hook using,

you guessed it, UnHookMainWindow,

after you‘re done using it, and this can be done

in the OnDestroy for the main form:

function TForm1.FormDestroy(Sender : TObject);
begin
  UnHookMainWindow(AppHookFunc);
end; 

Okay, disgustingly simple.

But I feel the best things in life are those that give maximum satisfaction

for the least amount of cost (please don‘t read ANYTHING into that <G>).

So, now you‘ve got the tools to create your own message "hooker" (sorry, had to do that at least once).

Until next time...

时间: 2024-10-09 18:27:45

Trapping Messages Sent to an Application的相关文章

对发给Application.Handle消息的三次执行(拦截)消息的过程

unit Main; interface uses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TMainForm = class(TForm) SendBtn: TButton; PostBtn: TButton; procedure SendBtnClick(Sender: TObject); procedure PostBtnClick

Application.HookMainWindow完全替代了原来的窗口过程(但是好像也会继续传递)

unit HookMain; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type THookForm = class(TForm) SendBtn: TButton; GroupBox1: TGroupBox; LogList: TListBox; DoLog: TCheckBox; ExitBtn: TButton; B

Application Layer

1. Applications – The Interface Between the Networks two programs access to the network: applications and services. Applications are designed to interact with us. Application is software for the user. If the device is a computer, the application is t

Android中Handler引起的内存泄露

在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用.通常我们的代码会这样实现. 但是,其实上面的代码可能导致内存泄露,当你使用Android lint工具的话,会得到这样的警告 In Android, Handler classes should be static or leaks might occur, Messages enqueued on the application thread’s MessageQueue also retain their t

This Handler class should be static or leaks might occur

Android中,在使用到Handler的时候,如果按如下代码编写: private Handler handler; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); handler = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-gene

Android - 抑制lint的Android XML的警告:tools:ignore

抑制lint的Android XML的警告:tools:ignore 本文地址:http://blog.csdn.net/caroline_wendy Android的XML经常会出现警告,对于一个良好的程序,应该认真对待所有的警告. 除非我们可以确认警告,才可以排除. 显示所有警告的方法:Analyze -> Inspect Code; 就可以检查出所有的警告: 抑制警告使用: tools:ignore. // 忽略全部 xmlns:tools="http://schemas.andro

Hooks——钩子概览

(资料源于MSDN,本文仅对其进行翻译.批注.其链接为:http://msdn.microsoft.com/en-us/library/windows/desktop/ms644959%28v=vs.85%29.aspx本文链接:http://blog.csdn.net/wlsgzl/article/details/37648721转载请注明出处并保持文章的完整性.) Hooks Overview A hook is a mechanism by which an application can

OPENVPN搭建与配置

Content-type: text/html; charset=UTF-8 openvpn Section: Maintenance Commands (8)Updated: 17 November 2008Index Return to Main Contents NAME openvpn - secure IP tunnel daemon. SYNOPSIS openvpn [ options ... ] INTRODUCTION OpenVPN is an open source VPN

Windows进程间通信(下)

六.动态数据交换(Dynamic Data Exchange) 动态数据交换(DDE)是使用共享内存在应用程序之间进行数据交换的一种进程间通信形式.应用程序可以使用DDE进行一次性数据传输,也可以当出现新数据时,通过发送更新值在应用程序间动态交换数据.DDE 和剪贴板一样既支持标准数据格式(如文本.位图等),又可以支持自己定义的数据格式.但它们的数据传输机制却不同,一个明显区别是剪贴板操作几乎总是用作对用户指定操作的一次性应答-如从菜单中选择Paste命令.尽管DDE也可以由用户启动,但它继续发