原理:该效果的实现主要是使用AllocateHwnd函数(可以查阅Delphi的帮助)生成一个非可视的窗口来响应消息,该函数的返回值既是非可视窗口的句柄。然后就可以在你的类中响应Windows的消息了。该函数只有一个参数就是要创建的非可视窗口的WinProc函数(就是处理该窗口消息的函数),当然你也可以在这个函数中处理你要处理的消息了。最后在类销毁时一定要DeallocateHWnd这个非可视窗口。
这些在翻看Delphi ScktComp单元的Socket类时得到。原因在于好奇这些类如何能得到Windows发给它们的关于Socket的消息。
以下是从TCustomWinSocket类摘出来源码(可以响应消息):
unit uClass;
interface
uses Messages, Classes, Dialogs;
const
WM_MYTEST = WM_USER + $1000; // 测试用
type
TMyClass = class
private
FHandle: THandle;
procedure WinProc(var Msg: TMessage);
procedure WMMyTest(var Msg: TMessage); message WM_MYTEST; // 测试用
public
constructor Create;
destructor Destroy; override;
property Handle: THandle read FHandle;
end;
implementation
{ TMyClass }
constructor TMyClass.Create;
begin
if FHandle = 0 then
FHandle := AllocateHwnd(WinProc);
end;
destructor TMyClass.Destroy;
begin
if FHandle <> 0 then
DeallocateHWnd(FHandle);
end;
procedure TMyClass.WinProc(var Msg: TMessage);
begin
try
//if Msg.Msg = WM_MYTEST then
// ShowMessage('I''m the first get the message "WM_MYTEST"');
Dispatch(Msg);
except
if Assigned(ApplicationHandleException) then
ApplicationHandleException(Self);
end;
end;
procedure TMyClass.WMMyTest(var Msg: TMessage);
begin
ShowMessage('Test OK!' + #10
+ 'I''m coming from Class "TMyClass" with message "WM_MYTEST"!');
end;
end.
后记:这样,这个类就具有了一个句柄,发个消息WM_MYTEST看看。还能执行。呵呵,以后再写需要响应消息的类的时候,直接继承它就可以了,记得要把 WMMyTest过程删掉,它只是一个测试。
测试:
var
mc: TMyClass;
begin
mc := TMyClass.Create;
PostMessage(mc.Handle, WM_MYTEST, 0, 0);
end;
我的程序如下
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, Unit2, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
FPluginRegistry : TPluginRegistry;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
FPluginRegistry := TPluginRegistry.Create;
RegisterWindowMessage('WM_DESERIALIZATION');
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
//如果我用这句就可以接收到自定义的消息
// PostMessage(FPluginRegistry.WindowHandle,WM_DESERIALIZATION,0,0);
//如果用这句就不行,怎么样才能实现广播呢?
PostMessage(HWND_BROADCAST,WM_DESERIALIZATION,0,0);
end;
end.
unit Unit2;
interface
uses Classes, Windows, Messages,Dialogs;
const
WM_DESERIALIZATION = WM_USER + 100;
type
TPluginRegistry = class(TPersistent)
private
FWindowHandle: HWND;
procedure WndProc(var Msg: TMessage);
protected
procedure ProcessSaveProperty; virtual;
public
constructor Create;
destructor Destroy; override;
property WindowHandle : HWND read FWindowHandle;
end;
implementation
uses Forms;
{ TPluginRegistry }
constructor TPluginRegistry.Create;
begin
inherited Create;
FWindowHandle := Classes.AllocateHWnd(WndProc);
end;
destructor TPluginRegistry.Destroy;
begin
Classes.DeallocateHWnd(FWindowHandle);
inherited;
end;
procedure TPluginRegistry.ProcessSaveProperty;
begin
Showmessage('Received');
end;
procedure TPluginRegistry.WndProc(var Msg: TMessage);
begin
with Msg do
if Msg = WM_DESERIALIZATION then
try
ProcessSaveProperty;
except
Application.HandleException(Self);
end
else
Result := DefWindowProc(FWindowHandle, Msg, wParam, lParam);
end;
end.