Jam*_*amo 2 delphi components system-tray
我有几个旧的应用程序(在Delphi中),由于各种原因使用系统托盘图标.大多数使用AppControls TacTrayIcon或其他类似组件.
这是我的问题:如何控制托盘图标的位置?(即,相对于系统时间的位置 - 第一位置/"槽",第二位置/"槽"等).我记得看到一个演示(C#,如果内存服务),允许用户"向左移动图标"和"向右移动图标",但不记得它是如何完成的.
对于Windows 2000 - Windows 7,我想允许用户选择他们想要显示图标的位置.(我知道Windows 7处理系统托盘的东西有点不同,但还没有测试过).
感谢您的帮助.
Rob*_*edy 10
程序没有记录或支持的方法来控制其shell通知图标的位置.甚至没有什么保证它们会出现,或者如果它们确实出现,它们将出现在任何时间点附近,这样你的定位指令就没有意义了.
(我以前使用的程序劫持了部分或全部图标,并可选择在自己的窗口而不是时钟附近区域显示它们.这是TraySaver,作者是Mike Lin.如果你想看看他的黑客工作了.)
图标的位置不在您的控制之下.我给你的建议是不要试图让你的程序负起责任,特别是如果没有人真正从你的程序中请求过这样的功能.如果人们想要控制你的程序的图标位置,他们可能想控制其他程序的图标位置,在这种情况下问题比你大.
访问和修改shell通知区域是一种破坏性但可能.您首先需要找到顶级窗口:
var
Wnd: HWND;
begin
Wnd := FindWindow('Shell_TrayWnd', nil);
if IsWindow(Wnd) then
EnumChildWindows(Wnd, @FindTrayWnd, 0);
end;
Run Code Online (Sandbox Code Playgroud)
然后枚举其子项以查找托盘通知区域:
function FindTrayWnd(AWnd: HWND; AParam: LPARAM): BOOL; stdcall;
var
ClassName: string;
begin
SetLength(ClassName, 64);
SetLength(ClassName, GetClassName(AWnd, PChar(ClassName), 64));
Result := True;
if AnsiCompareText(ClassName, 'TrayNotifyWnd') = 0 then begin
EnumChildWindows(AWnd, @FindToolbar, 0);
Result := False;
end;
end;
Run Code Online (Sandbox Code Playgroud)
然后枚举其子项以查找带有通知图标的标准Windows工具栏.Windows消息用于获取或设置工具栏属性.由于工具栏位于另一个进程中,您需要使用ReadProcessMemory()并WriteProcessMemory()涉及涉及某种缓冲区的所有消息(例如获取按钮文本或按钮信息):
function FindToolbar(AWnd: HWND; AParam: LPARAM): BOOL; stdcall;
const
VMFLAGS = PROCESS_VM_OPERATION or PROCESS_VM_READ or PROCESS_VM_WRITE;
var
ClassName: string;
i, ButtonCount: integer;
ProcessId, BytesRead: Cardinal;
ProcessHandle: THandle;
ExplorerButtonInfo: PTBButton;
ButtonInfo: array of TTBButton;
begin
SetLength(ClassName, 64);
SetLength(ClassName, GetClassName(AWnd, PChar(ClassName), 64));
if AnsiCompareText(ClassName, 'ToolbarWindow32') = 0 then begin
GetWindowThreadProcessId(AWnd, @ProcessId);
ProcessHandle := OpenProcess(VMFLAGS, FALSE, ProcessId);
ExplorerButtonInfo := VirtualAllocEx(ProcessHandle, nil, SizeOf(TTBButton),
MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE);
if ExplorerButtonInfo <> nil then try
ButtonCount := SendMessage(AWnd, TB_BUTTONCOUNT, 0, 0);
SetLength(ButtonInfo, ButtonCount);
for i := 0 to ButtonCount - 1 do begin
SendMessage(AWnd, TB_GETBUTTON, i, LPARAM(ExplorerButtonInfo));
ReadProcessMemory(ProcessHandle, ExplorerButtonInfo, @ButtonInfo[i],
SizeOf(TTBButton), BytesRead);
end;
// manipulate the button info, use WriteProcessMemory() and SendMessage()
// to repopulate the toolbar
finally
VirtualFreeEx(ProcessId, ExplorerButtonInfo, SizeOf(TTBButton),
MEM_RELEASE);
end;
Result := False;
end else
Result := True;
end;
Run Code Online (Sandbox Code Playgroud)
您应该能够通过其名称识别通知图标的按钮,然后删除该按钮,然后将其插入所需位置.省略了所有错误处理,但这应该可以帮助您入门.