У меня проблема с поиском иконки в трее (в пикселях) на панели задач.
Я могу найти трей, но не иконку. Это код, который я использую:
unit uTrayIconPosition;
interface
uses
Types;
function GetTrayIconPosition(const AWnd: THandle; const AButtonID: Integer; var APosition: TRect): Boolean;
implementation
uses
Windows, CommCtrl, Classes, SysUtils;
function EnumWindowsFunc(AHandle: THandle; AList: TStringList): Boolean; stdcall;
var
P: array [0..256] of Char;
S: string;
begin
if GetClassName(AHandle, P, SizeOf(P) - 1) <> 0 then
begin
S := P;
if S = AList[0] then
begin
AList[0] := IntToStr(AHandle);
Result := False;
end
else
Result := True;
end
else
Result := True;
end;
function FindClass(AName: string; AHandle: THandle; var AChild: THandle): Boolean;
var
List: TStringList;
begin
Result := False;
try
List := TStringList.Create;
try
List.Add(AName);
EnumChildWindows(AHandle, @EnumWindowsFunc, LParam(List));
if List.Count > 0 then
begin
AChild := StrToInt(List[0]);
Result := True;
end;
finally
List.Free;
end;
except
end;
end;
// --- Ручка уведомления Wnd
function GetTrayNotifyWnd: THandle;
var
ShellTray: THandle;
TrayNotify: THandle;
ToolBar: THandle;
begin
Result := 0;
ShellTray := FindWindow('Shell_TrayWnd', nil);
if ShellTray <> 0 then
if FindClass('TrayNotifyWnd', ShellTray, TrayNotify) then
if IsWindow(TrayNotify) then
if FindClass('ToolbarWindow32', TrayNotify, ToolBar) then
Result := ToolBar;
end;
// --- Поиск прямоугольника лотка
function GetTrayWndRect: TRect;
var
R: TRect;
Handle: THandle;
Width: Integer;
Height: Integer;
begin
Handle := GetTrayNotifyWnd;
if Handle > 0 then
begin
GetWindowRect(Handle, R);
Result := R;
end
else
begin
Width := GetSystemMetrics(SM_CXSCREEN);
Height := GetSystemMetrics(SM_CYSCREEN);
Result := Rect(Width - 40, Height - 20, Width, Height);
end;
end;
// --- Основная функция, которая должна найти иконку в трее
function GetTrayIconPosition(const AWnd: THandle; const AButtonID: Integer; var APosition: TRect): Boolean;
var
hWndTray: HWND;
dwTrayProcessID: DWORD;
hTrayProc: THandle;
iButtonsCount: Integer;
lpData: Pointer;
bIconFound: Boolean;
iButton: Integer;
dwBytesRead: DWORD;
ButtonData: TTBBUTTON;
dwExtraData: array [0..1] of DWORD;
hWndOfIconOwner: THandle;
iIconId: Integer;
// rcPosition: TPoint;
rcPosition: TRect;
begin
Result := False;
hWndTray := GetTrayNotifyWnd;
if hWndTray = 0 then
Exit;
dwTrayProcessID := 0;
GetWindowThreadProcessId(hWndTray, dwTrayProcessID);
if dwTrayProcessID <= 0 then
Exit;
hTrayProc := OpenProcess(PROCESS_ALL_ACCESS, False, dwTrayProcessID);
if hTrayProc = 0 then
Exit;
iButtonsCount := SendMessage(hWndTray, TB_BUTTONCOUNT, 0, 0);
lpData := VirtualAllocEx(hTrayProc, nil, SizeOf(TTBBUTTON), MEM_COMMIT, PAGE_READWRITE);
if (lpData = nil) or (iButtonsCount < 1) then
begin
CloseHandle(hTrayProc);
Exit;
end;
bIconFound := False;
for iButton :=0 to iButtonsCount - 1 do
begin
dwBytesRead := 0;
SendMessage(hWndTray, TB_GETBUTTON, iButton, LPARAM(lpData));
ReadProcessMemory(hTrayProc, lpData, @ButtonData, SizeOf(TTBBUTTON), dwBytesRead);
if dwBytesRead < SizeOf(TTBBUTTON) then
Break;
dwExtraData[0] := 0;
dwExtraData[1] := 0;
ReadProcessMemory(hTrayProc, Pointer(ButtonData.dwData), @dwExtraData, SizeOf(dwExtraData), dwBytesRead);
if dwBytesRead < SizeOf(dwExtraData) then
Break;
hWndOfIconOwner := THandle(dwExtraData[0]);
iIconId := Integer(dwExtraData[1]);
if hWndOfIconOwner = AWnd then
if iIconId = AButtonID then
begin
if (ButtonData.fsState or TBSTATE_HIDDEN) = 1 then
Break;
SendMessage(hWndTray, TB_GETITEMRECT, iButton, LPARAM(lpData));
ReadProcessMemory(hTrayProc, lpData, @rcPosition, SizeOf(TREct), dwBytesRead);
if dwBytesRead < SizeOf(TRect) then
Break;
MapWindowPoints(hWndTray, 0, rcPosition, 2);
APosition := rcPosition;
bIconFound := True;
Break;
end;
end;
if not bIconFound then
APosition := GetTrayWndRect;
VirtualFreeEx(hTrayProc, lpData, 0, MEM_RELEASE);
CloseHandle(hTrayProc);
Result := True;
end;
end.
Алгоритм обнаруживает # значков в трее, но не отображает каждую из них.
Это добавлено:
Потому что это решение работает только в XP и 32-битных системах, я попробовал следующее:
{$EXTERNALSYM Shell_NotifyIconGetRect}
function Shell_NotifyIconGetRect(const _in: NOTIFYICONIDENTIFIER; var _out: TRECT): HRESULT; stdcall;
implementation
function Shell_NotifyIconGetRect; external 'Shell32.dll' name 'Shell_NotifyIconGetRect';
Delphi 2007 не имеет этой функции, а также этой структуры:
type
NOTIFYICONIDENTIFIER = record
cbSize : DWORD;
hWnd : HWND;
uID : UINT;
guidItem: TGUID;
end;
PNOTIFYICONIDENTIFIER = ^NOTIFYICONIDENTIFIER;
После того как я создал иконку в трее с помощью Shell_NotifyIcon, я попытался передать эту структуру _NOTIFYICONDATA hWND этой новой структуре NOTIFYICONIDENTIFIER>
var
R: TRect;
S: NOTIFYICONIDENTIFIER;
FillChar(S, SizeOf(S), #0);
S.cbSize := SizeOf(NOTIFYICONIDENTIFIER);
S.hWnd := ATrayIcon.Data.Wnd;
S.uID := ATrayIcon.Data.uID;
Result := Shell_NotifyIconGetRect(S, R) = S_OK;
Это работает правильно, и я получаю в структуре Rect левый верхний угол моей иконки в трее.