| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783 |
- {******************************************************************************}
- { CnPack For Delphi/C++Builder }
- { 中国人自己的开放源码第三方开发包 }
- { (C)Copyright 2001-2018 CnPack 开发组 }
- { ------------------------------------ }
- { }
- { 本开发包是开源的自由软件,您可以遵照 CnPack 的发布协议来修 }
- { 改和重新发布这一程序。 }
- { }
- { 发布这一开发包的目的是希望它有用,但没有任何担保。甚至没有 }
- { 适合特定目的而隐含的担保。更详细的情况请参阅 CnPack 发布协议。 }
- { }
- { 您应该已经和开发包一起收到一份 CnPack 发布协议的副本。如果 }
- { 还没有,可访问我们的网站: }
- { }
- { 网站地址:http://www.cnpack.org }
- { 电子邮件:master@cnpack.org }
- { }
- {******************************************************************************}
- unit CnControlHook;
- {* |<PRE>
- ================================================================================
- * 软件名称:开发包基础库
- * 单元名称:控件消息处理过程挂接组件单元
- * 单元作者:周劲羽 (zjy@cnpack.org)
- * 备 注:该单元定义了 TCnControlHook 组件,允许通过替换 TControl 子类的
- * WindowProc 属性来获得控件的消息通知。
- * 开发平台:PWin2000Pro + Delphi 5.0
- * 兼容测试:PWin9X/2000/XP + Delphi 5/6
- * 本 地 化:该单元中的字符串均符合本地化处理方式
- * 单元标识:$Id$
- * 修改记录:2003.04.30 V1.2
- * 修正控件在消息处理过程中释放导致挂接对象出错的问题
- * 2002.10.19 V1.1
- * 重新编写比较完善的组件
- * 2002.10.15 V1.0
- * 创建单元
- ================================================================================
- |</PRE>}
- interface
- {$I CnPack.inc}
- uses
- Windows, Messages, SysUtils, Classes, Controls, Forms, CnClasses, CnConsts,
- CnCompConsts;
- type
- //==============================================================================
- // 控件挂接子项
- //==============================================================================
- { TCnControlHookItem }
- TCnControlHook = class;
- TCnControlHookCollection = class;
- THookMessageEvent = procedure (Sender: TObject; Control: TControl;
- var Msg: TMessage; var Handled: Boolean) of object;
- {* 挂接消息事件
- |<PRE>
- Sender: TObject - 产生事件的组件
- Control: TControl - 该消息要发送的控件对象,即被挂接的控件
- var Msg: TMessage - 消息变量
- var Handled: Boolean - 事件处理过程是否捕获该消息,如果为真将不调用原控件消息过程
- |</PRE>}
- TCnControlHookItem = class(TCollectionItem)
- {* 控件挂接子项类,用于 TCnControlHook 组件中。
- 当被挂接的控件释放时,相关联的 Item 对象也会被自动释放,
- 用户可不用考虑重复挂接的问题,但也不要静态访问 Item 对象。}
- private
- FOwner: TCnControlHookCollection;
- FControl: TControl;
- FBeforeMessage: THookMessageEvent;
- FAfterMessage: THookMessageEvent;
- procedure SetControl(const Value: TControl);
- procedure Hook;
- procedure UnHook;
- protected
- function DoAfterMessage(Control: TControl; var Msg: TMessage): Boolean; dynamic;
- function DoBeforeMessage(Control: TControl; var Msg: TMessage): Boolean; dynamic;
- property Owner: TCnControlHookCollection read FOwner;
- public
- procedure Assign(Source: TPersistent); override;
- constructor Create(Collection: TCollection); override;
- destructor Destroy; override;
- published
- property Control: TControl read FControl write SetControl;
- {* 要 Hook 的控件}
- property BeforeMessage: THookMessageEvent read FBeforeMessage write FBeforeMessage;
- {* 控件消息事件,在默认消息处理过程之前调用}
- property AfterMessage: THookMessageEvent read FAfterMessage write FAfterMessage;
- {* 控件消息事件,在默认消息处理过程之后调用}
- end;
- //==============================================================================
- // 控件挂接列表类
- //==============================================================================
-
- { TCnControlHookCollection }
- TCnControlHookCollection = class(TOwnedCollection)
- {* 控件挂接列表类,用于 TCnControlHook 组件中}
- private
- FOwner: TCnControlHook;
- function GetItem(Index: Integer): TCnControlHookItem;
- procedure SetItem(Index: Integer; const Value: TCnControlHookItem);
- protected
- property ControlHook: TCnControlHook read FOwner;
- public
- constructor Create(AOwner: TCnControlHook);
- destructor Destroy; override;
- function Add(Control: TControl): TCnControlHookItem;
- {* 增加一个控件挂接项}
- procedure Remove(Control: TControl);
- {* 删除一个控件挂接项}
- function IndexOf(Control: TControl): Integer;
- {* 查找控件挂接项}
- property Items[Index: Integer]: TCnControlHookItem read GetItem write SetItem; default;
- {* 控件挂接项数组}
- end;
- //==============================================================================
- // 控件消息过程挂接组件
- //==============================================================================
-
- { TCnControlHook }
- TCnControlHook = class(TCnComponent)
- {* 控件消息过程挂接组件,允许通过替换 TControl 子类的 WindowProc 属性来获得控件的消息通知}
- private
- FActive: Boolean;
- FItems: TCnControlHookCollection;
- FBeforeMessage: THookMessageEvent;
- FAfterMessage: THookMessageEvent;
- procedure SetActive(const Value: Boolean);
- procedure SetItems(const Value: TCnControlHookCollection);
- protected
- function DoAfterMessage(Control: TControl; var Msg: TMessage): Boolean; dynamic;
- function DoBeforeMessage(Control: TControl; var Msg: TMessage): Boolean; dynamic;
- procedure Loaded; override;
- procedure GetComponentInfo(var AName, Author, Email, Comment: string); override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
-
- function IndexOf(Control: TControl): Integer;
- {* 返回指定被挂接控件的索引号,如果不存在,返回 -1}
- function Hook(Control: TControl): TCnControlHookItem;
- {* 挂接指定控件,返回挂接项,如果已挂接返回原挂接项}
- procedure UnHook(Control: TControl);
- {* 取消对指定控件的挂接}
- function IsHooked(Control: TControl): Boolean;
- {* 判断指定控件是否被挂接}
- published
- property Active: Boolean read FActive write SetActive default True;
- {* 是否允许使用}
- property Items: TCnControlHookCollection read FItems write SetItems;
- {* 挂接控件列表}
- property BeforeMessage: THookMessageEvent read FBeforeMessage write FBeforeMessage;
- {* 控件消息事件,在默认消息处理过程之前调用}
- property AfterMessage: THookMessageEvent read FAfterMessage write FAfterMessage;
- {* 控件消息事件,在默认消息处理过程之后调用}
- end;
- implementation
- const
- UM_DESTROYHOOK = WM_USER + 101;
- type
- //==============================================================================
- // 控件消息处理过程挂接对象(私有类)
- //==============================================================================
-
- { TCnControlHookObject }
- TCnControlHookMgr = class;
- TCnControlHookObject = class
- private
- FList: TList;
- FControlHookMgr: TCnControlHookMgr;
- FControl: TControl;
- FOldWndProc: TWndMethod;
- FUpdateCount: Integer;
- FAutoFree: Boolean;
- function GetCount: Integer;
- function GetItem(Index: Integer): TCnControlHookItem;
- protected
- procedure WndProc(var Message: TMessage);
- property Control: TControl read FControl;
- property ControlHookMgr: TCnControlHookMgr read FControlHookMgr;
- public
- constructor Create(AControlHookMgr: TCnControlHookMgr; AControl: TControl);
- destructor Destroy; override;
- function Add(Item: TCnControlHookItem): Integer;
- procedure DoFree;
- function Updating: Boolean;
-
- procedure Delete(Item: TCnControlHookItem); overload;
- procedure Delete(Index: Integer); overload;
- property Count: Integer read GetCount;
- property Items[Index: Integer]: TCnControlHookItem read GetItem;
- end;
- //==============================================================================
- // 控件消息处理过程挂接组件(私有类)
- //==============================================================================
- { TCnControlHookMgr }
- TCnControlHookMgr = class(TComponent)
- {* 控件消息挂接组件,通过替换 TControl 子类的 WindowProc 属性来工作}
- private
- FList: TList;
- function GetCount: Integer;
- function GetHookedControls(Index: Integer): TControl;
- function GetItem(Index: Integer): TCnControlHookObject;
- protected
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure HookControl(Item: TCnControlHookItem);
- procedure UnhookControl(Item: TCnControlHookItem); overload;
- procedure UnhookControl(Control: TControl); overload;
- function IndexOf(Control: TControl): Integer;
- property Count: Integer read GetCount;
- property HookedControls[Index: Integer]: TControl read GetHookedControls;
- property Items[Index: Integer]: TCnControlHookObject read GetItem;
- end;
- var
- ControlHookMgr: TCnControlHookMgr;
- // 返回挂接管理器
- function GetControlHookMgr: TCnControlHookMgr;
- begin
- if not Assigned(ControlHookMgr) then
- ControlHookMgr := TCnControlHookMgr.Create(nil);
- Result := ControlHookMgr;
- end;
-
- //==============================================================================
- // 控件消息处理过程挂接对象(私有类)
- //==============================================================================
-
- { TCnControlHookObject }
- // 构造器
- constructor TCnControlHookObject.Create(AControlHookMgr: TCnControlHookMgr;
- AControl: TControl);
- begin
- Assert(Assigned(AControlHookMgr) and Assigned(AControl));
- FUpdateCount := 0;
- FAutoFree := False;
- FList := TList.Create;
- FControlHookMgr := AControlHookMgr;
- FControl := AControl;
- FOldWndProc := FControl.WindowProc;
- FControl.WindowProc := WndProc;
- FControl.FreeNotification(FControlHookMgr);
- end;
- // 析构器
- destructor TCnControlHookObject.Destroy;
- var
- i: Integer;
- begin
- try // 异常保护
- if Assigned(FControl) then
- begin
- FControlHookMgr.FList.Remove(Self);
- FControl.RemoveFreeNotification(FControlHookMgr);
- FControl.WindowProc := FOldWndProc;
- FControl := nil;
- end;
- for i := 0 to Count - 1 do
- Items[i].Free;
- FList.Free;
- except
- Application.HandleException(Self);
- end;
- inherited;
- end;
- function TCnControlHookObject.Updating: Boolean;
- begin
- Result := FUpdateCount > 0;
- end;
- procedure TCnControlHookObject.DoFree;
- begin
- if Updating then
- begin
- FAutoFree := True;
- try
- FControlHookMgr.FList.Remove(Self);
- FControl.RemoveFreeNotification(FControlHookMgr);
- FControl.WindowProc := FOldWndProc;
- FControl := nil;
- except
- Application.HandleException(Self);
- end;
- end
- else
- Free;
- end;
- // 新的消息处理过程
- procedure TCnControlHookObject.WndProc(var Message: TMessage);
- var
- i: Integer;
- Handled: Boolean;
- begin
- try
- Inc(FUpdateCount);
- try
- Handled := False;
- // 调用挂接消息前处理过程
- for i := Count - 1 downto 0 do // 后挂接的先处理
- if Assigned(Items[i].FOwner) and Assigned(Items[i].FOwner.FOwner) and
- Items[i].FOwner.FOwner.FActive and Items[i].DoBeforeMessage(FControl,
- Message) then
- begin
- Handled := True;
- Break;
- end;
- if Handled then Exit;
- // 调用原处理过程
- if Assigned(FOldWndProc) then
- FOldWndProc(Message);
- // 调用挂接消息后处理过程
- if not FAutoFree then
- begin
- for i := Count - 1 downto 0 do // 后挂接的先处理
- if Assigned(Items[i].FOwner) and Assigned(Items[i].FOwner.FOwner) and
- Items[i].FOwner.FOwner.FActive and Items[i].DoAfterMessage(FControl,
- Message) then
- Break;
- end;
- finally
- Dec(FUpdateCount);
- end;
- // 此处进行释放
- if FAutoFree then
- Free;
- except
- Application.HandleException(Self);
- end;
- end;
- //------------------------------------------------------------------------------
- // 列表操作方法
- //------------------------------------------------------------------------------
- // 增加一项
- function TCnControlHookObject.Add(Item: TCnControlHookItem): Integer;
- begin
- if FList.IndexOf(Item) < 0 then
- begin
- Item.FControl := FControl;
- Result := FList.Add(Item);
- end
- else
- Result := -1;
- end;
- // 根据索引号删除一项
- procedure TCnControlHookObject.Delete(Index: Integer);
- begin
- if (Index >= 0) and (Index < FList.Count) then
- begin
- FList.Delete(Index);
- if Count = 0 then // 无挂接项时自动释放
- DoFree;
- end;
- end;
- // 根据子项删除一项
- procedure TCnControlHookObject.Delete(Item: TCnControlHookItem);
- begin
- Delete(FList.IndexOf(Item));
- end;
- //------------------------------------------------------------------------------
- // 属性读写方法
- //------------------------------------------------------------------------------
- // Count 属性读方法
- function TCnControlHookObject.GetCount: Integer;
- begin
- Result := FList.Count;
- end;
- // Items 数组属性读方法
- function TCnControlHookObject.GetItem(Index: Integer): TCnControlHookItem;
- begin
- Result := TCnControlHookItem(FList[Index]);
- end;
- //==============================================================================
- // 控件消息处理过程挂接组件(私有类)
- //==============================================================================
- { TCnControlHookMgr }
- // 构造器
- constructor TCnControlHookMgr.Create(AOwner: TComponent);
- begin
- inherited;
- FList := TList.Create;
- end;
- // 析构器
- destructor TCnControlHookMgr.Destroy;
- var
- i: Integer;
- begin
- for i := Count - 1 downto 0 do
- Items[i].DoFree;
- FList.Free;
- inherited;
- end;
- //------------------------------------------------------------------------------
- // 挂接相关方法
- //------------------------------------------------------------------------------
- // 组件通知事件
- procedure TCnControlHookMgr.Notification(AComponent: TComponent;
- Operation: TOperation);
- begin
- inherited;
- if (Operation = opRemove) and (AComponent is TControl) then
- UnhookControl(TControl(AComponent)); // 控件释放时反挂接
- end;
- // 返回控件索引号
- function TCnControlHookMgr.IndexOf(Control: TControl): Integer;
- var
- i: Integer;
- begin
- Result := -1;
- for i := 0 to Count - 1 do
- if HookedControls[i] = Control then
- begin
- Result := i;
- Exit;
- end;
- end;
- // 挂接控件
- procedure TCnControlHookMgr.HookControl(Item: TCnControlHookItem);
- var
- Obj: TCnControlHookObject;
- Idx: Integer;
- begin
- Assert(Assigned(Item) and Assigned(Item.FControl));
- Idx := IndexOf(Item.FControl);
- if Idx < 0 then
- begin
- Obj := TCnControlHookObject.Create(Self, Item.FControl);
- Obj.Add(Item);
- FList.Add(Obj);
- end
- else
- Items[Idx].Add(Item);
- end;
- // 反挂接控件
- procedure TCnControlHookMgr.UnhookControl(Item: TCnControlHookItem);
- var
- Idx: Integer;
- begin
- Assert(Assigned(Item) and Assigned(Item.FControl));
- Idx := IndexOf(Item.FControl);
- if Idx >= 0 then
- Items[Idx].Delete(Item);
- end;
- // 反挂接控件
- procedure TCnControlHookMgr.UnhookControl(Control: TControl);
- var
- Idx: Integer;
- begin
- Idx := IndexOf(Control);
- if Idx >= 0 then
- Items[Idx].DoFree;
- end;
- //------------------------------------------------------------------------------
- // 属性读写方法
- //------------------------------------------------------------------------------
- // HookedControlCount 属性读方法
- function TCnControlHookMgr.GetCount: Integer;
- begin
- Result := FList.Count;
- end;
- // HookedControls 属性读方法
- function TCnControlHookMgr.GetHookedControls(Index: Integer): TControl;
- begin
- Result := TCnControlHookObject(FList[Index]).Control;
- end;
- // Items 数组属性读方法
- function TCnControlHookMgr.GetItem(Index: Integer): TCnControlHookObject;
- begin
- Result := TCnControlHookObject(FList[Index]);
- end;
- //==============================================================================
- // 控件挂接子项
- //==============================================================================
-
- { TCnControlHookItem }
- // 类构造器
- constructor TCnControlHookItem.Create(Collection: TCollection);
- begin
- inherited;
- Assert(Assigned(Collection));
- FOwner := TCnControlHookCollection(Collection);
- end;
- // 类析构器
- destructor TCnControlHookItem.Destroy;
- begin
- if Assigned(FControl) then
- GetControlHookMgr.UnhookControl(Self);
- inherited;
- end;
- // 对象赋值
- procedure TCnControlHookItem.Assign(Source: TPersistent);
- begin
- if Source is TCnControlHookItem then
- begin
- TCnControlHookItem(Source).Control := FControl;
- end
- else
- inherited;
- end;
- // 产生 AfterMessage 事件
- function TCnControlHookItem.DoAfterMessage(Control: TControl;
- var Msg: TMessage): Boolean;
- begin
- Result := FOwner.FOwner.DoAfterMessage(Control, Msg);
- if not Result and FOwner.FOwner.FActive and Assigned(FAfterMessage) then
- FAfterMessage(Self, Control, Msg, Result);
- end;
- // 产生 BeforeMessage 事件
- function TCnControlHookItem.DoBeforeMessage(Control: TControl;
- var Msg: TMessage): Boolean;
- begin
- Result := FOwner.FOwner.DoBeforeMessage(Control, Msg);
- if not Result and FOwner.FOwner.FActive and Assigned(FBeforeMessage) then
- FBeforeMessage(Self, Control, Msg, Result);
- end;
- // 挂接
- procedure TCnControlHookItem.Hook;
- begin
- if ([csLoading, csDesigning] * FOwner.FOwner.ComponentState = []) and
- Assigned(FControl) then
- GetControlHookMgr.HookControl(Self);
- end;
- // 反挂接
- procedure TCnControlHookItem.UnHook;
- begin
- if ([csLoading, csDesigning] * FOwner.FOwner.ComponentState = []) and
- Assigned(FControl) then
- GetControlHookMgr.UnhookControl(Self);
- end;
- // Control 属性写方法
- procedure TCnControlHookItem.SetControl(const Value: TControl);
- begin
- if Value <> FControl then
- begin
- UnHook;
- FControl := Value;
- Hook;
- end;
- end;
- //==============================================================================
- // 控件挂接列表类
- //==============================================================================
-
- { TCnControlHookCollection }
- // 构造器
- constructor TCnControlHookCollection.Create(AOwner: TCnControlHook);
- begin
- inherited Create(AOwner, TCnControlHookItem);
- FOwner := AOwner;
- end;
- // 析构器
- destructor TCnControlHookCollection.Destroy;
- begin
- inherited;
- end;
- // 增加一项
- function TCnControlHookCollection.Add(Control: TControl): TCnControlHookItem;
- var
- Idx: Integer;
- begin
- Idx := IndexOf(Control);
- if Idx >= 0 then
- Result := Items[Idx]
- else
- begin
- Result := TCnControlHookItem(inherited Add);
- Result.Control := Control;
- end;
- end;
- // 删除一项
- procedure TCnControlHookCollection.Remove(Control: TControl);
- var
- Idx: Integer;
- begin
- Idx := IndexOf(Control);
- if Idx >= 0 then
- Items[Idx].Free;
- end;
- // 查找子项
- function TCnControlHookCollection.IndexOf(Control: TControl): Integer;
- var
- i: Integer;
- begin
- Result := -1;
- for i := 0 to Count - 1 do
- if Items[i].FControl = Control then
- begin
- Result := i;
- Exit;
- end;
- end;
- // Items 数组属性读方法
- function TCnControlHookCollection.GetItem(
- Index: Integer): TCnControlHookItem;
- begin
- Result := TCnControlHookItem(inherited Items[Index]);
- end;
- // Items 数组属性写方法
- procedure TCnControlHookCollection.SetItem(Index: Integer;
- const Value: TCnControlHookItem);
- begin
- inherited SetItem(Index, Value);
- end;
- //==============================================================================
- // 控件消息过程挂接组件
- //==============================================================================
-
- { TCnControlHook }
- // 构造器
- constructor TCnControlHook.Create(AOwner: TComponent);
- begin
- inherited;
- FItems := TCnControlHookCollection.Create(Self);
- FActive := True;
- end;
- // 析构器
- destructor TCnControlHook.Destroy;
- begin
- FItems.Free;
- inherited;
- end;
- // 运行期属性已装载
- procedure TCnControlHook.Loaded;
- var
- i: Integer;
- begin
- inherited;
- for i := 0 to Items.Count - 1 do
- Items.Items[i].Hook;
- end;
- // 挂接指定控件,返回挂接项索引号,如果已挂接返回原挂接项索引号
- function TCnControlHook.Hook(Control: TControl): TCnControlHookItem;
- begin
- Result := Items.Add(Control);
- end;
- // 返回指定被挂接控件的索引号,如果不存在,返回 -1
- function TCnControlHook.IndexOf(Control: TControl): Integer;
- begin
- Result := Items.IndexOf(Control);
- end;
- // 判断指定控件是否被挂接
- function TCnControlHook.IsHooked(Control: TControl): Boolean;
- begin
- Result := IndexOf(Control) >= 0;
- end;
- // 取消对指定控件的挂接
- procedure TCnControlHook.UnHook(Control: TControl);
- begin
- Items.Remove(Control);
- end;
- //------------------------------------------------------------------------------
- // 产生事件方法
- //------------------------------------------------------------------------------
- // 产生AfterMessage事件
- function TCnControlHook.DoAfterMessage(Control: TControl;
- var Msg: TMessage): Boolean;
- begin
- Result := False;
- if Active and Assigned(FAfterMessage) then
- FAfterMessage(Self, Control, Msg, Result);
- end;
- // 产生BeforeMessage事件
- function TCnControlHook.DoBeforeMessage(Control: TControl;
- var Msg: TMessage): Boolean;
- begin
- Result := False;
- if Active and Assigned(FBeforeMessage) then
- FBeforeMessage(Self, Control, Msg, Result);
- end;
- // Active 属性写方法
- procedure TCnControlHook.SetActive(const Value: Boolean);
- begin
- FActive := Value;
- end;
- // Items 属性写方法
- procedure TCnControlHook.SetItems(
- const Value: TCnControlHookCollection);
- begin
- FItems.Assign(Value);
- end;
- // 取作者信息
- procedure TCnControlHook.GetComponentInfo(var AName, Author, Email,
- Comment: string);
- begin
- AName := SCnControlHookName;
- Author := SCnPack_Zjy;
- Email := SCnPack_ZjyEmail;
- Comment := SCnControlHookComment;
- end;
- initialization
- finalization
- if Assigned(ControlHookMgr) then
- FreeAndNil(ControlHookMgr);
- end.
|