| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687 |
- {******************************************************************************}
- { CnPack For Delphi/C++Builder }
- { 中国人自己的开放源码第三方开发包 }
- { (C)Copyright 2001-2018 CnPack 开发组 }
- { ------------------------------------ }
- { }
- { 本开发包是开源的自由软件,您可以遵照 CnPack 的发布协议来修 }
- { 改和重新发布这一程序。 }
- { }
- { 发布这一开发包的目的是希望它有用,但没有任何担保。甚至没有 }
- { 适合特定目的而隐含的担保。更详细的情况请参阅 CnPack 发布协议。 }
- { }
- { 您应该已经和开发包一起收到一份 CnPack 发布协议的副本。如果 }
- { 还没有,可访问我们的网站: }
- { }
- { 网站地址:http://www.cnpack.org }
- { 电子邮件:master@cnpack.org }
- { }
- {******************************************************************************}
- unit CnTrayIcon;
- {* |<PRE>
- ================================================================================
- * 软件名称:不可视工具组件包
- * 单元名称:TCnTrayIcon 单元
- * 单元作者:刘啸 liuxiao@cnpack.org; http://www.cnpack.org
- * 备 注:在 Explorer 非法结束重启后能自动恢复图标的系统托盘组件单元
- * 开发平台:PWin98SE + Delphi 5.0
- * 兼容测试:PWin9X/2000/XP + Delphi 5/6
- * 本 地 化:该单元中的字符串均符合本地化处理方式
- * 单元标识:$Id$
- * 修改记录:2012.06.21 V1.3
- * 恢复显示时加入一句BringToFront
- * 2005.02.05 V1.2
- * 修正显示气泡提示后弹出菜单和提示失效的问题
- * 2004.03.07 V1.1
- * 加入显示气泡提示和最小化时自动隐藏主窗口的功能
- * 2004.03.05 V1.0
- * 创建单元
- ================================================================================
- |</PRE>}
- interface
- {$I CnPack.inc}
- uses
- SysUtils, Classes, Messages, Windows, Forms, Menus, Controls,
- Graphics, ShellAPI, CnClasses, CnConsts, CnCompConsts;
- type
- EBalloonHintError = class(Exception);
- TMouseButtons = set of TMouseButton;
- TBalloonType = (btNone, btError, btInfo, btWarning);
- TNotifyIconDataXP = record
- cbSize: DWORD;
- Wnd: HWND;
- uID: UINT;
- uFlags: UINT;
- uCallbackMessage: UINT;
- hIcon: HICON;
- szTip: array [0..127] of AnsiChar;
- dwState: DWORD;
- dwStateMask: DWORD;
- szInfo: array [0..255] of AnsiChar;
- uTimeOut: DWORD;
- szInfoTitle: array [0..63] of AnsiChar;
- dwInfoFlags: DWORD;
- end;
- TCnTrayIcon = class(TCnComponent)
- private
- FHandle: HWND;
- FAcceptBalloons: Boolean;
- FActive: Boolean;
- FAdded: Boolean;
- FEnabled: Boolean;
- FClicked: TMouseButtons;
- FIconData: TNotifyIconData;
- FIconXP: TNotifyIconDataXP;
- FIcon: TIcon;
- FHint: string;
- FShowDesign: Boolean;
- FPopupMenu: TPopupMenu;
- FOnClick: TMouseEvent;
- FOnDblClick: TNotifyEvent;
- FOnMouseMove: TMouseMoveEvent;
- FOnMouseDown: TMouseEvent;
- FOnMouseUp: TMouseEvent;
- FOnBalloonShow: TNotifyEvent;
- FUseAppIcon: Boolean;
- FHooked: Boolean;
- FAutoHide: Boolean;
- FSaveWindowState: TWindowState;
- procedure ChangeIcon;
- procedure SendCancelMode;
- function CheckMenuPopup(X: Integer; Y: Integer): Boolean;
- function CheckDefaultMenuItem: Boolean;
- procedure SetHint(const Value: string);
- procedure SetIcon(Value: TIcon);
- procedure SetPopupMenu(Value: TPopupMenu);
- procedure Activate;
- procedure Deactivate;
- procedure HookApp;
- procedure UnHookApp;
- procedure SetActive(Value: Boolean);
- procedure SetShowDesign(Value: Boolean);
- procedure IconChanged(Sender: TObject);
- procedure WndProc(var Message: TMessage);
- procedure SetUseAppIcon(const Value: Boolean);
- function ApplicationHook(var Msg: TMessage): Boolean;
- protected
- procedure DblClick; dynamic;
- procedure DoClick(Button: TMouseButton; Shift: TShiftState; X: Integer; Y: Integer); dynamic;
- procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X: Integer; Y: Integer); dynamic;
- procedure MouseMove(Shift: TShiftState; X: Integer; Y: Integer); dynamic;
- procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X: Integer; Y: Integer); dynamic;
- procedure Loaded; override;
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- procedure UpdateNotifyData; virtual;
- procedure GetComponentInfo(var AName, Author, Email, Comment: string); override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure HideIcon;
- procedure ShowIcon;
- procedure HideApplication;
- procedure ShowApplication;
- procedure BalloonHint(const Title, Value: string; BalloonType: TBalloonType = btNone;
- DelaySeconds: Integer = 5);
- property Handle: HWND read FHandle;
- published
- property Active: Boolean read FActive write SetActive default True;
- property AutoHide: Boolean read FAutoHide write FAutoHide;
- property Enabled: Boolean read FEnabled write FEnabled default True;
- property Hint: string read FHint write SetHint;
- property Icon: TIcon read FIcon write SetIcon;
- property PopupMenu: TPopupMenu read FPopupMenu write SetPopupMenu;
- property ShowDesign: Boolean read FShowDesign write SetShowDesign stored False;
- property UseAppIcon: Boolean read FUseAppIcon write SetUseAppIcon;
- property OnClick: TMouseEvent read FOnClick write FOnClick;
- property OnDblClick: TNotifyEvent read FOnDblClick write FOnDblClick;
- property OnMouseMove: TMouseMoveEvent read FOnMouseMove write FOnMouseMove;
- property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;
- property OnMouseUp: TMouseEvent read FOnMouseUp write FOnMouseUp;
- property OnBalloonShow: TNotifyEvent read FOnBalloonShow write FOnBalloonShow;
- end;
- implementation
- uses
- CnCommon;
- const
- SCnCreateTaskBar: string = 'TaskbarCreated';
- SCnTrayIcon: string = 'CnTrayIcon';
- NIF_STATE = $00000008;
- NIF_INFO = $00000010;
- NIIF_NONE = $00000000;
- NIIF_INFO = $00000001;
- NIIF_WARNING = $00000002;
- NIIF_ERROR = $00000003;
- NIN_BALLOONSHOW = WM_USER + 2;
- NIN_BALLOONHIDE = WM_USER + 3;
- NIN_BALLOONTIMEOUT = WM_USER + 4;
- NIN_BALLOONUSERCLICK = WM_USER + 5;
- var
- WM_CNCREATETASKBAR: Cardinal;
- WM_CNTRAYICONCALLBACK: Cardinal;
- procedure SwitchToWindow(Wnd: HWnd; Restore: Boolean);
- begin
- if IsWindowEnabled(Wnd) then
- begin
- SetForegroundWindow(Wnd);
- if Restore and IsWindowVisible(Wnd) then
- begin
- if not IsZoomed(Wnd) then
- SendMessage(Wnd, WM_SYSCOMMAND, SC_RESTORE, 0);
- SetFocus(Wnd);
- end;
- end;
- end;
- { TCnTrayIcon }
- procedure TCnTrayIcon.Activate;
- var
- S: string;
- begin
- Deactivate;
- if FIcon.Handle <> 0 then
- begin
- FClicked := [];
- UpdateNotifyData;
- FAdded := Shell_NotifyIconA(NIM_ADD, @FIconData);
- S := GetShortHint(FHint);
- if FAdded and (S <> '') then
- Shell_NotifyIconA(NIM_MODIFY, @FIconData);
- end;
- end;
- procedure TCnTrayIcon.BalloonHint(const Title, Value: string;
- BalloonType: TBalloonType; DelaySeconds: Integer);
- begin
- if FAcceptBalloons then
- begin
- FIconXP.cbSize := SizeOf(FIconXP);
- FIconXP.Wnd := FHandle;
- FIconXP.hIcon := FIcon.Handle;
- StrPLCopy(FIconXP.szInfoTitle, {$IFDEF UNICODE}AnsiString{$ENDIF}(Title), SizeOf(FIconXP.szInfoTitle) - 1);
- StrPLCopy(FIconXP.szInfo, {$IFDEF UNICODE}AnsiString{$ENDIF}(Value), SizeOf(FIconXP.szInfo) - 1);
- FIconXP.uFlags := NIF_ICON or NIF_INFO; // 此处如加其他标志会导致其他标志失效
- FIconXP.uTimeOut := DelaySeconds;
- case BalloonType of
- btError:
- FIconXP.dwInfoFlags := NIIF_ERROR;
- btInfo:
- FIconXP.dwInfoFlags := NIIF_INFO;
- btNone:
- FIconXP.dwInfoFlags := NIIF_NONE;
- btWarning:
- FIconXP.dwInfoFlags := NIIF_WARNING;
- end;
- Shell_NotifyIconA(NIM_MODIFY, @FIconXP);
- if Assigned(FOnBalloonShow) then
- FOnBalloonShow(Self);
- end
- else
- raise EBalloonHintError.Create('Balloon Hint not Supported.');
- end;
- procedure TCnTrayIcon.ChangeIcon;
- begin
- if FAdded then
- begin
- if FIcon.Handle <> 0 then
- begin
- UpdateNotifyData;
- Shell_NotifyIconA(NIM_MODIFY, @FIconData);
- end
- else
- Deactivate;
- Exit;
- end;
- if (csDesigning in ComponentState) and FShowDesign or
- (not (csDesigning in ComponentState) and FActive) then
- Activate;
- end;
- function TCnTrayIcon.CheckDefaultMenuItem: Boolean;
- var
- Item: TMenuItem;
- I: Integer;
- begin
- Result := False;
- if not (csDesigning in ComponentState) then
- if FActive and (FPopupMenu <> nil) then
- if FPopupMenu.Items <> nil then
- begin
- for I := 0 to FPopupMenu.Items.Count - 1 do
- begin
- Item := FPopupMenu.Items[I];
- if Item.Default and Item.Enabled then
- begin
- Item.Click;
- Result := True;
- Break;
- end;
- end;
- end;
- end;
- function TCnTrayIcon.CheckMenuPopup(X, Y: Integer): Boolean;
- begin
- Result := False;
- if not (csDesigning in ComponentState) then
- begin
- if FActive and (FPopupMenu <> nil) then
- begin
- if FPopupMenu.AutoPopup then
- begin
- FPopupMenu.PopupComponent := Self;
- SendCancelMode;
- SwitchToWindow(FHandle, False);
- Application.ProcessMessages;
- try
- FPopupMenu.Popup(X, Y);
- finally
- SwitchToWindow(FHandle, False);
- end;
- Result := True;
- end;
- end;
- end;
- end;
- constructor TCnTrayIcon.Create(AOwner: TComponent);
- var
- H: THandle;
- F: array[0..255] of Char;
- begin
- inherited;
- FHandle := AllocateHwnd(WndProc);
- FIcon := TIcon.Create;
- FIcon.OnChange := IconChanged;
- FActive := True;
- FEnabled := True;
- HookApp;
- H := LoadLibrary('Shell32.DLL');
- if (H <> 0) and (0 <> GetModuleFileName(H, F, SizeOf(F))) then
- FAcceptBalloons := GetFileVersionNumber(F).Major >= 5;
- end;
- procedure TCnTrayIcon.DblClick;
- begin
- if not CheckDefaultMenuItem and Assigned(FOnDblClick) then
- FOnDblClick(Self);
- end;
- procedure TCnTrayIcon.Deactivate;
- begin
- Shell_NotifyIconA(NIM_DELETE, @FIconData);
- FAdded := False;
- FClicked := [];
- end;
- destructor TCnTrayIcon.Destroy;
- begin
- Destroying;
- UnHookApp;
- FEnabled := False;
- FIcon.OnChange := nil;
- Deactivate;
- DeallocateHWnd(FHandle);
- FreeAndNil(FIcon);
- inherited;
- end;
- procedure TCnTrayIcon.DoClick(Button: TMouseButton; Shift: TShiftState; X,
- Y: Integer);
- begin
- if (Button <> mbRight) or not CheckMenuPopup(X, Y) then
- if Assigned(FOnClick) then
- FOnClick(Self, Button, Shift, X, Y);
- end;
- procedure TCnTrayIcon.HideIcon;
- begin
- Active := False;
- end;
- procedure TCnTrayIcon.HideApplication;
- begin
- if (Application.MainForm <> nil) and (Application.MainForm.WindowState <> wsMinimized) then
- begin
- FSaveWindowState := Application.MainForm.WindowState;
- Application.Minimize;
- Application.MainForm.Hide;
- end;
- ShowWindow(Application.Handle, SW_HIDE);
- end;
- procedure TCnTrayIcon.IconChanged(Sender: TObject);
- begin
- ChangeIcon;
- end;
- procedure TCnTrayIcon.Loaded;
- begin
- inherited;
- if FActive and not (csDesigning in ComponentState) then
- Activate;
- end;
- procedure TCnTrayIcon.MouseDown(Button: TMouseButton; Shift: TShiftState;
- X, Y: Integer);
- begin
- if Assigned(FOnMouseDown) then
- FOnMouseDown(Self, Button, Shift, X, Y);
- end;
- procedure TCnTrayIcon.MouseMove(Shift: TShiftState; X, Y: Integer);
- begin
- if Assigned(FOnMouseMove) then
- FOnMouseMove(Self, Shift, X, Y);
- end;
- procedure TCnTrayIcon.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
- Y: Integer);
- begin
- if Assigned(FOnMouseUp) then
- FOnMouseUp(Self, Button, Shift, X, Y);
- end;
- procedure TCnTrayIcon.Notification(AComponent: TComponent;
- Operation: TOperation);
- begin
- inherited;
- if (AComponent = FPopupMenu) and (Operation = opRemove) then
- PopupMenu := nil;
- end;
- procedure TCnTrayIcon.SendCancelMode;
- begin
- if not (csDestroying in ComponentState) then
- if Screen.ActiveCustomForm <> nil then
- if Application.MainForm <> nil then
- Application.MainForm.SendCancelMode(nil);
- end;
- procedure TCnTrayIcon.SetActive(Value: Boolean);
- begin
- if Value <> FActive then
- begin
- FActive := Value;
- if not (csDesigning in ComponentState) then
- begin
- if Value then
- Activate
- else
- Deactivate;
- end;
- end;
- end;
- procedure TCnTrayIcon.SetHint(const Value: string);
- begin
- if Value <> FHint then
- begin
- FHint := Value;
- ChangeIcon;
- end;
- end;
- procedure TCnTrayIcon.SetIcon(Value: TIcon);
- begin
- FIcon.Assign(Value);
- end;
- procedure TCnTrayIcon.SetPopupMenu(Value: TPopupMenu);
- begin
- FPopupMenu := Value;
- if Value <> nil then
- Value.FreeNotification(Self);
- end;
- procedure TCnTrayIcon.SetShowDesign(Value: Boolean);
- begin
- if csDesigning in ComponentState then
- begin
- if Value then
- Activate
- else
- Deactivate;
- FShowDesign := FAdded;
- end;
- end;
- procedure TCnTrayIcon.SetUseAppIcon(const Value: Boolean);
- begin
- FUseAppIcon := Value;
- if Value and (FIcon <> nil) then
- FIcon.Assign(Application.Icon);
- end;
- procedure TCnTrayIcon.ShowIcon;
- begin
- Active := True;
- end;
- procedure TCnTrayIcon.ShowApplication;
- begin
- ShowWindow(Application.Handle, SW_SHOW);
- Application.Restore;
- if Application.MainForm <> nil then
- begin
- if FSaveWindowState <> wsMinimized then
- Application.MainForm.WindowState := FSaveWindowState
- else
- Application.MainForm.WindowState := wsNormal;
- Application.BringToFront;
- Application.MainForm.Show;
- end;
- end;
- procedure TCnTrayIcon.UpdateNotifyData;
- var
- ShortHint: AnsiString;
- begin
- FIconData.cbSize := SizeOf(TNotifyIconData);
- FIconData.Wnd := FHandle;
- FIconData.uFlags := NIF_ICON or NIF_MESSAGE or NIF_TIP or NIF_INFO;
- FIconData.hIcon := FIcon.Handle;
- ShortHint := {$IFDEF UNICODE}AnsiString{$ENDIF}(GetShortHint(FHint));
- {$IFDEF UNICODE}
- if ShortHint <> '' then
- CopyMemory(@FIconData.szTip, Pointer(ShortHint), 63)
- else
- FIconData.szTip[0] := #0;
- {$ELSE}
- StrPLCopy(FIconData.szTip, ShortHint, 63);
- {$ENDIF}
- FIconData.uCallbackMessage := WM_CNTRAYICONCALLBACK;
- FIconData.uID := 0;
- end;
- procedure TCnTrayIcon.WndProc(var Message: TMessage);
- function GetShiftState: TShiftState;
- begin
- Result := [];
- if GetKeyState(VK_SHIFT) < 0 then
- Include(Result, ssShift);
- if GetKeyState(VK_CONTROL) < 0 then
- Include(Result, ssCtrl);
- if GetKeyState(VK_MENU) < 0 then
- Include(Result, ssAlt);
- end;
- var
- P: TPoint;
- Shift: TShiftState;
- begin
- try
- if Message.Msg = WM_CNTRAYICONCALLBACK then
- begin
- if FEnabled then
- begin
- Shift := GetShiftState;
- case Message.lParam of
- WM_LBUTTONDBLCLK:
- begin
- DblClick;
- GetCursorPos(P);
- MouseDown(mbLeft, Shift, P.x, P.y);
- end;
- WM_RBUTTONDBLCLK:
- begin
- DblClick;
- GetCursorPos(P);
- MouseDown(mbRight, Shift, P.x, P.y);
- end;
- WM_MBUTTONDBLCLK:
- begin
- DblClick;
- GetCursorPos(P);
- MouseDown(mbMiddle, Shift, P.x, P.y);
- end;
- WM_MOUSEMOVE:
- begin
- GetCursorPos(P);
- MouseMove(Shift, P.X, P.Y);
- end;
- WM_LBUTTONDOWN:
- begin
- GetCursorPos(P);
- MouseDown(mbLeft, Shift, P.X, P.Y);
- Include(FClicked, mbLeft);
- end;
- WM_LBUTTONUP:
- begin
- GetCursorPos(P);
- if mbLeft in FClicked then
- begin
- Exclude(FClicked, mbLeft);
- DoClick(mbLeft, Shift, P.x, P.y);
- end;
- MouseUp(mbLeft, Shift, P.x, P.y);
- end;
- WM_RBUTTONDOWN:
- begin
- GetCursorPos(P);
- MouseDown(mbRight, Shift, P.x, P.y);
- Include(FClicked, mbRight);
- end;
- WM_RBUTTONUP:
- begin
- GetCursorPos(P);
- if mbRight in FClicked then
- begin
- Exclude(FClicked, mbRight);
- DoClick(mbRight, Shift, P.x, P.y);
- end;
- MouseUp(mbRight, Shift, P.X, P.Y);
- end;
- WM_MBUTTONDOWN:
- begin
- GetCursorPos(P);
- MouseDown(mbMiddle, Shift, P.X, P.Y);
- Include(FClicked, mbMiddle);
- end;
- WM_MBUTTONUP:
- begin
- GetCursorPos(P);
- if mbMiddle in FClicked then
- begin
- Exclude(FClicked, mbMiddle);
- DoClick(mbMiddle, Shift, P.x, P.y);
- end;
- MouseUp(mbMiddle, Shift, P.X, P.Y);
- end;
- NIN_BALLOONSHOW:
- begin
- end;
- NIN_BALLOONHIDE:
- begin
- end;
- NIN_BALLOONTIMEOUT:
- begin
- end;
- NIN_BALLOONUSERCLICK:
- begin
- end;
- end; // end of case
- end;
- end
- else if Message.Msg = WM_CNCREATETASKBAR then
- begin
- if not (csDesigning in ComponentState) and FActive then
- Activate;
- end
- else with Message do
- Result := DefWindowProc(FHandle, Msg, wParam, lParam);
- except
- Application.HandleException(Self);
- end;
- end;
- procedure TCnTrayIcon.HookApp;
- begin
- if FHooked then
- Exit;
- Application.HookMainWindow(ApplicationHook);
- FHooked := True;
- end;
- procedure TCnTrayIcon.UnHookApp;
- begin
- if not FHooked then
- Exit;
- Application.UnhookMainWindow(ApplicationHook);
- FHooked := False;
- end;
- function TCnTrayIcon.ApplicationHook(var Msg: TMessage): Boolean;
- begin
- if (Msg.Msg = WM_SYSCOMMAND) and (Msg.WParam = SC_MINIMIZE) and
- FAutoHide and FActive then
- if not (csDesigning in ComponentState) then
- HideApplication;
- Result := False;
- end;
- procedure TCnTrayIcon.GetComponentInfo(var AName, Author, Email,
- Comment: string);
- begin
- AName := SCnTrayIconName;
- Author := SCnPack_LiuXiao;
- Email := SCnPack_LiuXiaoEmail;
- Comment := SCnTrayIconComment;
- end;
- initialization
- WM_CNCREATETASKBAR := RegisterWindowMessage(PChar(SCnCreateTaskBar));
- WM_CNTRAYICONCALLBACK := RegisterWindowMessage(PChar(SCnTrayIcon));
- end.
|