gpt4 book ai didi

delphi - 找到托盘图标

转载 作者:行者123 更新时间:2023-12-02 03:12:45 25 4
gpt4 key购买 nike

我在托盘栏上定位托盘图标(以 px 为单位)时遇到问题。

我可以找到托盘,但也找不到图标。这是我正在使用的代码:

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;

这工作正常,我在托盘图标的左上角收到矩形结构。

最佳答案

在 Windows 7 及更高版本上,您应该使用 MS 为此目的引入的 API 函数:Shell_NotifyIconGetRect .

您当前的代码由于以下一个或多个原因而失败:

  1. 您正在尝试从 64 位进程读取 32 位版本的结构。在这种情况下,TTBBUTTON 在 64 位下具有不同的布局和大小,并且您正在攻击的进程是 64 位资源管理器。
  2. 通知区域的实现(您所依赖的细节)在 XP 和 7 之间发生了变化。我不知道这是否属实,但有可能是!

关于delphi - 找到托盘图标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9502418/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com