为什么要这样做?

有时候我们需要一个非窗口组件(比如一个非继承自TWinContrl的组件)可以接受Windows消息。要接受消息就需要一个窗口句柄,但是非窗口组件却没有句柄。这篇文章将讲述怎么让一个没有句柄的组件如何通过一个隐藏的窗口接受消息

这是怎么做到的?

例如
我的剪贴板查看组件就是一个不可视的组件。这个窗体可以接收提供信息关于更改剪贴板的消息。

Delphi库里面的AllocateHWnd函数可以帮助我们创建一个隐藏的窗口,同时与之相关的DeallocateHWnd函数可以释放当我们使用完的隐藏窗口。

这个隐藏的窗口将命令窗口过程。

通常当Windows调用一个stdcall函数时,AllocateHWnd函数能让我们像窗体过程一样的使用方法。

我们通过一个引用allocatehwnd函数所需的方法来并将它注册为一个窗口过程的方法来解决问题。

在这个被注册的方法内部我们可以处理我们感兴趣的消息同时传递给Windows

下面的代码清单2停工了一个如何使用AllocateHWnd函数的框架。尽管如此,我们的代码清单1定义一个组件类的轮廓:

------------------代码清单1------------------
type
  {*******************************
   Our class derived from TComponent 
    or another ancestor class
  ********************************}
  TMyClass = class(TComponent)
  private
    fHWnd: HWND;
      {*******************************
       field to store the window handle
       存储窗口句柄的字段 
      ********************************}
    ...
  protected
    procedure WndMethod(var Msg: TMessage); virtual;
    {*******************************  
     window proc - called by Windows    窗口过程(window proc) 由windows系统调用
     to handle messages passed to our
     hidden window    该窗口过程是用来处理传递到我们的隐藏窗口的
    ********************************}
    ...
  public
     constructor Create(AOwner: TComponent); override;
     {*******************************
      create hidden window here: 
      store handle in fHWnd
      在这里创建隐藏窗体,并且把它的句柄存储在fHWnd字段。

********************************}
     destructor Destroy; override;
     {*******************************
      free hidden window here
      销毁隐藏窗口过程
     ********************************}
     ...
  end;
------------------代码清单1------------------

同时下面将是实现部分的详细代码:

------------------代码清单2------------------
constructor TMyClass.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ...
  //创建一个隐藏窗体并且用WndMethod过程
  fHWnd := AllocateHWnd(WndMethod);
  ...
end;

destructor TMyClass.Destroy;
begin
  ...
  //销毁隐藏窗口
  DeallocateHWnd(fHWnd);
  ...
  inherited Destroy;
end;

procedure TMyClass.WndMethod(var Msg : TMessage);
var
  Handled: Boolean;
begin
  //假定我们可以处理消息
  Handled := True;
  case Msg.Msg of
    WM_SOMETHING: DoSomething;
       //处理消息的代码

WM_SOMETHINGELSE: DoSomethingElse;
       //处理另一个消息的代码
    //这里处理其他的消息
    else
      //我们不再处理消息
      Handled := False;
  end;

if Handled then
    //我们在消息记录里处理消息
    Msg.Result := 0
  else
    //我们通过DefWindowProc函数
    //不处理的消息同时记录结果
    Msg.Result := DefWindowProc(fHWnd,
                                Msg.Msg, 
                                Msg.WParam,
                                Msg.LParam);
end;
------------------代码清单2------------------

原文:Of course, we could just use the Windows API to create a window the hard way and provide a windows procedure.

But it is more difficult to use a method as a window procedure if we do it this way.

The clever features about AllocateHWnd are that (a) it creates the hidden window for us and (b) it allows us to use a method, rather than a simple procedure,

as the window procedure – and a method is more useful since it has access to the class's private data.

译文:当然,我们仅使用 Windows API提供的比较难的方式创建了一个window(窗口)并提供窗口过程。
但是,如果我们采用这种方式,那么把一个方法作为窗口过程来使用的话将是困难的。

关于AllocateHWnd灵活的特性有:
(a)它创建一个隐藏窗口给我们使用
(b)它允许我们使用一个方法,而不是一个简单的过程(procedure),作为该窗口过程——当使用这个方法来访问该类的私有数据的时候更加有用。

后记:第一次翻译文章,可能有些地方理解的不是很透彻,所以附录原文地址如下.

原文:http://www.delphidabbler.com/articles?article=1

