Pergunta

Estou tendo problema de localizar o ícone da bandeja (em px) em traybar.

Eu posso localizar uma bandeja, mas não o ícone bem.Este é o código que estou 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;

// --- Identificador de notificar 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;

// --- Encontrar 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;

// --- Função principal que deve localizar o ícone da 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 ícones de Bandeja, mas não o mapa de cada um deles.

Esta é adicionado:

Causa esta solução só funciona no XP e sistemas de 32 bits eu tentei o seguinte:

{$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 não tem esta função mapeada e, também, a seguinte estrutura:

type
  NOTIFYICONIDENTIFIER = record
    cbSize  : DWORD;
    hWnd    : HWND;
    uID     : UINT;
    guidItem: TGUID;
end;
  PNOTIFYICONIDENTIFIER = ^NOTIFYICONIDENTIFIER;

Depois que eu criei o meu ícone de bandeja com Shell_NotifyIcon eu tentei passar essa _NOTIFYICONDATA estrutura hWND para este novo NOTIFYICONIDENTIFIER estrutura >

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;

Este está funcionando corretamente e se eu receber na estrutura Rect canto superior esquerdo da minha Ícone da Bandeja.

Foi útil?

Solução

No Windows 7 e para cima, você deve usar a função da API que o MS apresentou para este propósito: Shell_NotifyIconGetRect.

O código atual é falha de um ou mais dos seguintes motivos:

  1. Você está tentando ler versões de 32 bits das estruturas de uma versão de 64 bits do processo.Neste caso, TTBBUTTON tem um layout diferente e tamanho de 64 bits e o processo que você está atacando é de 64 bits explorer.
  2. A implementação (detalhes do que você está confiando em) da área de notificação foi alterado entre o XP e o 7.Eu não sei se isso é verdade ou não, mas poderia ser!
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top