我有几个旧的应用程序(在Delphi中),由于各种原因使用系统托盘图标。大多数人正在使用AppControls TacTrayIcon或其他类似的组件。
以下是我的问题:如何控制托盘图标的位置? (即,相对于系统时间的位置 - 第一位置/“槽”,第二位置/“槽”等)。我记得看到一个演示(C#,如果内存服务),允许用户“向左移动图标”和“向右移动图标”,但不记得它是如何完成的。
我想让用户选择他们想要显示图标的位置,对于Windows 2000 - Windows 7.(我知道Windows 7处理系统托盘的东西有点不同,但没有测试出来尚未)。
感谢您的帮助。
答案 0 :(得分:10)
程序无法记录或支持其控制shell通知图标位置的方法。甚至没有什么能保证它们会出现,或者它们确实出现,它们会出现在任何时间点附近,这样你的定位指令就没有任何意义。
(我以前使用的程序劫持了部分或全部图标,并可选择将它们显示在自己的窗口中,而不是显示在时钟附近的区域。由Mike Lin提供TraySaver。来源是如果你想看看他的黑客如何工作,你可以使用。)
图标的位置不在您的控制之下。我给你的建议是不要试图让你的程序负起责任,特别是如果没有人真正从你的程序中请求过这样的功能。如果人们想要控制你的程序的图标位置,他们可能想要控制其他程序的图标位置,在这种情况下,问题比你还要大。
答案 1 :(得分:6)
访问和修改shell通知区域是hackish但可能。您首先需要找到顶级窗口:
var
Wnd: HWND;
begin
Wnd := FindWindow('Shell_TrayWnd', nil);
if IsWindow(Wnd) then
EnumChildWindows(Wnd, @FindTrayWnd, 0);
end;
然后枚举其子项以查找托盘通知区域:
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;
然后枚举其子项以查找带有通知图标的标准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;
您应该能够通过其名称识别通知图标的按钮,然后删除该按钮,然后将其插入所需位置。省略了所有错误处理,但这应该让你开始。
答案 2 :(得分:1)
看看this article on CodeProject,希望它有所帮助。
此解决方案的兼容性非常有限,根本不推荐。