让一个非窗口组件(non-windowed component)可以接受来自Windows的消息的更多相关文章

  1. 怎么让一个非窗口组件可以接受来自Windows的消息

    为什么要这样做? 有时候我们需要一个非窗口组件(比如一个非继承自TWinContrl的组件)可以接受Windows消息.要接受消息就需要一个窗口句柄,但是非窗口组件却没有句柄.这篇文章将讲述怎么让一个 ...

  2. Java-Spring MVC如何返回一个非JSP文件名字的地址

    return new ModelAndView("redirect:/bizitem/goEditItem.do?item_id="+item_id+"&msg= ...

  3. 4年前端、2年CTO:一个非科班程序员的真实奋斗史

    1.引言   我,Scott,一家创业公司的 CTO. 从业6年却很少写文章,近一年来接触了几十个刚毕业的前端新人,也面试了100多个前端工程师和Nodejs工程师,对于前端发展的这个职业算是有些感触 ...

  4. [物理学与PDEs]第3章习题1 只有一个非零分量的磁场

    设磁场 ${\bf H}$ 只有一个非零分量, 试证明 $$\bex ({\bf H}\cdot\n){\bf H}={\bf 0}. \eex$$ 证明: 不妨设 ${\bf H}=(0,0,H_3 ...

  5. Quartz的集群模式和单机模式共存-让一个非集群的Quartz与集群节点并行着运行

    假如你让一个非集群的 Quartz 应用与集群节点并行着运行,设法使用 JobInitializationPlugin和 RAMJobStore Quartz支持可选节点执行jobquartz集群,会 ...

  6. 最后一个非零数字(POJ 1604、POJ 1150、POJ 3406)

    POJ中有些问题给出了一个长数字序列(即序列中的数字非常多),这个长数字序列的生成有一定的规律,要求求出这个长数字序列中某个位上的数字是多少.这种问题通过分析,找出规律就容易解决. 例如,N!是一个非 ...

  7. coalesce函数-返回参数中第一个非null值

    coalesce函数-返回参数中第一个非null值 学习了:http://www.cnblogs.com/zc_0101/archive/2009/08/11/1543650.html 这个要复杂一些 ...

  8. Python算法每日一题--001--给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素

    给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次.找出那个只出现了一次的元素. 说明: 你的算法应该具有线性时间复杂度. 你可以不使用额外空间来实现吗? 示例 1: 输入: [ ...

  9. 一个非侵入的Go事务管理库——如何使用

    在文章"清晰架构(Clean Architecture)的Go微服务: 事物管理"中,我谈到了如何在清晰架构中实现非侵入的事务管理. 它允许你把事务代码与业务逻辑代码分开,并且让你 ...

随机推荐

  1. python运算符&优先性

    (1)算数运算符:  +      -      *      /      //(求整)      %(求余)      ** (2)比较运算符:  >      <     >  ...

  2. 第9章 应用层(2)_动态主机配置协议(DHCP)

    2. 动态主机配置协议(DHCP) 2.1 静态地址和动态地址的应用场景 (1)静态地址应用场景 ①IP地址不经常更改的设备(如服务器地址) ②使用有规律的IP地址以便于管理(如学校机房为方便教师管理 ...

  3. ECharts动态加载堆叠柱状图的实例

    一.引入echarts.js文件(下载页:http://echarts.baidu.com/download.html) 二.HTML代码: <div style="width: 10 ...

  4. 爬虫概念 requests模块

    requests模块 - 基于如下5点展开requests模块的学习 什么是requests模块 requests模块是python中原生的基于网络请求的模块,其主要作用是用来模拟浏览器发起请求.功能 ...

  5. ES6学习笔记<一> let const class extends super

    学习参考地址1  学习参考地址2 ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准.因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015:也 ...

  6. nodejs多语句查询

    执行多条查询语句 为了安全起见,默认情况下是不允许执行多条查询语句的.要使用多条查询语句的功能,就需要在创建数据库连接的时候打开这一功能: var connection = mysql.createC ...

  7. redis导数到mysql

    filename=$(date "+%Y%m%d%H%M%S") //将type为list,键为bi0205导出文本,并保存到mysql导入导出目录redis-cli -h 服务器 ...

  8. 复习 HTML

    1.<b></b>:加粗 <i></b>:斜体 <u></u>:文字下划线 <s></s>:文字删除线 ...

  9. hive安装教程本地模式

    1.安装模式介绍: Hive官网上介绍了Hive的3种安装方式,分别对应不同的应用场景. a.内嵌模式(元数据保村在内嵌的derby种,允许一个会话链接,尝试多个会话链接时会报错) b.本地模式(本地 ...

  10. microsoft visual c++ 14.0 is required问题解决办法

    方法有两个: 1.绕过pip,手动下载包 2.升级vc 详情参考:https://blog.csdn.net/amoscn/article/details/78215641