[转]让你的Delphi非窗口自定义控件接收Windows消息

最近在编写ocx插件,遇到不少问题,windows消息就是其中一个,博文留下吧

 

Windows消息用来在Windows系统与应用程序之间,或应用程序与应用程序之间进行交互通迅。例如:当用户关闭应用程序窗口时,WM_CLOSE消息就会发送到相应的窗口。

对于一个接收Windows消息的应用来说,必须提供一个窗口来接收消息。通常它会是应用程序的主窗口,你写一个过程处理特定消息,比如WM_NCHitTest,那么就可以处理该消息 。但是如果没有窗口来接收消息,你要一个从TObject继承的类来处理消息,又该怎么办呢?

 

在类TMyObject = class(TObject)中处理Windows消息

 

一个从TWinControl继承的Delphi控件是可以接收Windows消息的。TObject类并没有提供一个窗口句柄,因此,从TObject继承的类是没有办法处理Windows消息 的,至少默认情况下是这样的。为了接收Windows消息 ,你需要为你的自定义类提供一个窗口句柄来接收Windows消息。关键是使用classes.pas中定义的下面介绍的方法:

AllocateHWnd(WndMethod : TWndMethod).

AllocateHWnd用来创建一个不与窗口控件关联的窗口 

WndMethod : TWndMethod

用来指定生成的窗口响应消息的窗口过程。

DeallocateHWnd

DeallocateHWnd 用来销毁AllocateHWnd创建的窗口。

 

下面的TMsgReceiver是从TObject继承的类,并且能处理Windows消息。


[delphi] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. interface  
  2.   
  3.   
  4. TMsgReceiver = class(TObject)  
  5. private  
  6.   fMsgHandlerHWND : HWND;  
  7.   procedure WndMethod(var Msg: TMessage);  
  8. public  
  9.   constructor Create;  
  10.   destructor Destroy; override;  
  11. end;  
  12.   
  13.   
  14. implementation  
  15.   
  16.   
  17. constructor TMsgReceiver.Create;  
  18. begin  
  19.   inherited Create;  
  20.   
  21.   
  22.   fMsgHandlerHWND := AllocateHWnd(WndMethod);  
  23. end;  
  24.   
  25.   
  26. destructor TMsgReceiver.Destroy;  
  27. begin  
  28.   DeallocateHWnd(fMsgHandlerHWND);  
  29.   inherited;  
  30. end;  
  31.   
  32.   
  33. procedure TMsgReceiver.WndMethod(var Msg: TMessage);  
  34. begin  
  35.   if Msg.Msg = WM_MY_UNIQUE_MESSAGE then  
  36.   begin  
  37.     //do something  
  38.   end  
  39.   else  
  40.     Msg.Result := DefWindowProc(fMsgHandlerHWND, Msg.Msg, Msg.wParam, Msg.lParam);  
  41. end;  


在WndMethod过程中(就是隐藏窗口的窗口过程)你可以处理你感兴趣的窗口消息。对于其它消息需要调用默认的消息处理过程DefWindowProc。

 


处理来自其它应用的消息

通过上面的代码,假设其它应用使用RegisterWindowMessage注册了Windows消息,你现在也能处理来自其它应用的消息。RegisterWindowMessage通常用来注册互相协作的应用程序间的消息.

发送消息的应用可能有如下代码:

[delphi] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. WM_MY_APP_MESSAGE := RegisterWindowMessage('MSG_MY_APP_MESSAGE');  


当消息发送到其它窗口时,WM_MY_APP_MESSAGE是一个无符号整数,假设我们在一个事件中发送该消息:

[delphi] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. procedure TClickSendForm.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);  
  2. begin  
  3.   PostMessage(HWND_BROADCAST, WM_MY_APP_MESSAGE, x, y);  
  4. end;  


HWND_BROADCAST参数确保WM_MY_APP_MESSAGE消息被发送到所有的顶层窗口,包括禁用或不可见的窗口,层叠窗口,弹出窗口,当然也包括我们的TMsgReceiver隐藏窗口,为了处理该消息TMsgReceiver的WndMethod如下:

[delphi] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. procedure TMsgReceiver.WndMethod(var Msg: TMessage);  
  2. begin  
  3.   if Msg.Msg = WM_MY_UNIQUE_MESSAGE then  
  4.   begin  
  5.     Point.X := Msg.LParam;  
  6.     Point.Y := Msg.WParam;  
  7.     // just to have some "output"  
  8.     Windows.Beep(Point.X, Point.Y);  
  9.   end  
  10.   else  
  11.     Msg.Result := DefWindowProc(fMsgHandlerHWND, Msg.Msg, Msg.wParam, Msg.lParam);  
  12. end;  

 

"Point"是TMsgReceiver的一个字段. TMsgReceiver接收到其它的应用程序用户在窗口的哪里点击了鼠标。WM_MY_UNIQUE_MESSAGE也需要在TMsgReceiver中进行注册。

 

 

原文:http://blog.csdn.net/maxwoods/article/details/26286017

posted @ 2015-06-28 21:36  卒子  阅读(321)  评论(0)    收藏  举报