分享
 
 
 

具有自动恢复功能的通知栏图标控件

王朝delphi·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

任务栏(Taskbar)是微软公司在Windows 95中引入的一种特殊的桌面工具条,它为用户快速访问计算机资源提供了极大的方便,而状态栏(以下称通知栏)无疑是任务栏上较为特殊的一个窗口。编程人员可以调用API函数Shell_NotifyIcon向通知栏发送消息来添加、删除或修改图标,当在图标上发生鼠标或键盘事件时,系统会向应用程序发送编程时预先定义的消息,通知栏处理回调函数就会被自动调用以做出相应的处理。实现上述功能的相关文章俯仰即拾,此处不再赘述。本文将讨论两个较为深入的问题及其在Delphi中的实现方法。

1、Windows发生错误导致外壳Explorer.exe重启时通知栏图标的自动恢复

2、将自动恢复功能封装在控件中以便其它程序中调用。

关键词:通知栏、窗口过程

1外壳Explorer重启时通知栏图标的自动恢复

相信很多Windows用户都碰到过这种情况:运行某个程序时出现意外错误,导致外壳程序Explorer.exe崩溃而发生重启(即Explorer.exe被关闭后重新运行),任务栏也在消失后重新生成,但应用程序在通知栏添加的图标消失了,虽然这些程序仍在运行,但再也无法通过通知栏图标与用户交互。为避免这种情况出现,Windows提供了相应的机制。

在安装了Internet Explorer 4.0及以上版本的Windows操作系统中,当任务栏建立后,外壳会向所有顶层的应用程序发出通知消息,该消息是外壳以字符串"TaskbarCreated"为参数向系统注册获得的,应用程序窗口接收到该消息后就应该重新添加的通知栏图标。

在Delphi中实现过程如下:

1). 定义一个整型变量MsgTaskbarRestart,用以保存任务栏重建的消息。

2). 在主程序的initialization部分或者是在OnCreate事件中以"TaskbarCreated"为参数向系统注册消息(也即是询问"TaskbarCreated"是哪条消息,因为以相同的参数注册会得到相同的消息,而"TaskbarCreated"在Windows启动的时候就已经被外壳注册)。

initialization

MsgTaskbarRestart := RegisterWindowMessage('TaskbarCreated');

3). 重载主窗口的消息处理过程,拦截任务栏重建消息,进行重新添加图标的操作。

procedure TMainForm.WndProc(var Message: TMessage);

begin

……

if Message.Msg = MsgTaskbarRestart then

begin

TrayIcon.Active := False; //删除通知栏图标

TrayIcon.Active := True; //添加通知栏图标

end;

……

inherited WndProc(Message);

end; //end of WndProc

2自动恢复功能的封装

由于外壳只向所有顶层的应用程序发送通知,这为封装自动恢复功能带来了一定的困难。因为通知栏图标的回调函数只能接收WM_XBUTTONDOWN、WM_XBUTTONUP等有限的几个消息,并不能接收所有的窗口消息。本节介绍的方法将使得在控件中能够接收窗口消息,从而实现自动恢复功能的封装。

解决问题的关键是SetWindowLong函数,向它传入GWL_WNDPROC参数,可以改变一个窗口的窗口过程。只需在创建控件时将应用程序窗口的窗口过程指针保存起来,并指向为控件中的某个新的窗口处理过程,在控件中就能够响应所有的窗口消息了(包括任务栏重建的消息);当控件销毁的时候再将保存的原始窗口过程指针恢复即可。实现代码如下(其中"……"的地方略去容易实现的添加、删除通知栏图标等函数及过程):

TEoCSysTray = class(TComponent)

Private

……

FActive: boolean;

FParentWindow: TWinControl; //父窗口

FNewWndProc: Pointer; //新的父窗口过程指针

FPrevWndProc: Pointer; //原先的父窗口过程指针

FTaskBarCreated: TNotifyEvent; //任务栏重建事件

……

procedure SetActive(Value: boolean); //设置控件是否起作用

procedure HookParentForm; //替换父窗口的窗口过程

procedure UnHookParentForm; //还原父窗口的窗口过程

