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

Trapping Messages Sent to an Application

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

Trapping Messages Sent to an Application的更多相关文章

  1. Sending messages to non-windowed applications -- AllocateHWnd, DeallocateHWnd

    http://delphi.about.com/od/windowsshellapi/l/aa093003a.htm Page 1: How Delphi dispatches messages in ...

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

    unit HookMain; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialo ...

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

    unit Main; interface uses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms ...

  4. VCL -- Understanding the Message-Handling System

    Understanding the Message-Handling System http://docwiki.embarcadero.com/RADStudio/XE7/en/Understand ...

  5. windows消息机制详解(转载)

    消息,就是指Windows发出的一个通知,告诉应用程序某个事情发生了.例如,单击鼠标.改变窗口尺寸.按下键盘上的一个键都会使Windows发送一个消息给应用程序.消息本身是作为一个记录传递给应用程序的 ...

  6. 将asp.net core站点发布到IIS上遇到的问题

    今天第一次将整个 asp.net core 站点发布到 IIS 上,以前都是发布到 Linux 服务器上. 开始使用 dotnet publish -c release 命令发布,用浏览器访问站点时出 ...

  7. Competing Consumers Pattern (竞争消费者模式)

    Enable multiple concurrent consumers to process messages received on the same messaging channel. Thi ...

  8. Logging configuration

    The Play logger is built on Log4j. Since most Java libraries use Log4j or a wrapper able to use Log4 ...

  9. django+nginx+xshell简易日志查询,接上<关于《rsyslog+mysql+loganalyzer搭建日志服务器<个人笔记>》的反思>

    纠正一下之前在<关于<rsyslog+mysql+loganalyzer搭建日志服务器<个人笔记>>的反思>中说到的PHP+MySQL太慢,这里只是说我技术不好,没 ...

随机推荐

  1. Python 字典(Dictionary) get()方法

    描述 Python 字典(Dictionary) get() 函数返回指定键的值,如果值不在字典中返回默认值. 语法 get()方法语法: dict.get(key, default=None) 参数 ...

  2. Apache二级域名配置方法

    下面这个Apache二级域名配置方法是今天在其它BBS看到的,以前我配置是都是配置每个为一个虚拟目录今天正在想如何写没想到找到了. Apache二级域名实现方法介绍 首先,你的拥有一个有泛域名解析的顶 ...

  3. MSSQL 查询分组前N条记录

    sql语句中,查询分组中前n条记录的sql语句如下 第一种方法 select * from consultingfeebill awhere n>(select count(*) from co ...

  4. Android 最火框架XUtils之注解机制详解

    http://blog.csdn.net/rain_butterfly/article/details/37931031

  5. Appium过程中用到的adb点滴知识库

    一.认识abd adb是什么? adb的全称为Android Debug Bridge,就是起到调试桥的作用.通过adb我们可以在Eclipse中方面通过DDMS来调试Android程序,说白了就是d ...

  6. Yii笔记---redirect重定向

    Yii的redirect方法在CControler与CHttpRequest之中都有被定义,CController中的redirect调用了CHttpRequest中的redirect方法.我们平常调 ...

  7. Java Core 学习笔记——3.char/Unicode/代码点/代码单元

    通用字符集(UCS) UCS是由ISO制定的ISO 10646(或称ISO/IEC 10646)标准所制定的标准字符集. UCS包括了其他所有的字符集(包含了已知语言的所以字符). ISO/IEC 1 ...

  8. 理解display:inline、block、inline-block

    要理解display:inline.block.inline-block的区别,需要先了解HTML中的块级(block)元素和行级(inline)元素的特点,行内元素也叫内联元素. 块级元素 总是另起 ...

  9. php 解压 .gz 文件

    在百度搜索到的 PharData 类和 ZipArchive 都是解压不了 .gz 的文件的,后来在 google 搜索到解决方法,问题解决. try { $phar = new PharData($ ...

  10. Hadoop概述

    本章内容 什么是Hadoop Hadoop项目及其结构 Hadoop的体系结构 Hadoop与分布式开发 Hadoop计算模型—MapReduce Hadoop的数据管理 小结 1.1 什么是Hado ...