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.

¿Fue útil?

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:

  1. 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.
  2. 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!
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top