home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2001 September
/
Chip_2001-09_cd1.bin
/
zkuste
/
delphi
/
kolekce
/
d6
/
RX275D6.ZIP
/
Units
/
RXSHELL.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1999-10-12
|
22KB
|
788 lines
{*******************************************************}
{ }
{ Delphi VCL Extensions (RX) }
{ }
{ Copyright (c) 1995, 1996 AO ROSNO }
{ Copyright (c) 1997 Master-Bank }
{ }
{*******************************************************}
{.$DEFINE USE_TIMER}
{ - Use Windows timer instead thread to the animated TrayIcon }
{$IFNDEF WIN32}
{$DEFINE USE_TIMER} { - Always use timer in 16-bit version }
{$ENDIF}
unit RXShell;
{$I RX.INC}
{$P+,W-,R-}
interface
uses {$IFDEF WIN32} Windows, {$ELSE} WinTypes, WinProcs, {$ENDIF} Messages,
Classes, Graphics, SysUtils, Forms, Controls, Menus, ShellAPI,
{$IFDEF USE_TIMER} ExtCtrls, {$ENDIF} IcoList;
type
{$IFNDEF WIN32}
PNotifyIconData = ^TNotifyIconData;
TNotifyIconData = record
cbSize: Longint;
Wnd: Longint;
uID: Longint;
uFlags: Longint;
uCallbackMessage: Longint;
hIcon: Longint;
szTip: array [0..63] of Char;
end;
{$ENDIF}
TMouseButtons = set of TMouseButton;
{ TRxTrayIcon }
TRxTrayIcon = class(TComponent)
private
FHandle: HWnd;
FActive: Boolean;
FAdded: Boolean;
FAnimated: Boolean;
FEnabled: Boolean;
FClicked: TMouseButtons;
FIconIndex: Integer;
FInterval: Word;
FIconData: TNotifyIconData;
FIcon: TIcon;
FIconList: TIconList;
{$IFDEF USE_TIMER}
FTimer: TTimer;
{$ELSE}
FTimer: TThread;
{$ENDIF}
FHint: string;
FShowDesign: Boolean;
FPopupMenu: TPopupMenu;
FOnClick: TMouseEvent;
FOnDblClick: TNotifyEvent;
FOnMouseMove: TMouseMoveEvent;
FOnMouseDown: TMouseEvent;
FOnMouseUp: TMouseEvent;
procedure ChangeIcon;
{$IFDEF USE_TIMER}
procedure Timer(Sender: TObject);
{$ELSE}
procedure Timer;
{$ENDIF}
procedure SendCancelMode;
function CheckMenuPopup(X, Y: Integer): Boolean;
function CheckDefaultMenuItem: Boolean;
procedure SetHint(const Value: string);
procedure SetIcon(Value: TIcon);
procedure SetIconList(Value: TIconList);
procedure SetPopupMenu(Value: TPopupMenu);
procedure Activate;
procedure Deactivate;
procedure SetActive(Value: Boolean);
function GetAnimated: Boolean;
procedure SetAnimated(Value: Boolean);
procedure SetShowDesign(Value: Boolean);
procedure SetInterval(Value: Word);
procedure IconChanged(Sender: TObject);
procedure WndProc(var Message: TMessage);
function GetActiveIcon: TIcon;
protected
procedure DblClick; dynamic;
procedure DoClick(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic;
procedure MouseMove(Shift: TShiftState; X, Y: Integer); dynamic;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic;
procedure Loaded; override;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure UpdateNotifyData; virtual;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Hide;
procedure Show;
property Handle: HWnd read FHandle;
published
property Active: Boolean read FActive write SetActive default True;
property Enabled: Boolean read FEnabled write FEnabled default True;
property Hint: string read FHint write SetHint;
property Icon: TIcon read FIcon write SetIcon;
property Icons: TIconList read FIconList write SetIconList;
{ Ensure Icons is declared before Animated }
property Animated: Boolean read GetAnimated write SetAnimated default False;
property Interval: Word read FInterval write SetInterval default 150;
property PopupMenu: TPopupMenu read FPopupMenu write SetPopupMenu;
property ShowDesign: Boolean read FShowDesign write SetShowDesign stored False;
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;
end;
function IconExtract(const FileName: string; Id: Integer): TIcon;
procedure WinAbout(const AppName, Stuff: string);
type
TExecState = (esNormal, esMinimized, esMaximized, esHidden);
function FileExecute(const FileName, Params, StartDir: string;
InitialState: TExecState): THandle;
function FileExecuteWait(const FileName, Params, StartDir: string;
InitialState: TExecState): Integer;
implementation
uses RxConst, RxCConst, VCLUtils, MaxMin;
{$IFNDEF WIN32}
const
Shell = 'shell';
function ExtractAssociatedIcon(hInst: THandle; lpIconPath: PChar;
var lpiIcon: Word): HIcon; far; external Shell;
function ShellAbout(Wnd: HWnd; App, Stuff: PChar; Icon: HIcon): Integer;
far; external Shell;
{$ENDIF WIN32}
procedure WinAbout(const AppName, Stuff: string);
var
{$IFNDEF WIN32}
szApp, szStuff: array[0..255] of Char;
{$ENDIF}
Wnd: HWnd;
Icon: HIcon;
begin
if Application.MainForm <> nil then Wnd := Application.MainForm.Handle
else Wnd := 0;
Icon := Application.Icon.Handle;
if Icon = 0 then Icon := LoadIcon(0, IDI_APPLICATION);
{$IFDEF WIN32}
ShellAbout(Wnd, PChar(AppName), PChar(Stuff), Icon);
{$ELSE}
StrPLCopy(szApp, AppName, SizeOf(szApp) - 1);
StrPLCopy(szStuff, Stuff, SizeOf(szStuff) - 1);
ShellAbout(Wnd, szApp, szStuff, Icon);
{$ENDIF}
end;
function IconExtract(const FileName: string; Id: Integer): TIcon;
var
S: array[0..255] of char;
IconHandle: HIcon;
Index: Word;
begin
Result := TIcon.Create;
try
StrPLCopy(S, FileName, SizeOf(S) - 1);
IconHandle := ExtractIcon(hInstance, S, Id);
if IconHandle < 2 then begin
Index := Id;
IconHandle := ExtractAssociatedIcon(hInstance, S, Index);
end;
if IconHandle < 2 then begin
if IconHandle = 1 then
raise EResNotFound.Create(LoadStr(SFileNotExec))
else begin
Result.Free;
Result := nil;
end;
end else Result.Handle := IconHandle;
except
Result.Free;
raise;
end;
end;
const
ShowCommands: array[TExecState] of Integer =
(SW_SHOWNORMAL, SW_MINIMIZE, SW_SHOWMAXIMIZED, SW_HIDE);
function FileExecute(const FileName, Params, StartDir: string;
InitialState: TExecState): THandle;
{$IFDEF WIN32}
begin
Result := ShellExecute(Application.Handle, nil, PChar(FileName),
PChar(Params), PChar(StartDir), ShowCommands[InitialState]);
end;
{$ELSE}
var
cFileName, cParams, cPath: array [0..80] of Char;
begin
Result := ShellExecute(Application.Handle, nil, StrPCopy(cFileName,
FileName), StrPCopy(cParams, Params), StrPCopy(cPath, StartDir),
ShowCommands[InitialState]);
end;
{$ENDIF}
function FileExecuteWait(const FileName, Params, StartDir: string;
InitialState: TExecState): Integer;
{$IFDEF WIN32}
var
Info: TShellExecuteInfo;
ExitCode: DWORD;
begin
FillChar(Info, SizeOf(Info), 0);
Info.cbSize := SizeOf(TShellExecuteInfo);
with Info do begin
fMask := SEE_MASK_NOCLOSEPROCESS;
Wnd := Application.Handle;
lpFile := PChar(FileName);
lpParameters := PChar(Params);
lpDirectory := PChar(StartDir);
nShow := ShowCommands[InitialState];
end;
if ShellExecuteEx(@Info) then begin
repeat
Application.ProcessMessages;
GetExitCodeProcess(Info.hProcess, ExitCode);
until (ExitCode <> STILL_ACTIVE) or Application.Terminated;
Result := ExitCode;
end
else Result := -1;
end;
{$ELSE}
var
Task: THandle;
begin
Result := 0;
Task := FileExecute(FileName, Params, StartDir, InitialState);
if Task >= HINSTANCE_ERROR then begin
repeat
Application.ProcessMessages;
until (GetModuleUsage(Task) = 0) or Application.Terminated;
end
else Result := -1;
end;
{$ENDIF}
{$IFNDEF USE_TIMER}
{ TTimerThread }
type
TTimerThread = class(TThread)
private
FOwnerTray: TRxTrayIcon;
protected
procedure Execute; override;
public
constructor Create(TrayIcon: TRxTrayIcon; CreateSuspended: Boolean);
end;
constructor TTimerThread.Create(TrayIcon: TRxTrayIcon; CreateSuspended: Boolean);
begin
FOwnerTray := TrayIcon;
inherited Create(CreateSuspended);
FreeOnTerminate := True;
end;
procedure TTimerThread.Execute;
function ThreadClosed: Boolean;
begin
Result := Terminated or Application.Terminated or (FOwnerTray = nil);
end;
begin
while not Terminated do begin
if not ThreadClosed then
if SleepEx(FOwnerTray.FInterval, False) = 0 then begin
if not ThreadClosed and FOwnerTray.Animated then
FOwnerTray.Timer;
end;
end;
end;
{$ENDIF USE_TIMER}
{$IFNDEF WIN32}
type
TLoadLibrary32 = function (FileName: PChar; Handle, Special: Longint): Longint;
TFreeLibrary32 = function (Handle: Longint): Bool;
TGetAddress32 = function (Handle: Longint; ProcName: PChar): Pointer;
TCallProc32 = function (Msg: Longint; Data: PNotifyIconData; ProcHandle: Pointer;
AddressConvert, Params: Longint): Longint;
const
NIM_ADD = $00000000;
NIM_MODIFY = $00000001;
NIM_DELETE = $00000002;
NIF_MESSAGE = $00000001;
NIF_ICON = $00000002;
NIF_TIP = $00000004;
const
Shell32: Longint = 0;
ProcAddr: Pointer = nil;
FreeLib32: TFreeLibrary32 = nil;
CallPrc32: TCallProc32 = nil;
procedure FreeHandles; far;
begin
if (ProcAddr <> nil) and Assigned(FreeLib32) then FreeLib32(Shell32);
end;
procedure InitHandles;
var
Kernel16: THandle;
LoadLib32: TLoadLibrary32;
GetAddr32: TGetAddress32;
begin
Kernel16 := GetModuleHandle('kernel');
@LoadLib32 := GetProcAddress(Kernel16, 'LoadLibraryEx32W');
@FreeLib32 := GetProcAddress(Kernel16, 'FreeLibrary32W');
@GetAddr32 := GetProcAddress(Kernel16, 'GetProcAddress32W');
@CallPrc32 := GetProcAddress(Kernel16, 'CallProc32W');
if (@LoadLib32 <> nil) and (@FreeLib32 <> nil) and (@GetAddr32 <> nil)
and (@CallPrc32 <> nil) then
begin
Shell32 := LoadLib32('shell32', 0, 0);
if Shell32 >= HINSTANCE_ERROR then begin
ProcAddr := GetAddr32(Shell32, 'Shell_NotifyIcon');
if ProcAddr = nil then begin
FreeLib32(Shell32);
Shell32 := 1;
end
else AddExitProc(FreeHandles);
end
else Shell32 := 1;
end;
end;
function Shell_NotifyIcon(dwMessage: Longint; lpData: PNotifyIconData): Bool;
begin
if (ProcAddr = nil) and (Shell32 <> 1) then InitHandles;
if ProcAddr <> nil then
Result := Bool(CallPrc32(dwMessage, lpData, ProcAddr, $01, 2));
end;
{$ENDIF WIN32}
{ TRxTrayIcon }
constructor TRxTrayIcon.Create(AOwner: Tcomponent);
begin
inherited Create(AOwner);
FHandle := AllocateHWnd(WndProc);
FIcon := TIcon.Create;
FIcon.OnChange := IconChanged;
FIconList := TIconList.Create;
FIconList.OnChange := IconChanged;
FIconIndex := -1;
FEnabled := True;
FInterval := 150;
FActive := True;
end;
destructor TRxTrayIcon.Destroy;
begin
Destroying;
FEnabled := False;
FIconList.OnChange := nil;
FIcon.OnChange := nil;
SetAnimated(False);
Deactivate;
DeallocateHWnd(FHandle);
FIcon.Free;
FIcon := nil;
FIconList.Free;
FIconList := nil;
inherited Destroy;
end;
procedure TRxTrayIcon.Loaded;
begin
inherited Loaded;
if FActive and not (csDesigning in ComponentState) then Activate;
end;
procedure TRxTrayIcon.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (AComponent = PopupMenu) and (Operation = opRemove) then
PopupMenu := nil;
end;
procedure TRxTrayIcon.SetPopupMenu(Value: TPopupMenu);
begin
FPopupMenu := Value;
{$IFDEF WIN32}
if Value <> nil then Value.FreeNotification(Self);
{$ENDIF}
end;
procedure TRxTrayIcon.SendCancelMode;
var
F: TForm;
begin
if not (csDestroying in ComponentState) then begin
F := Screen.ActiveForm;
if F = nil then F := Application.MainForm;
if F <> nil then F.SendCancelMode(nil);
end;
end;
function TRxTrayIcon.CheckMenuPopup(X, Y: Integer): Boolean;
begin
Result := False;
if not (csDesigning in ComponentState) and Active and
(PopupMenu <> nil) and PopupMenu.AutoPopup then
begin
PopupMenu.PopupComponent := Self;
SendCancelMode;
SwitchToWindow(FHandle, False);
Application.ProcessMessages;
try
PopupMenu.Popup(X, Y);
finally
{$IFDEF WIN32}
SwitchToWindow(FHandle, False);
{$ENDIF}
end;
Result := True;
end;
end;
function TRxTrayIcon.CheckDefaultMenuItem: Boolean;
{$IFDEF WIN32}
var
Item: TMenuItem;
I: Integer;
{$ENDIF}
begin
Result := False;
{$IFDEF WIN32}
if not (csDesigning in ComponentState) and Active and
(PopupMenu <> nil) and (PopupMenu.Items <> nil) then
begin
I := 0;
while (I < PopupMenu.Items.Count) do begin
Item := PopupMenu.Items[I];
if Item.Default and Item.Enabled then begin
Item.Click;
Result := True;
Break;
end;
Inc(I);
end;
end;
{$ENDIF}
end;
procedure TRxTrayIcon.SetIcon(Value: TIcon);
begin
FIcon.Assign(Value);
end;
procedure TRxTrayIcon.SetIconList(Value: TIconList);
begin
FIconList.Assign(Value);
end;
function TRxTrayIcon.GetActiveIcon: TIcon;
begin
Result := FIcon;
if (FIconList <> nil) and (FIconList.Count > 0) and Animated then
Result := FIconList[Max(Min(FIconIndex, FIconList.Count - 1), 0)];
end;
function TRxTrayIcon.GetAnimated: Boolean;
begin
Result := FAnimated;
end;
procedure TRxTrayIcon.SetAnimated(Value: Boolean);
begin
Value := Value and Assigned(FIconList) and (FIconList.Count > 0);
if Value <> Animated then begin
if Value then begin
{$IFDEF USE_TIMER}
FTimer := TTimer.Create(Self);
FTimer.Enabled := FAdded;
FTimer.Interval := FInterval;
FTimer.OnTimer := Timer;
{$ELSE}
FTimer := TTimerThread.Create(Self, not FAdded);
{$ENDIF}
FAnimated := True;
end
else begin
FAnimated := False;
{$IFDEF USE_TIMER}
FTimer.Free;
FTimer := nil;
{$ELSE}
TTimerThread(FTimer).FOwnerTray := nil;
while FTimer.Suspended do FTimer.Resume;
FTimer.Terminate;
{$ENDIF}
end;
FIconIndex := 0;
ChangeIcon;
end;
end;
procedure TRxTrayIcon.SetActive(Value: Boolean);
begin
if (Value <> FActive) then begin
FActive := Value;
if not (csDesigning in ComponentState) then
if Value then Activate else Deactivate;
end;
end;
procedure TRxTrayIcon.Show;
begin
Active := True;
end;
procedure TRxTrayIcon.Hide;
begin
Active := False;
end;
procedure TRxTrayIcon.SetShowDesign(Value: Boolean);
begin
if (csDesigning in ComponentState) then begin
if Value then Activate else Deactivate;
FShowDesign := FAdded;
end;
end;
procedure TRxTrayIcon.SetInterval(Value: Word);
begin
if FInterval <> Value then begin
FInterval := Value;
{$IFDEF USE_TIMER}
if Animated then FTimer.Interval := FInterval;
{$ENDIF}
end;
end;
{$IFDEF USE_TIMER}
procedure TRxTrayIcon.Timer(Sender: TObject);
{$ELSE}
procedure TRxTrayIcon.Timer;
{$ENDIF}
begin
if not (csDestroying in ComponentState) and Animated then begin
Inc(FIconIndex);
if (FIconList = nil) or (FIconIndex >= FIconList.Count) then
FIconIndex := 0;
ChangeIcon;
end;
end;
procedure TRxTrayIcon.IconChanged(Sender: TObject);
begin
ChangeIcon;
end;
procedure TRxTrayIcon.SetHint(const Value: string);
begin
if FHint <> Value then begin
FHint := Value;
ChangeIcon;
end;
end;
procedure TRxTrayIcon.UpdateNotifyData;
var
Ico: TIcon;
begin
with FIconData do begin
cbSize := SizeOf(TNotifyIconData);
Wnd := FHandle;
uFlags := NIF_MESSAGE or NIF_ICON or NIF_TIP;
Ico := GetActiveIcon;
if Ico <> nil then hIcon := Ico.Handle
{$IFDEF WIN32}
else hIcon := INVALID_HANDLE_VALUE;
{$ELSE}
else hIcon := 0;
{$ENDIF}
StrPLCopy(szTip, GetShortHint(FHint), SizeOf(szTip) - 1);
uCallbackMessage := CM_TRAYICON;
uID := 0;
end;
end;
procedure TRxTrayIcon.Activate;
var
Ico: TIcon;
begin
Deactivate;
Ico := GetActiveIcon;
if (Ico <> nil) and not Ico.Empty then begin
FClicked := [];
UpdateNotifyData;
FAdded := Shell_NotifyIcon(NIM_ADD, @FIconData);
if (GetShortHint(FHint) = '') and FAdded then
Shell_NotifyIcon(NIM_MODIFY, @FIconData);
{$IFDEF USE_TIMER}
if Animated then FTimer.Enabled := True;
{$ELSE}
if Animated then
while FTimer.Suspended do FTimer.Resume;
{$ENDIF}
end;
end;
procedure TRxTrayIcon.Deactivate;
begin
Shell_NotifyIcon(NIM_DELETE, @FIconData);
FAdded := False;
FClicked := [];
{$IFDEF USE_TIMER}
if Animated then FTimer.Enabled := False;
{$ELSE}
if Animated and not FTimer.Suspended then FTimer.Suspend;
{$ENDIF}
end;
procedure TRxTrayIcon.ChangeIcon;
var
Ico: TIcon;
begin
if (FIconList = nil) or (FIconList.Count = 0) then SetAnimated(False);
if FAdded then begin
Ico := GetActiveIcon;
if (Ico <> nil) and not Ico.Empty then begin
UpdateNotifyData;
Shell_NotifyIcon(NIM_MODIFY, @FIconData);
end
else Deactivate;
end
else begin
if ((csDesigning in ComponentState) and FShowDesign) or
(not (csDesigning in ComponentState) and FActive) then Activate;
end;
end;
procedure TRxTrayIcon.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
if Assigned(FOnMouseMove) then FOnMouseMove(Self, Shift, X, Y);
end;
procedure TRxTrayIcon.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Assigned(FOnMouseDown) then FOnMouseDown(Self, Button, Shift, X, Y);
end;
procedure TRxTrayIcon.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Assigned(FOnMouseUp) then FOnMouseUp(Self, Button, Shift, X, Y);
end;
procedure TRxTrayIcon.DblClick;
begin
if not CheckDefaultMenuItem and Assigned(FOnDblClick) then
FOnDblClick(Self);
end;
procedure TRxTrayIcon.DoClick(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
if (Button = mbRight) and CheckMenuPopup(X, Y) then Exit;
if Assigned(FOnClick) then FOnClick(Self, Button, Shift, X, Y);
end;
procedure TRxTrayIcon.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
with Message do
if (Msg = CM_TRAYICON) and Self.FEnabled then begin
case lParam of
WM_LBUTTONDBLCLK:
begin
DblClick;
GetCursorPos(P);
MouseDown(mbLeft, GetShiftState + [ssDouble], P.X, P.Y);
end;
WM_RBUTTONDBLCLK:
begin
GetCursorPos(P);
MouseDown(mbRight, GetShiftState + [ssDouble], P.X, P.Y);
end;
WM_MBUTTONDBLCLK:
begin
GetCursorPos(P);
MouseDown(mbMiddle, GetShiftState + [ssDouble], P.X, P.Y);
end;
WM_MOUSEMOVE:
begin
GetCursorPos(P);
MouseMove(GetShiftState, P.X, P.Y);
end;
WM_LBUTTONDOWN:
begin
GetCursorPos(P);
MouseDown(mbLeft, GetShiftState + [ssLeft], P.X, P.Y);
Include(FClicked, mbLeft);
end;
WM_LBUTTONUP:
begin
Shift := GetShiftState + [ssLeft];
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, GetShiftState + [ssRight], P.X, P.Y);
Include(FClicked, mbRight);
end;
WM_RBUTTONUP:
begin
Shift := GetShiftState + [ssRight];
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, GetShiftState + [ssMiddle], P.X, P.Y);
end;
WM_MBUTTONUP:
begin
GetCursorPos(P);
MouseUp(mbMiddle, GetShiftState + [ssMiddle], P.X, P.Y);
end;
end;
end
else Result := DefWindowProc(FHandle, Msg, wParam, lParam);
except
Application.HandleException(Self);
end;
end;
end.