打入消息循环的另类方法

原创 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 方法的时候,一旦消息窗口释放,程序会崩溃。目前也只能先用这个方法了。

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

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

另类数据Alternative Data行业调查

Alternative Data行业调查 1. 另类数据的定义: “Alternative data in finance refers to any data that is not tradi...
  • Richard_More
  • Richard_More
  • 2016年11月15日 00:08
  • 820

Maven<打包Scala程序打不进class文件和依赖的解决办法>

新建一个Maven项目,开开心心地写完scala程序,在本地调试没什么问题,要打包部署在spark集群上运行的时候却出错了,说找不到主类java.lang.ClassNotFoundException...
  • Gpwner
  • Gpwner
  • 2017年06月18日 23:43
  • 983

maven 将依赖包打入war中

maven-assembly-plugin src/main/resources/assembly.xml ...
  • kkgbn
  • kkgbn
  • 2016年12月09日 01:21
  • 799

我是IT另类吗?

下个学期开学就大二了,各种课程接踵而至,数据结构,数字电路,计网基础,Java设计 小生感到甚是迷茫,问了C++老师,他说搞 ACM是条好出路 ACM难暂且不提,当身边的朋友一个个去搞实际的项目并...
  • huhuhuhuywh
  • huhuhuhuywh
  • 2015年08月14日 10:00
  • 160

gitlab上新建项目 并将已有项目添加进VS2017

今天第一次用gitlab添加新项目(gitlab是公司内网搭的),怕忘  记一下  环境 VS2017  1.添加项目 然后在提示框填该填的 然后你会看到一个空白的项目 记住框起来的这个htt...
  • niuniuyaobuyao
  • niuniuyaobuyao
  • 2018年01月15日 14:34
  • 15

Lonlife-ACM 1000 - Spoon Devil's 3-D Matrix(最小生成树)——“玲珑杯”acm比赛-试运行赛

Lonlife-ACM 1000 - Spoon Devil's 3-D Matrix(最小生成树)——“玲珑杯”acm比赛-试运行赛...
  • queuelovestack
  • queuelovestack
  • 2016年10月01日 21:30
  • 1030

Java中另类使用内存的方法

Java中另类使用内存的方法  Published: 09 Mar 2014  Category: Java sun.misc.Unsafe为你大开Java的方便之门,你可以用它做很多...
  • asia_one
  • asia_one
  • 2014年03月10日 14:43
  • 298

另类DLL加载方法 —— PEAnalyais

本文详细介绍了PE文件解析方法,C++源码示例介绍如何解析PE文件从而打造自己的GetProcAddress,从资源文件中调用dll函数(无需释放文件) 转载请注明出处:http://blog.cs...
  • wangningyu
  • wangningyu
  • 2013年03月25日 13:31
  • 3210

Java中另类使用内存的方法

sun.misc.Unsafe为你大开Java的方便之门,你可以用它做很多Java不允许的事情,在一些非常特殊的场景下它还是非常有用的。99%的时候,你都应该避免使用它,然而在有些非常罕见的情况下,只...
  • spidercoco
  • spidercoco
  • 2014年03月10日 00:19
  • 1052
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:打入消息循环的另类方法
举报原因:
原因补充:

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