Rxshell.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:21k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 1995, 1996 AO ROSNO             }
  6. {         Copyright (c) 1997 Master-Bank                }
  7. {                                                       }
  8. {*******************************************************}
  9. {.$DEFINE USE_TIMER}
  10. { - Use Windows timer instead thread to the animated TrayIcon }
  11. {$IFNDEF WIN32}
  12.   {$DEFINE USE_TIMER}  { - Always use timer in 16-bit version }
  13. {$ENDIF}
  14. unit RXShell;
  15. {$I RX.INC}
  16. {$P+,W-,R-}
  17. interface
  18. uses {$IFDEF WIN32} Windows, {$ELSE} WinTypes, WinProcs, {$ENDIF} Messages,
  19.   Classes, Graphics, SysUtils, Forms, Controls, Menus, ShellAPI,
  20.   {$IFDEF USE_TIMER} ExtCtrls, {$ENDIF} IcoList;
  21. type
  22. {$IFNDEF WIN32}
  23.   PNotifyIconData = ^TNotifyIconData;
  24.   TNotifyIconData = record
  25.     cbSize: Longint;
  26.     Wnd: Longint;
  27.     uID: Longint;
  28.     uFlags: Longint;
  29.     uCallbackMessage: Longint;
  30.     hIcon: Longint;
  31.     szTip: array [0..63] of Char;
  32.   end;
  33. {$ENDIF}
  34.   TMouseButtons = set of TMouseButton;
  35. { TRxTrayIcon }
  36.   TRxTrayIcon = class(TComponent)
  37.   private
  38.     FHandle: HWnd;
  39.     FActive: Boolean;
  40.     FAdded: Boolean;
  41.     FAnimated: Boolean;
  42.     FEnabled: Boolean;
  43.     FClicked: TMouseButtons;
  44.     FIconIndex: Integer;
  45.     FInterval: Word;
  46.     FIconData: TNotifyIconData;
  47.     FIcon: TIcon;
  48.     FIconList: TIconList;
  49. {$IFDEF USE_TIMER}
  50.     FTimer: TTimer;
  51. {$ELSE}
  52.     FTimer: TThread;
  53. {$ENDIF}
  54.     FHint: string;
  55.     FShowDesign: Boolean;
  56.     FPopupMenu: TPopupMenu;
  57.     FOnClick: TMouseEvent;
  58.     FOnDblClick: TNotifyEvent;
  59.     FOnMouseMove: TMouseMoveEvent;
  60.     FOnMouseDown: TMouseEvent;
  61.     FOnMouseUp: TMouseEvent;
  62.     procedure ChangeIcon;
  63. {$IFDEF USE_TIMER}
  64.     procedure Timer(Sender: TObject);
  65. {$ELSE}
  66.     procedure Timer;
  67. {$ENDIF}
  68.     procedure SendCancelMode;
  69.     function CheckMenuPopup(X, Y: Integer): Boolean;
  70.     function CheckDefaultMenuItem: Boolean;
  71.     procedure SetHint(const Value: string);
  72.     procedure SetIcon(Value: TIcon);
  73.     procedure SetIconList(Value: TIconList);
  74.     procedure SetPopupMenu(Value: TPopupMenu);
  75.     procedure Activate;
  76.     procedure Deactivate;
  77.     procedure SetActive(Value: Boolean);
  78.     function GetAnimated: Boolean;
  79.     procedure SetAnimated(Value: Boolean);
  80.     procedure SetShowDesign(Value: Boolean);
  81.     procedure SetInterval(Value: Word);
  82.     procedure IconChanged(Sender: TObject);
  83.     procedure WndProc(var Message: TMessage);
  84.     function GetActiveIcon: TIcon;
  85.   protected
  86.     procedure DblClick; dynamic;
  87.     procedure DoClick(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic;
  88.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic;
  89.     procedure MouseMove(Shift: TShiftState; X, Y: Integer); dynamic;
  90.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic;
  91.     procedure Loaded; override;
  92.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  93.     procedure UpdateNotifyData; virtual;
  94.   public
  95.     constructor Create(AOwner: TComponent); override;
  96.     destructor Destroy; override;
  97.     procedure Hide;
  98.     procedure Show;
  99.     property Handle: HWnd read FHandle;
  100.   published
  101.     property Active: Boolean read FActive write SetActive default True;
  102.     property Enabled: Boolean read FEnabled write FEnabled default True;
  103.     property Hint: string read FHint write SetHint;
  104.     property Icon: TIcon read FIcon write SetIcon;
  105.     property Icons: TIconList read FIconList write SetIconList;
  106.     { Ensure Icons is declared before Animated }
  107.     property Animated: Boolean read GetAnimated write SetAnimated default False;
  108.     property Interval: Word read FInterval write SetInterval default 150;
  109.     property PopupMenu: TPopupMenu read FPopupMenu write SetPopupMenu;
  110.     property ShowDesign: Boolean read FShowDesign write SetShowDesign stored False;
  111.     property OnClick: TMouseEvent read FOnClick write FOnClick;
  112.     property OnDblClick: TNotifyEvent read FOnDblClick write FOnDblClick;
  113.     property OnMouseMove: TMouseMoveEvent read FOnMouseMove write FOnMouseMove;
  114.     property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;
  115.     property OnMouseUp: TMouseEvent read FOnMouseUp write FOnMouseUp;
  116.   end;
  117. function IconExtract(const FileName: string; Id: Integer): TIcon;
  118. procedure WinAbout(const AppName, Stuff: string);
  119. type
  120.   TExecState = (esNormal, esMinimized, esMaximized, esHidden);
  121. function FileExecute(const FileName, Params, StartDir: string;
  122.   InitialState: TExecState): THandle;
  123. function FileExecuteWait(const FileName, Params, StartDir: string;
  124.   InitialState: TExecState): Integer;
  125. implementation
  126. uses RxConst, RxCConst, VCLUtils, MaxMin;
  127. {$IFNDEF WIN32}
  128. const
  129.   Shell = 'shell';
  130. function ExtractAssociatedIcon(hInst: THandle; lpIconPath: PChar;
  131.   var lpiIcon: Word): HIcon; far; external Shell;
  132. function ShellAbout(Wnd: HWnd; App, Stuff: PChar; Icon: HIcon): Integer;
  133.   far; external Shell;
  134. {$ENDIF WIN32}
  135. procedure WinAbout(const AppName, Stuff: string);
  136. var
  137. {$IFNDEF WIN32}
  138.   szApp, szStuff: array[0..255] of Char;
  139. {$ENDIF}
  140.   Wnd: HWnd;
  141.   Icon: HIcon;
  142. begin
  143.   if Application.MainForm <> nil then Wnd := Application.MainForm.Handle
  144.   else Wnd := 0;
  145.   Icon := Application.Icon.Handle;
  146.   if Icon = 0 then Icon := LoadIcon(0, IDI_APPLICATION);
  147. {$IFDEF WIN32}
  148.   ShellAbout(Wnd, PChar(AppName), PChar(Stuff), Icon);
  149. {$ELSE}
  150.   StrPLCopy(szApp, AppName, SizeOf(szApp) - 1);
  151.   StrPLCopy(szStuff, Stuff, SizeOf(szStuff) - 1);
  152.   ShellAbout(Wnd, szApp, szStuff, Icon);
  153. {$ENDIF}
  154. end;
  155. function IconExtract(const FileName: string; Id: Integer): TIcon;
  156. var
  157.   S: array[0..255] of char;
  158.   IconHandle: HIcon;
  159.   Index: Word;
  160. begin
  161.   Result := TIcon.Create;
  162.   try
  163.     StrPLCopy(S, FileName, SizeOf(S) - 1);
  164.     IconHandle := ExtractIcon(hInstance, S, Id);
  165.     if IconHandle < 2 then begin
  166.       Index := Id;
  167.       IconHandle := ExtractAssociatedIcon(hInstance, S, Index);
  168.     end;
  169.     if IconHandle < 2 then begin
  170.       if IconHandle = 1 then
  171.         raise EResNotFound.Create(LoadStr(SFileNotExec))
  172.       else begin
  173.         Result.Free;
  174.         Result := nil;
  175.       end;
  176.     end else Result.Handle := IconHandle;
  177.   except
  178.     Result.Free;
  179.     raise;
  180.   end;
  181. end;
  182. const
  183.   ShowCommands: array[TExecState] of Integer =
  184.     (SW_SHOWNORMAL, SW_MINIMIZE, SW_SHOWMAXIMIZED, SW_HIDE);
  185. function FileExecute(const FileName, Params, StartDir: string;
  186.   InitialState: TExecState): THandle;
  187. {$IFDEF WIN32}
  188. begin
  189.   Result := ShellExecute(Application.Handle, nil, PChar(FileName),
  190.     PChar(Params), PChar(StartDir), ShowCommands[InitialState]);
  191. end;
  192. {$ELSE}
  193. var
  194.   cFileName, cParams, cPath: array [0..80] of Char;
  195. begin
  196.   Result := ShellExecute(Application.Handle, nil, StrPCopy(cFileName,
  197.     FileName), StrPCopy(cParams, Params), StrPCopy(cPath, StartDir),
  198.     ShowCommands[InitialState]);
  199. end;
  200. {$ENDIF}
  201. function FileExecuteWait(const FileName, Params, StartDir: string;
  202.   InitialState: TExecState): Integer;
  203. {$IFDEF WIN32}
  204. var
  205.   Info: TShellExecuteInfo;
  206.   ExitCode: DWORD;
  207. begin
  208.   FillChar(Info, SizeOf(Info), 0);
  209.   Info.cbSize := SizeOf(TShellExecuteInfo);
  210.   with Info do begin
  211.     fMask := SEE_MASK_NOCLOSEPROCESS;
  212.     Wnd := Application.Handle;
  213.     lpFile := PChar(FileName);
  214.     lpParameters := PChar(Params);
  215.     lpDirectory := PChar(StartDir);
  216.     nShow := ShowCommands[InitialState];
  217.   end;
  218.   if ShellExecuteEx(@Info) then begin
  219.     repeat
  220.       Application.ProcessMessages;
  221.       GetExitCodeProcess(Info.hProcess, ExitCode);
  222.     until (ExitCode <> STILL_ACTIVE) or Application.Terminated;
  223.     Result := ExitCode;
  224.   end
  225.   else Result := -1;
  226. end;
  227. {$ELSE}
  228. var
  229.   Task: THandle;
  230. begin
  231.   Result := 0;
  232.   Task := FileExecute(FileName, Params, StartDir, InitialState);
  233.   if Task >= HINSTANCE_ERROR then begin
  234.     repeat
  235.       Application.ProcessMessages;
  236.     until (GetModuleUsage(Task) = 0) or Application.Terminated;
  237.   end
  238.   else Result := -1;
  239. end;
  240. {$ENDIF}
  241. {$IFNDEF USE_TIMER}
  242. { TTimerThread }
  243. type
  244.   TTimerThread = class(TThread)
  245.   private
  246.     FOwnerTray: TRxTrayIcon;
  247.   protected
  248.     procedure Execute; override;
  249.   public
  250.     constructor Create(TrayIcon: TRxTrayIcon; CreateSuspended: Boolean);
  251.   end;
  252. constructor TTimerThread.Create(TrayIcon: TRxTrayIcon; CreateSuspended: Boolean);
  253. begin
  254.   FOwnerTray := TrayIcon;
  255.   inherited Create(CreateSuspended);
  256.   FreeOnTerminate := True;
  257. end;
  258. procedure TTimerThread.Execute;
  259.   function ThreadClosed: Boolean;
  260.   begin
  261.     Result := Terminated or Application.Terminated or (FOwnerTray = nil);
  262.   end;
  263. begin
  264.   while not Terminated do begin
  265.     if not ThreadClosed then
  266.       if SleepEx(FOwnerTray.FInterval, False) = 0 then begin
  267.         if not ThreadClosed and FOwnerTray.Animated then
  268.           FOwnerTray.Timer;
  269.       end;
  270.   end;
  271. end;
  272. {$ENDIF USE_TIMER}
  273. {$IFNDEF WIN32}
  274. type
  275.   TLoadLibrary32 = function (FileName: PChar; Handle, Special: Longint): Longint;
  276.   TFreeLibrary32 = function (Handle: Longint): Bool;
  277.   TGetAddress32 = function (Handle: Longint; ProcName: PChar): Pointer;
  278.   TCallProc32 = function (Msg: Longint; Data: PNotifyIconData; ProcHandle: Pointer;
  279.     AddressConvert, Params: Longint): Longint;
  280. const
  281.   NIM_ADD     = $00000000;
  282.   NIM_MODIFY  = $00000001;
  283.   NIM_DELETE  = $00000002;
  284.   NIF_MESSAGE = $00000001;
  285.   NIF_ICON    = $00000002;
  286.   NIF_TIP     = $00000004;
  287. const
  288.   Shell32: Longint = 0;
  289.   ProcAddr: Pointer = nil;
  290.   FreeLib32: TFreeLibrary32 = nil;
  291.   CallPrc32: TCallProc32 = nil;
  292. procedure FreeHandles; far;
  293. begin
  294.   if (ProcAddr <> nil) and Assigned(FreeLib32) then FreeLib32(Shell32);
  295. end;
  296. procedure InitHandles;
  297. var
  298.   Kernel16: THandle;
  299.   LoadLib32: TLoadLibrary32;
  300.   GetAddr32: TGetAddress32;
  301. begin
  302.   Kernel16 := GetModuleHandle('kernel');
  303.   @LoadLib32 := GetProcAddress(Kernel16, 'LoadLibraryEx32W');
  304.   @FreeLib32 := GetProcAddress(Kernel16, 'FreeLibrary32W');
  305.   @GetAddr32 := GetProcAddress(Kernel16, 'GetProcAddress32W');
  306.   @CallPrc32 := GetProcAddress(Kernel16, 'CallProc32W');
  307.   if (@LoadLib32 <> nil) and (@FreeLib32 <> nil) and (@GetAddr32 <> nil)
  308.     and (@CallPrc32 <> nil) then
  309.   begin
  310.     Shell32 := LoadLib32('shell32', 0, 0);
  311.     if Shell32 >= HINSTANCE_ERROR then begin
  312.       ProcAddr := GetAddr32(Shell32, 'Shell_NotifyIcon');
  313.       if ProcAddr = nil then begin
  314.         FreeLib32(Shell32);
  315.         Shell32 := 1;
  316.       end
  317.       else AddExitProc(FreeHandles);
  318.     end
  319.     else Shell32 := 1;
  320.   end;
  321. end;
  322. function Shell_NotifyIcon(dwMessage: Longint; lpData: PNotifyIconData): Bool;
  323. begin
  324.   if (ProcAddr = nil) and (Shell32 <> 1) then InitHandles;
  325.   if ProcAddr <> nil then
  326.     Result := Bool(CallPrc32(dwMessage, lpData, ProcAddr, $01, 2));
  327. end;
  328. {$ENDIF WIN32}
  329. { TRxTrayIcon }
  330. constructor TRxTrayIcon.Create(AOwner: Tcomponent);
  331. begin
  332.   inherited Create(AOwner);
  333.   FHandle := AllocateHWnd(WndProc);
  334.   FIcon := TIcon.Create;
  335.   FIcon.OnChange := IconChanged;
  336.   FIconList := TIconList.Create;
  337.   FIconList.OnChange := IconChanged;
  338.   FIconIndex := -1;
  339.   FEnabled := True;
  340.   FInterval := 150;
  341.   FActive := True;
  342. end;
  343. destructor TRxTrayIcon.Destroy;
  344. begin
  345.   Destroying;
  346.   FEnabled := False;
  347.   FIconList.OnChange := nil;
  348.   FIcon.OnChange := nil;
  349.   SetAnimated(False);
  350.   Deactivate;
  351.   DeallocateHWnd(FHandle);
  352.   FIcon.Free;
  353.   FIcon := nil;
  354.   FIconList.Free;
  355.   FIconList := nil;
  356.   inherited Destroy;
  357. end;
  358. procedure TRxTrayIcon.Loaded;
  359. begin
  360.   inherited Loaded;
  361.   if FActive and not (csDesigning in ComponentState) then Activate;
  362. end;
  363. procedure TRxTrayIcon.Notification(AComponent: TComponent;
  364.   Operation: TOperation);
  365. begin
  366.   inherited Notification(AComponent, Operation);
  367.   if (AComponent = PopupMenu) and (Operation = opRemove) then
  368.     PopupMenu := nil;
  369. end;
  370. procedure TRxTrayIcon.SetPopupMenu(Value: TPopupMenu);
  371. begin
  372.   FPopupMenu := Value;
  373. {$IFDEF WIN32}
  374.   if Value <> nil then Value.FreeNotification(Self);
  375. {$ENDIF}
  376. end;
  377. procedure TRxTrayIcon.SendCancelMode;
  378. var
  379.   F: TForm;
  380. begin
  381.   if not (csDestroying in ComponentState) then begin
  382.     F := Screen.ActiveForm;
  383.     if F = nil then F := Application.MainForm;
  384.     if F <> nil then F.SendCancelMode(nil);
  385.   end;
  386. end;
  387. function TRxTrayIcon.CheckMenuPopup(X, Y: Integer): Boolean;
  388. begin
  389.   Result := False;
  390.   if not (csDesigning in ComponentState) and Active and
  391.     (PopupMenu <> nil) and PopupMenu.AutoPopup then
  392.   begin
  393.     PopupMenu.PopupComponent := Self;
  394.     SendCancelMode;
  395.     SwitchToWindow(FHandle, False);
  396.     Application.ProcessMessages;
  397.     try
  398.       PopupMenu.Popup(X, Y);
  399.     finally
  400. {$IFDEF WIN32}
  401.       SwitchToWindow(FHandle, False);
  402. {$ENDIF}
  403.     end;
  404.     Result := True;
  405.   end;
  406. end;
  407. function TRxTrayIcon.CheckDefaultMenuItem: Boolean;
  408. {$IFDEF WIN32}
  409. var
  410.   Item: TMenuItem;
  411.   I: Integer;
  412. {$ENDIF}
  413. begin
  414.   Result := False;
  415. {$IFDEF WIN32}
  416.   if not (csDesigning in ComponentState) and Active and
  417.     (PopupMenu <> nil) and (PopupMenu.Items <> nil) then
  418.   begin
  419.     I := 0;
  420.     while (I < PopupMenu.Items.Count) do begin
  421.       Item := PopupMenu.Items[I];
  422.       if Item.Default and Item.Enabled then begin
  423.         Item.Click;
  424.         Result := True;
  425.         Break;
  426.       end;
  427.       Inc(I);
  428.     end;
  429.   end;
  430. {$ENDIF}
  431. end;
  432. procedure TRxTrayIcon.SetIcon(Value: TIcon);
  433. begin
  434.   FIcon.Assign(Value);
  435. end;
  436. procedure TRxTrayIcon.SetIconList(Value: TIconList);
  437. begin
  438.   FIconList.Assign(Value);
  439. end;
  440. function TRxTrayIcon.GetActiveIcon: TIcon;
  441. begin
  442.   Result := FIcon;
  443.   if (FIconList <> nil) and (FIconList.Count > 0) and Animated then
  444.     Result := FIconList[Max(Min(FIconIndex, FIconList.Count - 1), 0)];
  445. end;
  446. function TRxTrayIcon.GetAnimated: Boolean;
  447. begin
  448.   Result := FAnimated;
  449. end;
  450. procedure TRxTrayIcon.SetAnimated(Value: Boolean);
  451. begin
  452.   Value := Value and Assigned(FIconList) and (FIconList.Count > 0);
  453.   if Value <> Animated then begin
  454.     if Value then begin
  455. {$IFDEF USE_TIMER}
  456.       FTimer := TTimer.Create(Self);
  457.       FTimer.Enabled := FAdded;
  458.       FTimer.Interval := FInterval;
  459.       FTimer.OnTimer := Timer;
  460. {$ELSE}
  461.       FTimer := TTimerThread.Create(Self, not FAdded);
  462. {$ENDIF}
  463.       FAnimated := True;
  464.     end
  465.     else begin
  466.       FAnimated := False;
  467. {$IFDEF USE_TIMER}
  468.       FTimer.Free;
  469.       FTimer := nil;
  470. {$ELSE}
  471.       TTimerThread(FTimer).FOwnerTray := nil;
  472.       while FTimer.Suspended do FTimer.Resume;
  473.       FTimer.Terminate;
  474. {$ENDIF}
  475.     end;
  476.     FIconIndex := 0;
  477.     ChangeIcon;
  478.   end;
  479. end;
  480. procedure TRxTrayIcon.SetActive(Value: Boolean);
  481. begin
  482.   if (Value <> FActive) then begin
  483.     FActive := Value;
  484.     if not (csDesigning in ComponentState) then
  485.       if Value then Activate else Deactivate;
  486.   end;
  487. end;
  488. procedure TRxTrayIcon.Show;
  489. begin
  490.   Active := True;
  491. end;
  492. procedure TRxTrayIcon.Hide;
  493. begin
  494.   Active := False;
  495. end;
  496. procedure TRxTrayIcon.SetShowDesign(Value: Boolean);
  497. begin
  498.   if (csDesigning in ComponentState) then begin
  499.     if Value then Activate else Deactivate;
  500.     FShowDesign := FAdded;
  501.   end;
  502. end;
  503. procedure TRxTrayIcon.SetInterval(Value: Word);
  504. begin
  505.   if FInterval <> Value then begin
  506.     FInterval := Value;
  507. {$IFDEF USE_TIMER}
  508.     if Animated then FTimer.Interval := FInterval;
  509. {$ENDIF}
  510.   end;
  511. end;
  512. {$IFDEF USE_TIMER}
  513. procedure TRxTrayIcon.Timer(Sender: TObject);
  514. {$ELSE}
  515. procedure TRxTrayIcon.Timer;
  516. {$ENDIF}
  517. begin
  518.   if not (csDestroying in ComponentState) and Animated then begin
  519.     Inc(FIconIndex);
  520.     if (FIconList = nil) or (FIconIndex >= FIconList.Count) then
  521.       FIconIndex := 0;
  522.     ChangeIcon;
  523.   end;
  524. end;
  525. procedure TRxTrayIcon.IconChanged(Sender: TObject);
  526. begin
  527.   ChangeIcon;
  528. end;
  529. procedure TRxTrayIcon.SetHint(const Value: string);
  530. begin
  531.   if FHint <> Value then begin
  532.     FHint := Value;
  533.     ChangeIcon;
  534.   end;
  535. end;
  536. procedure TRxTrayIcon.UpdateNotifyData;
  537. var
  538.   Ico: TIcon;
  539. begin
  540.   with FIconData do begin
  541.     cbSize := SizeOf(TNotifyIconData);
  542.     Wnd := FHandle;
  543.     uFlags := NIF_MESSAGE or NIF_ICON or NIF_TIP;
  544.     Ico := GetActiveIcon;
  545.     if Ico <> nil then hIcon := Ico.Handle
  546. {$IFDEF WIN32}
  547.     else hIcon := INVALID_HANDLE_VALUE;
  548. {$ELSE}
  549.     else hIcon := 0;
  550. {$ENDIF}
  551.     StrPLCopy(szTip, GetShortHint(FHint), SizeOf(szTip) - 1);
  552.     uCallbackMessage := CM_TRAYICON;
  553.     uID := 0;
  554.   end;
  555. end;
  556. procedure TRxTrayIcon.Activate;
  557. var
  558.   Ico: TIcon;
  559. begin
  560.   Deactivate;
  561.   Ico := GetActiveIcon;
  562.   if (Ico <> nil) and not Ico.Empty then begin
  563.     FClicked := [];
  564.     UpdateNotifyData;
  565.     FAdded := Shell_NotifyIcon(NIM_ADD, @FIconData);
  566.     if (GetShortHint(FHint) = '') and FAdded then
  567.       Shell_NotifyIcon(NIM_MODIFY, @FIconData);
  568. {$IFDEF USE_TIMER}
  569.     if Animated then FTimer.Enabled := True;
  570. {$ELSE}
  571.     if Animated then
  572.       while FTimer.Suspended do FTimer.Resume;
  573. {$ENDIF}
  574.   end;
  575. end;
  576. procedure TRxTrayIcon.Deactivate;
  577. begin
  578.   Shell_NotifyIcon(NIM_DELETE, @FIconData);
  579.   FAdded := False;
  580.   FClicked := [];
  581. {$IFDEF USE_TIMER}
  582.   if Animated then FTimer.Enabled := False;
  583. {$ELSE}
  584.   if Animated and not FTimer.Suspended then FTimer.Suspend;
  585. {$ENDIF}
  586. end;
  587. procedure TRxTrayIcon.ChangeIcon;
  588. var
  589.   Ico: TIcon;
  590. begin
  591.   if (FIconList = nil) or (FIconList.Count = 0) then SetAnimated(False);
  592.   if FAdded then begin
  593.     Ico := GetActiveIcon;
  594.     if (Ico <> nil) and not Ico.Empty then begin
  595.       UpdateNotifyData;
  596.       Shell_NotifyIcon(NIM_MODIFY, @FIconData);
  597.     end
  598.     else Deactivate;
  599.   end
  600.   else begin
  601.     if ((csDesigning in ComponentState) and FShowDesign) or
  602.       (not (csDesigning in ComponentState) and FActive) then Activate;
  603.   end;
  604. end;
  605. procedure TRxTrayIcon.MouseMove(Shift: TShiftState; X, Y: Integer);
  606. begin
  607.   if Assigned(FOnMouseMove) then FOnMouseMove(Self, Shift, X, Y);
  608. end;
  609. procedure TRxTrayIcon.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  610. begin
  611.   if Assigned(FOnMouseDown) then FOnMouseDown(Self, Button, Shift, X, Y);
  612. end;
  613. procedure TRxTrayIcon.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  614. begin
  615.   if Assigned(FOnMouseUp) then FOnMouseUp(Self, Button, Shift, X, Y);
  616. end;
  617. procedure TRxTrayIcon.DblClick;
  618. begin
  619.   if not CheckDefaultMenuItem and Assigned(FOnDblClick) then
  620.     FOnDblClick(Self);
  621. end;
  622. procedure TRxTrayIcon.DoClick(Button: TMouseButton; Shift: TShiftState;
  623.   X, Y: Integer);
  624. begin
  625.   if (Button = mbRight) and CheckMenuPopup(X, Y) then Exit;
  626.   if Assigned(FOnClick) then FOnClick(Self, Button, Shift, X, Y);
  627. end;
  628. procedure TRxTrayIcon.WndProc(var Message: TMessage);
  629.   function GetShiftState: TShiftState;
  630.   begin
  631.     Result := [];
  632.     if GetKeyState(VK_SHIFT) < 0 then Include(Result, ssShift);
  633.     if GetKeyState(VK_CONTROL) < 0 then Include(Result, ssCtrl);
  634.     if GetKeyState(VK_MENU) < 0 then Include(Result, ssAlt);
  635.   end;
  636. var
  637.   P: TPoint;
  638.   Shift: TShiftState;
  639. begin
  640.   try
  641.     with Message do
  642.       if (Msg = CM_TRAYICON) and Self.FEnabled then begin
  643.         case lParam of
  644.           WM_LBUTTONDBLCLK:
  645.             begin
  646.               DblClick;
  647.               GetCursorPos(P);
  648.               MouseDown(mbLeft, GetShiftState + [ssDouble], P.X, P.Y);
  649.             end;
  650.           WM_RBUTTONDBLCLK:
  651.             begin
  652.               GetCursorPos(P);
  653.               MouseDown(mbRight, GetShiftState + [ssDouble], P.X, P.Y);
  654.             end;
  655.           WM_MBUTTONDBLCLK:
  656.             begin
  657.               GetCursorPos(P);
  658.               MouseDown(mbMiddle, GetShiftState + [ssDouble], P.X, P.Y);
  659.             end;
  660.           WM_MOUSEMOVE:
  661.             begin
  662.               GetCursorPos(P);
  663.               MouseMove(GetShiftState, P.X, P.Y);
  664.             end;
  665.           WM_LBUTTONDOWN:
  666.             begin
  667.               GetCursorPos(P);
  668.               MouseDown(mbLeft, GetShiftState + [ssLeft], P.X, P.Y);
  669.               Include(FClicked, mbLeft);
  670.             end;
  671.           WM_LBUTTONUP:
  672.             begin
  673.               Shift := GetShiftState + [ssLeft];
  674.               GetCursorPos(P);
  675.               if mbLeft in FClicked then begin
  676.                 Exclude(FClicked, mbLeft);
  677.                 DoClick(mbLeft, Shift, P.X, P.Y);
  678.               end;
  679.               MouseUp(mbLeft, Shift, P.X, P.Y);
  680.             end;
  681.           WM_RBUTTONDOWN:
  682.             begin
  683.               GetCursorPos(P);
  684.               MouseDown(mbRight, GetShiftState + [ssRight], P.X, P.Y);
  685.               Include(FClicked, mbRight);
  686.             end;
  687.           WM_RBUTTONUP:
  688.             begin
  689.               Shift := GetShiftState + [ssRight];
  690.               GetCursorPos(P);
  691.               if mbRight in FClicked then begin
  692.                 Exclude(FClicked, mbRight);
  693.                 DoClick(mbRight, Shift, P.X, P.Y);
  694.               end;
  695.               MouseUp(mbRight, Shift, P.X, P.Y);
  696.             end;
  697.           WM_MBUTTONDOWN:
  698.             begin
  699.               GetCursorPos(P);
  700.               MouseDown(mbMiddle, GetShiftState + [ssMiddle], P.X, P.Y);
  701.             end;
  702.           WM_MBUTTONUP:
  703.             begin
  704.               GetCursorPos(P);
  705.               MouseUp(mbMiddle, GetShiftState + [ssMiddle], P.X, P.Y);
  706.             end;
  707.         end;
  708.       end
  709.       else Result := DefWindowProc(FHandle, Msg, wParam, lParam);
  710.   except
  711.     Application.HandleException(Self);
  712.   end;
  713. end;
  714. end.