打入消息循环的另类方法

原创 2007年01月28日 11:09:00

正常打入消息循环的方法:
如果要监视 WM_CONTEXTMENU 消息来实现菜单的右键菜单,一般做法是通过子类化 (subclass) Menus.PopupList.WndProc 的方法来处理窗口消息。简单讲就是:打入消息循环,完成我的处理,再把消息交还给原先的消息处理函数。当不需要监视消息的时候再退出消息处理(un-subclass)。这样做的好处是:不打破控件的结构。

procedure TMyMenuMessagesHandler.SubclassWndProc;
begin
  FDefMenuProc := Pointer(GetWindowLongA(PopupList.Window, GWL_WNDPROC));
  FObjInstance := Classes.MakeObjectInstance(CustomMenuWndProc);
  SetWindowLongA(PopupList.Window, GWL_WNDPROC, Longint(FObjInstance));
end;

procedure TMyMenuMessagesHandler.UnSubclassWndProc;
begin
  
if Assigned(FDefMenuProc) then
    SetWindowLongA(PopupList.Window, GWL_WNDPROC, Longint(FDefMenuProc));
  
if Assigned(FObjInstance) then
    Classes.FreeObjectInstance(FObjInstance);
end;

procedure TMyMenuMessagesHandler.CustomMenuWndProc(var Message: TMessage);
var
  CancelPopupContextMenu: Boolean;
begin
  
if Message.Msg = WM_CONTEXTMENU then
  
begin
    
// My own code ....
    Message.Result := 
1;
    Exit;
  
end;

  
// Send message to default message handler
  
with Message do
    Result := CallWindowProcA(FDefMenuProc, PopupList.Window, Msg, wParam, lParam);
end


问题的提出
但是这样做有个隐藏问题如果你接管的消息窗口提前释放了那么消息处理链就断了这个时候程序可能会崩溃。如果我们可以直接修改Menus.PopupList.WndProc,那么就不用通过 subclass 来实现消息接管了。幸运的是,对于 Menus.PopupList 这个特殊的全局变量来说,这个是可以做到的。

实现原理:
PopupList 的类型是 TPopupList,我们可以在自己的程序里面定义一个继承类,名为TPopupListEx。因为这是个特殊的全局变量,它是在 Menus.pas 的初始化部分就创建的,我们可以在它创建之后,立刻释放它,然后以 TPopupListEx的形式重新创建。只要声明部分没有任何变化,这种方法可以 “骗过” 任何调用者,它们以为还是在调用TPopupList。

具体代码:
把上面的代码替换成如下代码即可

//PATCH-BEGIN
type
  TPopupListEx = 
class(TPopupList)
  
private
    FOnCustomWndProc: TWndMethod;
  
public
    
property OnCustomWndProc: TWndMethod read FOnCustomWndProc write FOnCustomWndProc;
  
protected
    
procedure WndProc(var Message: TMessage); override;
  
end;

procedure TPopupListEx.WndProc(var Message: TMessage);
begin
  
if Assigned(OnCustomWndProc) then
  
begin
    OnCustomWndProc(Message);
    
if Message.Result = 1 then
      Exit;
  
end;
  
inherited;
end;
//PATCH-END

procedure TMyMenuMessagesHandler.SubclassWndProc;
begin
  
if Assigned(PopupList) then
    TPopupListEx(PopupList).OnCustomWndProc := CustomMenuWndProc;
end;

procedure TMyMenuMessagesHandler.UnSubclassWndProc;
begin
  
if Assigned(PopupList) then
    TPopupListEx(PopupList).OnCustomWndProc := 
nil;
end;

procedure TMyMenuMessagesHandler.CustomMenuWndProc(var Message: TMessage);
var
  CancelPopupContextMenu: Boolean;
begin
  
if Message.Msg = WM_CONTEXTMENU then
  
begin
    
// My own code ....
    Message.Result := 
1;
  
end;
end


initialization
  FreeAndNil(PopupList);
  PopupList := TPopupListEx.Create;

finalization
//FreeAndNil(PopupList); //NOTE: will be freed by finalization section of Menus.pas
end.

 

说明
但是我还不清楚为什么用 subclass 方法的时候,一旦消息窗口释放,程序会崩溃。目前也只能先用这个方法了。

裸板调试方法合集

我们用的比较多的(点灯串口打印)
  • 2017年01月12日 14:55

消息循环的错误分析.txt

  • 2011年09月19日 09:09
  • 3KB
  • 下载

Android 下的多线程

  • 2011年07月20日 08:36
  • 49KB
  • 下载

PTA_6-4 另类堆栈(15 分)_单指针栈

6-4 另类堆栈(15 分) 在栈的顺序存储实现中,另有一种方法是将Top定义为栈顶的上一个位置。请编写程序实现这种定义下堆栈的入栈、出栈操作。如何判断堆栈为空或者满? 函数接口定义:bool P...
  • jianbagengmu
  • jianbagengmu
  • 2017-11-27 14:02:39
  • 598

大数据和AI策略——面向投资的机器学习和另类数据方法

  • 2017年10月08日 21:39
  • 31.79MB
  • 下载

一个比较另类的WINDOWS后门

 在windows 2000/xp/vista下,按shift键5次,可以打开粘置,会运行sethc.exe,而且,在登录界面里也可以打开。这就让人联想到WINDOWS的屏保,将程序替换成cmd.ex...
  • inject2006
  • inject2006
  • 2007-09-15 13:24:00
  • 428

堆栈的顺序存储---顺序栈

堆栈的顺序存储—顺序栈堆栈的顺序存储结构简称顺序栈,它是利用一组地址连续的存储单元依次存放自栈底到栈顶之间的元素。...
  • qq_22583409
  • qq_22583409
  • 2017-10-01 13:57:41
  • 220

ios-消息循环

什么是消息循环? Runloop就叫做消息循环,每一个线程内部都有一个消息循环。 只有主线程的消息循环是默认开启的,子线程的消息循环默认不开启 消息循环的目的 保证程序不退出 负责处理输入事件,就是等...
  • ZCMUCZX
  • ZCMUCZX
  • 2017-08-09 20:50:58
  • 182

Windows 退出消息循环流程

  • 2010年12月10日 01:38
  • 359KB
  • 下载

for循环的另类写法

在做项目的时候经常需要对查询出来的数据进行便利循环 一般会有两种方式for和Iterator ; for循环不能对循环的对象进行remove和add操作 iterator 与while结合代码又...
  • JockTY
  • JockTY
  • 2018-01-26 08:34:03
  • 38
收藏助手
不良信息举报
您举报文章:打入消息循环的另类方法
举报原因:
原因补充:

(最多只允许输入30个字)