procedure HookWndProc(var AMsg: TMessage); //新的父窗口过程

protected

procedure DoTaskBarCreated; dynamic; //触发任务栏重建事件

public

constructor Create(AOwner: TComponent); override;

destructor Destroy; override;

property Active: boolean read FActive write SetActive;

property OnTaskBarCreated: TNotifyEvent read FTaskBarCreated

write FTaskBarCreated;

implementation

type

THack = class(TWinControl); //用以访问位于父窗口保护域的默认窗口处理过程

var

MsgTaskbarCreated : Integer; //由系统注册的任务栏重建消息

constructor TEoCSysTray.Create(AOwner: TComponent);

begin

inherited Create(AOwner);

……

FActive := false;

FNewWndProc := MakeObjectInstance(HookWndProc);//建立新的窗口过程指针

FPrevWndProc := nil;

if (AOwner <> nil) and (AOwner is TForm) then //获得父窗口

FParentWindow := TWinControl(AOwner)

else

FParentWindow := Application.MainForm;

……

end;//end of Contructor

destructor TEoCSysTray.Destroy;

begin

……

FDestroying := True;

FParentWindow := nil;

FreeObjectInstance(FNewWndProc);

FNewWndProc := nil;

……

inherited Destroy;

end; //end of destructor

procedure TEoCSysTray.SetActive(Value: boolean);

begin

if Value <> FActive then

begin

FActive := Value;

if not (csDesigning in ComponentState) then //控件未处于设计状态

case Value of

True:

begin

……

HookParentForm; //替换父窗口的窗口过程

……

end;

False:

begin

……

UnHookParentForm; //还原父窗口的窗口过程

……

end;

end;

end;

end; //end of procedure SetActive

procedure TEoCSysTray.HookParentForm; //替换父窗口的窗口过程

var

P : Pointer;

begin

if Assigned(FParentWindow) and

not ((csDesigning in FParentWindow.ComponentState) or

(csDestroying in FParentWindow.ComponentState) or FDestroying) then

begin

FParentWindow.HandleNeeded;

P := Pointer(GetWindowLong(FParentWindow.Handle, GWL_WNDPROC));

if (P <> FNewWndProc) then

begin

FPrevWndProc := P;

SetWindowLong(FParentWindow.Handle,

GWL_WNDPROC, LongInt(FNewWndProc)); //替换父窗口的窗口过程

end;

end;

end; //end of procedure HookParentForm

procedure TEoCSysTray.UnHookParentForm; //还原父窗口的窗口过程

begin

if Assigned(FParentWindow) then

begin

if Assigned(FPrevWndProc) and FParentWindow.HandleAllocated and

(Pointer(GetWindowLong(FParentWindow.Handle, GWL_WNDPROC)) = FNewWndProc) then

SetWindowLong(FParentWindow.Handle,

GWL_WNDPROC, LongInt(FPrevWndProc)); //还原父窗口的窗口过程

end;

FPrevWndProc := nil;

end; //end of procedure UnHookParentForm

procedure TEoCSysTray.HookWndProc(var AMsg: TMessage);

begin

if Assigned(FParentWindow) then

begin

with AMsg do

begin

if Msg = MsgTaskbarCreated then //接收到任务栏重建消息

DoTaskBarCreated; //触发任务栏重建事件

if Assigned(FPrevWndProc) then //调用原窗口的窗口过程

Result := CallWindowProc(FPrevWndProc, FParentWindow.Handle,

Msg, WParam, LParam)

else

Result := CallWindowProc(THack(FParentWindow).DefWndProc,

FParentWindow.Handle, Msg, WParam, LParam);

if Msg = WM_DESTROY then //窗口正被销毁

UnHookParentForm; //还原父窗口的窗口过程

end;

end;

end; //end of procedure HookWndProc

procedure TEoCSysTray.DoTaskBarCreated;

begin

…… //在这里重新添加通知栏图标

if Assigned(FTaskBarCreated) then

FTaskBarCreated(Self);

end; //end of procedure DoTaskBarCreated

initialization

//注册询问任务栏重建的消息

MsgTaskbarCreated := RegisterWindowMessage('TaskbarCreated');

end.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有