Busque El Icono De La Bandeja
Pregunta
Estoy teniendo problemas para localizar el icono de la bandeja (en px) en traybar.
Me puede localizar la bandeja pero no el icono.Este es el código que estoy usando:
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;
// --- Manija de notificar a 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;
// --- Hallazgo de la Bandeja rect
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;
// --- Función principal que debe buscar el icono de la bandeja
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.
Algo detectar # de los iconos de la Bandeja, pero no mapa de cada uno de ellos.
A esto se añade:
La causa de esta solución sólo funciona bajo XP y los sistemas de 32bit he probado los siguientes:
{$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 no tiene esta función asignada y también esta estructura:
type
NOTIFYICONIDENTIFIER = record
cbSize : DWORD;
hWnd : HWND;
uID : UINT;
guidItem: TGUID;
end;
PNOTIFYICONIDENTIFIER = ^NOTIFYICONIDENTIFIER;
Después he creado mi icono de la bandeja con Shell_NotifyIcon he probado a pasar que _NOTIFYICONDATA estructura hWND a esta nueva NOTIFYICONIDENTIFIER estructura >
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;
Esto está funcionando correctamente y me recibe en la estructura Rect esquina superior izquierda de mi Icono de la Bandeja.
Solución
En Windows 7 y hacia arriba, usted debe utilizar la función de API que MS introducido para este propósito: Shell_NotifyIconGetRect
.
Su actual código de falla para una o más de las siguientes razones:
- Usted está tratando de leer las versiones de 32 bits de las estructuras de 64 bits proceso.En este caso
TTBBUTTON
tiene un diseño diferente y tamaño por debajo de los 64 bits y el proceso que se está atacando es de 64 bits explorer. - La aplicación (los detalles de lo que usted está confiando en la notificación de la zona ha cambiado entre XP y 7.No sé si esto es o no es cierto, pero podría ser!