给你个控件的源代码,自己看吧!<br>{<br>This is a component for placing icons in the notification area<br>of the Windows taskbar (aka. the traybar).<br><br>The component is freeware. Feel free to use and improve it.<br>I would be pleased to hear what you think.<br><br>Troels Jakobsen - tjak@get2net.dk<br>}<br>unit CoolTrayIcon;<br><br>interface<br><br>uses<br> Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,<br> Menus, ShellApi, extctrls;<br><br>const<br> { User-defined message sent from the icon. Some low user-defined<br> messages are used by Windows itself! (WM_USER+1 = DM_SETDEFID). }<br> WM_TRAYNOTIFY = WM_USER + 1024;<br> IconID = 1;<br><br>type<br> TCycleEvent = procedure(Sender: TObject; Current: Integer) of object;<br> TMainFormMinimizeEvent = procedure(Sender: TObject; var GotoTray: Boolean) of object;<br><br> TCoolTrayIcon = class(TComponent)<br> private<br> FEnabled: Boolean;<br> FIcon: TIcon;<br> FIconVisible: Boolean;<br> FHint: String;<br> FShowHint: Boolean;<br> FPopupMenu: TPopupMenu;<br> FLeftPopup: Boolean;<br> FOnClick,<br> FOnDblClick: TNotifyEvent;<br> FOnCycle: TCycleEvent;<br> FOnMouseDown,<br> FOnMouseUp: TMouseEvent;<br> FOnMouseMove: TMouseMoveEvent;<br> FStartMinimized: Boolean;<br> FMinimizeToTray: Boolean;<br> HasShown: Boolean;<br> FClicked: Boolean;<br> CycleTimer: TTimer; // For icon cycling<br> FDesignPreview: Boolean;<br> SettingPreview: Boolean;<br> FIconList: TImageList;<br> FCycleIcons: Boolean;<br> FCycleInterval: Cardinal;<br> IconIndex: Integer; // Current index in imagelist<br> OldAppProc, NewAppProc: Pointer; // Procedure variables<br> procedure SetCycleIcons(Value: Boolean);<br> procedure SetDesignPreview(Value: Boolean);<br> procedure SetCycleInterval(Value: Cardinal);<br> procedure TimerCycle(Sender: TObject);<br> procedure HandleIconMessage(var Msg: TMessage);<br> function InitIcon: Boolean;<br> procedure SetIcon(Value: TIcon);<br> procedure SetIconVisible(Value: Boolean);<br> procedure SetHint(Value: String);<br> procedure SetShowHint(Value: Boolean);<br> procedure PopupAtCursor;<br> procedure HookApp;<br> procedure UnhookApp;<br> procedure HookAppProc(var Message: TMessage);<br> protected<br> IconData: TNotifyIconData; // Data of the tray icon wnd.<br> procedure Loaded; override;<br> function ShowIcon: Boolean; virtual;<br> function HideIcon: Boolean; virtual;<br> function ModifyIcon: Boolean; virtual;<br> procedure Click; dynamic;<br> procedure DblClick; dynamic;<br> procedure CycleIcon; dynamic;<br> procedure MouseDown(Button: TMouseButton; Shift: TShiftState;<br> X, Y: Integer); dynamic;<br> procedure MouseUp(Button: TMouseButton; Shift: TShiftState;<br> X, Y: Integer); dynamic;<br> procedure MouseMove(Shift: TShiftState; X, Y: Integer); dynamic;<br> procedure DoMinimizeToTray; dynamic;<br> procedure Notification(AComponent: TComponent; Operation: TOperation);<br> override;<br> public<br> property Handle: HWND read IconData.wnd;<br> constructor Create(AOwner: TComponent); override;<br> destructor Destroy; override;<br> procedure ShowMainForm;<br> procedure HideMainForm;<br> procedure Refresh;<br> published<br> // Properties:<br> property DesignPreview: Boolean read FDesignPreview<br> write SetDesignPreview default False;<br> property IconList: TImageList read FIconList write FIconList;<br> property CycleIcons: Boolean read FCycleIcons write SetCycleIcons<br> default False;<br> property CycleInterval: Cardinal read FCycleInterval<br> write SetCycleInterval;<br> property Enabled: Boolean read FEnabled write FEnabled default True;<br> property Hint: String read FHint write SetHint;<br> property ShowHint: Boolean read FShowHint write SetShowHint;<br> property Icon: TIcon read FIcon write SetIcon stored True;<br> property IconVisible: Boolean read FIconVisible write SetIconVisible<br> default True;<br> property PopupMenu: TPopupMenu read FPopupMenu write FPopupMenu;<br> property LeftPopup: Boolean read FLeftPopup write FLeftPopup<br> default False;<br> property StartMinimized: Boolean read FStartMinimized write FStartMinimized<br> default False; // Main form minimized on appl. start-up?<br> property MinimizeToTray: Boolean read FMinimizeToTray write FMinimizeToTray<br> default False; // Minimize main form to tray when minimizing?<br> // Events:<br> property OnClick: TNotifyEvent read FOnClick write FOnClick;<br> property OnDblClick: TNotifyEvent read FOnDblClick write FOnDblClick;<br> property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;<br> property OnMouseUp: TMouseEvent read FOnMouseUp write FOnMouseUp;<br> property OnMouseMove: TMouseMoveEvent read FOnMouseMove write FOnMouseMove;<br> property OnCycle: TCycleEvent read FOnCycle write FOnCycle;<br> end;<br><br>procedure Register;<br><br>implementation<br><br>{--------------------- TCoolTrayIcon ----------------------}<br><br>constructor TCoolTrayIcon.Create(AOwner: TComponent);<br>begin<br> inherited Create(AOwner);<br> FIconVisible := True; // Visible by default<br> FEnabled := True; // Enabled by default<br> HasShown := False; // The main form has not been shown before<br> SettingPreview := False;<br><br> FIcon := TIcon.Create;<br> IconData.cbSize := SizeOf(TNotifyIconData);<br> // IconData.wnd points to procedure to receive callback messages from the icon<br> IconData.wnd := Classes.AllocateHWnd(HandleIconMessage);<br> // Add an id for the tray icon<br> IconData.uId := IconID;<br> // We want icon, message handling, and tooltips<br> IconData.uFlags := NIF_ICON + NIF_MESSAGE + NIF_TIP;<br> // Message to send to IconData.wnd when mouse event occurs<br> IconData.uCallbackMessage := WM_TRAYNOTIFY;<br><br> CycleTimer := TTimer.Create(Self);<br> CycleTimer.Enabled := False;<br> CycleTimer.Interval := FCycleInterval;<br> CycleTimer.OnTimer := TimerCycle;<br><br> if not (csDesigning in ComponentState) then<br> HookApp;<br>end;<br><br><br>destructor TCoolTrayIcon.Destroy;<br>begin<br> SetIconVisible(False); // Remove the icon from the tray<br> FIcon.Free; // Free the icon<br> Classes.DeallocateHWnd(IconData.Wnd); // Free the tray window<br> CycleTimer.Free;<br> // It is important to unhook any hooked processes<br> if not (csDesigning in ComponentState) then<br> UnhookApp;<br> inherited Destroy;<br>end;<br><br><br>procedure TCoolTrayIcon.Loaded;<br>{ This method is called when all properties of the component have been<br> initialized. The method SetIconVisible must be called here, after the<br> tray icon (FIcon) has loaded itself. Otherwise, the tray icon will<br> be blank (no icon image). }<br>begin<br> inherited Loaded; // Always call inherited Loaded first<br> SetIconVisible(FIconVisible);<br> if (StartMinimized) and not (csDesigning in ComponentState) then<br> begin<br> Application.ShowMainForm := False;<br> ShowWindow(Application.Handle, SW_HIDE);<br> end;<br> ModifyIcon;<br>end;<br><br><br>procedure TCoolTrayIcon.Notification(AComponent: TComponent;<br> Operation: TOperation);<br>begin<br> inherited Notification(AComponent, Operation);<br> { Check if either the imagelist or the popup menu<br> is about to be deleted }<br> if (AComponent = IconList) and (Operation = opRemove) then<br> IconList := nil;<br> if (AComponent = PopupMenu) and (Operation = opRemove) then<br> PopupMenu := nil;<br>end;<br><br><br>{ For MinimizeToTray to work, we need to know when the form is minimized<br> (happens when either the application or the main form minimizes).<br> The straight-forward way is to make TCoolTrayIcon trap the<br> Application.OnMinimize event. However, if you also make use of this<br> event in the application, the OnMinimize code used by TCoolTrayIcon<br> is discarded.<br> The alternative is to hook into the app.'s message handling (via<br> HookApp). You can then catch any message that goes through the app.<br> and still use the OnMinimize event. }<br><br>procedure TCoolTrayIcon.HookApp;<br>begin<br> // Hook the application<br> OldAppProc := Pointer(GetWindowLong(Application.Handle, GWL_WNDPROC));<br> NewAppProc := Classes.MakeObjectInstance(HookAppProc);<br> SetWindowLong(Application.Handle, GWL_WNDPROC, LongInt(NewAppProc));<br>end;<br><br><br>procedure TCoolTrayIcon.UnhookApp;<br>begin<br> if Assigned(OldAppProc) then<br> SetWindowLong(Application.Handle, GWL_WNDPROC, LongInt(OldAppProc));<br> if Assigned(NewAppProc) then<br> Classes.FreeObjectInstance(NewAppProc);<br> NewAppProc := nil;<br> OldAppProc := nil;<br>end;<br><br><br>{ All app. messages pass through HookAppProc. You can override the<br> messages by not passing them along to Windows (via CallWindowProc). }<br><br>procedure TCoolTrayIcon.HookAppProc(var Message: TMessage);<br>begin<br> with Message do<br> begin<br> case Msg of<br> WM_SIZE:<br> if wParam = SIZE_MINIMIZED then<br> begin<br> if FMinimizeToTray then<br> DoMinimizeToTray;<br>{ It is tempting to insert a minimize event here, but it would behave<br> exactly like Application.OnMinimize, so I see no need for it. }<br> end;<br> end;<br><br> Result := CallWindowProc(OldAppProc, Application.Handle, Msg, wParam, lParam);<br> end;<br>end;<br><br><br>{ You can hook into the main form (or any other window) just as easily<br> as hooking into the app., allowing you to handle any message that<br> window processes. Uncomment the procedures HookParent and UnhookParent<br> below if you want to hook the main form. Remember to unhook when the<br> app. terminates, or Bad Things may happen. }<br>{<br>procedure TCoolTrayIcon.HookParent;<br>begin<br> if Assigned(Owner as TWinControl) then<br> begin<br> // Hook the parent window<br> OldWndProc := Pointer(GetWindowLong((Owner as TWinControl).Handle, GWL_WNDPROC));<br> NewWndProc := MakeObjectInstance(HookWndProc);<br> SetWindowLong((Owner as TWinControl).Handle, GWL_WNDPROC, LongInt(NewWndProc));<br> end;<br>end;<br><br><br>procedure TCoolTrayIcon.UnhookParent;<br>begin<br> if ((Owner as TWinControl) <> nil) and Assigned(OldWndProc) then<br> SetWindowLong((Owner as TWinControl).Handle, GWL_WNDPROC, LongInt(OldWndProc));<br> if Assigned(NewWndProc) then<br> FreeObjectInstance(NewWndProc);<br> NewWndProc := nil;<br> OldWndProc := nil;<br>end;<br>}<br><br><br>{ HandleIconMessage handles messages that go to the shell notification<br> window (tray icon) itself. Most messages are passed through WM_TRAYNOTIFY.<br> Use lParam to get the actual message, eg. WM_MOUSEMOVE.<br> Sends the usual Delphi events for the mouse messages. Also interpolates<br> the OnClick event when the user clicks the left button, and makes the<br> menu (if any) popup on left and right mouse down events. }<br><br>procedure TCoolTrayIcon.HandleIconMessage(var Msg: TMessage);<br><br> function ShiftState: TShiftState;<br> // Return the state of the shift, ctrl, and alt keys<br> begin<br> Result := [];<br> if GetKeyState(VK_SHIFT) < 0 then<br> Include(Result, ssShift);<br> if GetKeyState(VK_CONTROL) < 0 then<br> Include(Result, ssCtrl);<br> if GetKeyState(VK_MENU) < 0 then<br> Include(Result, ssAlt);<br> end;<br><br>var<br> Pt: TPoint;<br> Shift: TShiftState;<br> I: Integer;<br> M: TMenuItem;<br>begin<br> if Msg.Msg = WM_TRAYNOTIFY then<br> // Take action if a message from the icon comes through<br> begin<br> case Msg.lParam of<br><br> WM_MOUSEMOVE:<br> if FEnabled then<br> begin<br> Shift := ShiftState;<br> GetCursorPos(Pt);<br> MouseMove(Shift, Pt.X, Pt.Y);<br> end;<br><br> WM_LBUTTONDOWN:<br> if FEnabled then<br> begin<br> Shift := ShiftState + [ssLeft];<br> GetCursorPos(Pt);<br> MouseDown(mbLeft, Shift, Pt.X, Pt.Y);<br> FClicked := True;<br> if FLeftPopup then<br> PopupAtCursor;<br> end;<br><br> WM_RBUTTONDOWN:<br> if FEnabled then<br> begin<br> Shift := ShiftState + [ssRight];<br> GetCursorPos(Pt);<br> MouseDown(mbRight, Shift, Pt.X, Pt.Y);<br> PopupAtCursor;<br> end;<br><br> WM_MBUTTONDOWN:<br> if FEnabled then<br> begin<br> Shift := ShiftState + [ssMiddle];<br> GetCursorPos(Pt);<br> MouseDown(mbMiddle, Shift, Pt.X, Pt.Y);<br> end;<br><br> WM_LBUTTONUP:<br> if FEnabled then<br> begin<br> Shift := ShiftState + [ssLeft];<br> GetCursorPos(Pt);<br> if FClicked then // Then WM_LBUTTONDOWN was called before<br> begin<br> FClicked := False;<br> Click;<br> end;<br> MouseUp(mbLeft, Shift, Pt.X, Pt.Y);<br> end;<br><br> WM_RBUTTONUP:<br> if FEnabled then<br> begin<br> Shift := ShiftState + [ssRight];<br> GetCursorPos(Pt);<br> MouseUp(mbRight, Shift, Pt.X, Pt.Y);<br> end;<br><br> WM_MBUTTONUP:<br> if FEnabled then<br> begin<br> Shift := ShiftState + [ssMiddle];<br> GetCursorPos(Pt);<br> MouseUp(mbMiddle, Shift, Pt.X, Pt.Y);<br> end;<br><br> WM_LBUTTONDBLCLK:<br> if FEnabled then<br> begin<br> DblClick;<br> { Handle default menu items. But only if LeftPopup is false,<br> or it will conflict with the popupmenu, when it is called<br> by a click event. }<br> M := nil;<br> if Assigned(FPopupMenu) then<br> if (FPopupMenu.AutoPopup) and (not FLeftPopup) then<br> for I := PopupMenu.Items.Count -1 downto 0 do<br> begin<br> if PopupMenu.Items.Default then<br> M := PopupMenu.Items;<br> end;<br> if M <> nil then<br> M.Click;<br> end;<br> end;<br> end<br><br> else // Messages that didn't go through the icon<br> case Msg.Msg of<br> WM_QUERYENDSESSION: Msg.Result := 1;<br> { Evaluate WM_QUERYENDSESSION message to tell Windows that the<br> icon will stop executing if user requests a shutdown (Msg.Result<br> must not return 0, or the system will not be able to shut down). }<br> else // Handle all other messages with the default handler<br> Msg.Result := DefWindowProc(IconData.Wnd, Msg.Msg, Msg.wParam, Msg.lParam);<br> end;<br>end;<br><br><br>procedure TCoolTrayIcon.SetIcon(Value: TIcon);<br>begin<br> FIcon.Assign(Value);<br> ModifyIcon;<br>end;<br><br><br>procedure TCoolTrayIcon.SetIconVisible(Value: Boolean);<br>begin<br> if Value then<br> ShowIcon<br> else<br> HideIcon;<br>end;<br><br><br>procedure TCoolTrayIcon.SetDesignPreview(Value: Boolean);<br>begin<br> FDesignPreview := Value;<br> SettingPreview := True; // Raise flag<br> SetIconVisible(Value);<br> SettingPreview := False; // Clear flag<br>end;<br><br><br>procedure TCoolTrayIcon.SetCycleIcons(Value: Boolean);<br>begin<br> FCycleIcons := Value;<br> if Value then<br> IconIndex := 0;<br> CycleTimer.Enabled := Value;<br>end;<br><br><br>procedure TCoolTrayIcon.SetCycleInterval(Value: Cardinal);<br>begin<br> FCycleInterval := Value;<br> CycleTimer.Interval := FCycleInterval;<br>end;<br><br><br>procedure TCoolTrayIcon.SetHint(Value: String);<br>begin<br> FHint := Value;<br> ModifyIcon;<br>end;<br><br><br>procedure TCoolTrayIcon.SetShowHint(Value: Boolean);<br>begin<br> FShowHint := Value;<br> ModifyIcon;<br>end;<br><br><br>function TCoolTrayIcon.InitIcon: Boolean;<br>// Set icon and tooltip<br>var<br> ok: Boolean;<br>begin<br> Result := False;<br> ok := True;<br> if (csDesigning in ComponentState) {or<br> (csLoading in ComponentState)} then<br> begin<br> if SettingPreview then<br> ok := True<br> else<br> ok := FDesignPreview<br> end;<br><br> if ok then<br> begin<br> IconData.hIcon := FIcon.Handle;<br> if (FHint <> '') and (FShowHint) then<br> StrLCopy(IconData.szTip, PChar(FHint), SizeOf(IconData.szTip))<br> // StrLCopy must be used since szTip is only 64 bytes<br> else<br> IconData.szTip := '';<br> Result := True;<br> end;<br>end;<br><br><br>function TCoolTrayIcon.ShowIcon: Boolean;<br>// Add/show the icon on the tray<br>begin<br> Result := False;<br> if not SettingPreview then<br> FIconVisible := True;<br> begin<br> if (csDesigning in ComponentState) {or<br> (csLoading in ComponentState)} then<br> begin<br> if SettingPreview then<br> if InitIcon then<br> Result := Shell_NotifyIcon(NIM_ADD, @IconData);<br> end<br> else<br> if InitIcon then<br> Result := Shell_NotifyIcon(NIM_ADD, @IconData);<br> end;<br>end;<br><br><br>function TCoolTrayIcon.HideIcon: Boolean;<br>// Remove/hide the icon from the tray<br>begin<br> Result := False;<br> if not SettingPreview then<br> FIconVisible := False;<br> begin<br> if (csDesigning in ComponentState) {or<br> (csLoading in ComponentState)} then<br> begin<br> if SettingPreview then<br> if InitIcon then<br> Result := Shell_NotifyIcon(NIM_DELETE, @IconData);<br> end<br> else<br> if InitIcon then<br> Result := Shell_NotifyIcon(NIM_DELETE, @IconData);<br> end;<br>end;<br><br><br>function TCoolTrayIcon.ModifyIcon: Boolean;<br>// Change icon or tooltip if icon already placed<br>begin<br> Result := False;<br> if InitIcon then<br> Result := Shell_NotifyIcon(NIM_MODIFY, @IconData);<br>end;<br><br><br>procedure TCoolTrayIcon.TimerCycle(Sender: TObject);<br>begin<br> if Assigned(FIconList) then<br> begin<br> FIconList.GetIcon(IconIndex, FIcon);<br> CycleIcon; // Call event method<br> ModifyIcon;<br><br> if IconIndex < FIconList.Count-1 then<br> Inc(IconIndex)<br> else<br> IconIndex := 0;<br> end;<br>end;<br><br><br>procedure TCoolTrayIcon.ShowMainForm;<br>var<br> I, J: Integer;<br>begin<br> // Show application's TASKBAR icon (not the traybar icon)<br> ShowWindow(Application.Handle, SW_RESTORE);<br> // Show the form itself<br> ShowWindow(Application.MainForm.Handle, SW_RESTORE);<br>// Application.MainForm.BringToFront;<br><br> { If the main form has not been shown before (if StartMinimized<br> was true (Application.ShowMainForm was false on startup)),<br> it's necessary to force the form's controls to show, as they<br> have been created invisible (regardless of the value of their<br> Visible property). This is done via ShowWindow and a lot of<br> loops. }<br> { By the way: TForm.Position has no effect if StartMinimized<br> is true. Kind of stupid. }<br> if not HasShown then // This block is only executed once<br> begin<br> for I := 0 to Application.MainForm.ComponentCount -1 do<br> if Application.MainForm.Components is TWinControl then<br> with Application.MainForm.Components as TWinControl do<br> if Visible then<br> begin<br> // Show this control<br> ShowWindow(Handle, SW_SHOWDEFAULT);<br> // Now show child controls owned by this control<br> for J := 0 to ComponentCount -1 do<br> if Components[J] is TWinControl then<br> ShowWindow((Components[J] as TWinControl).Handle, SW_SHOWDEFAULT);<br> end;<br> HasShown := True; // The main form has now been shown<br> end;<br>end;<br><br><br>procedure TCoolTrayIcon.HideMainForm;<br>begin<br> // Hide application's TASKBAR icon (not the traybar icon)<br> ShowWindow(Application.Handle, SW_HIDE);<br> // Hide the form itself<br> ShowWindow(Application.MainForm.Handle, SW_HIDE);<br>end;<br><br><br>procedure TCoolTrayIcon.Refresh;<br>// Refresh the icon<br>begin<br> ModifyIcon;<br>end;<br><br><br>procedure TCoolTrayIcon.PopupAtCursor;<br>var<br> CursorPos: TPoint;<br>begin<br> if Assigned(PopupMenu) then<br> if PopupMenu.AutoPopup then<br> if GetCursorPos(CursorPos) then<br> begin<br> { Win98 (but not Win95/WinNT) seems to empty a popup menu before<br> closing it. This is a problem when the menu is about to display<br> while it already is active (two click-events following each<br> other). The menu will flicker annoyingly.<br> Calling ProcessMessages fixes this. }<br> Application.ProcessMessages;<br> SetForegroundWindow(Application.MainForm.Handle);<br> PopupMenu.PopupComponent := Self;<br> PopupMenu.Popup(CursorPos.X, CursorPos.Y);<br> PostMessage(Application.MainForm.Handle, WM_NULL, 0, 0);<br> end;<br>end;<br><br><br>procedure TCoolTrayIcon.Click;<br>begin<br> // Execute user-assigned method<br> if Assigned(FOnClick) then<br> FOnClick(Self);<br>end;<br><br><br>procedure TCoolTrayIcon.DblClick;<br>begin<br> // Execute user-assigned method<br> if Assigned(FOnDblClick) then<br> FOnDblClick(Self);<br>end;<br><br><br>procedure TCoolTrayIcon.MouseDown(Button: TMouseButton; Shift: TShiftState;<br> X, Y: Integer);<br>begin<br> // Execute user-assigned method<br> if Assigned(FOnMouseDown) then<br> FOnMouseDown(Self, Button, Shift, X, Y);<br>end;<br><br><br>procedure TCoolTrayIcon.MouseUp(Button: TMouseButton; Shift: TShiftState;<br> X, Y: Integer);<br>begin<br> // Execute user-assigned method<br> if Assigned(FOnMouseUp) then<br> FOnMouseUp(Self, Button, Shift, X, Y);<br>end;<br><br><br>procedure TCoolTrayIcon.MouseMove(Shift: TShiftState; X, Y: Integer);<br>begin<br> // Execute user-assigned method<br> if Assigned(FOnMouseMove) then<br> FOnMouseMove(Self, Shift, X, Y);<br>end;<br><br><br>procedure TCoolTrayIcon.CycleIcon;<br>begin<br> // Execute user-assigned method<br> if Assigned(FOnCycle) then<br> FOnCycle(Self, IconIndex);<br>end;<br><br><br>procedure TCoolTrayIcon.DoMinimizeToTray;<br>begin<br> // Override this method to change automatic tray minimizing behavior<br> HideMainForm;<br> IconVisible := True;<br>end;<br><br><br>procedure Register;<br>begin<br> RegisterComponents('Custom', [TCoolTrayIcon]);<br>end;<br><br>end.<br>