为什么要这样做?
有时候我们需要一个非窗口组件(比如一个非继承自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
to handle messages passed to our
hidden window
窗口过程的调用Windows将通过我们的
隐藏窗口来处理消息
********************************}
...
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------------------
当然,我们正是使用Windows API函数创建一个窗体这种困难的方法提供给Windows过程。它是一种用一个方法作为一个窗口过程很困难的方法,如果我们使用它的话。关于AllocateHWnd函数明智的用法是a创建一个隐藏的窗口给我们同时B允许我是用一个方法。而不是一个简单的函数作为窗口的过程同时一个方法自从他存取了类的私有数据后变得很有用。
后记:第一次翻译文章,可能有些地方理解的不是很透彻,所以附录原文地址如下.
原文:http://www.delphidabbler.com/articles?article=1