Windows System Tray Icons - Control Position

I have several old applications that I wrote (in Delphi) that, for various reasons, use the icon in the system tray. Most of them use AppControls TacTrayIcon or some other similar component.

Here is my question: how to control the position of the tray icon? (that is, where it is, say, with respect to the system time - 1st position / "slot", 2nd position / "slot", etc.). I remember seeing a demo (C # if memory serves) that allowed the user to "shift the icon to the left" and "shift the icon to the right", but don’t remember how it was done.

I would like to allow the user to choose which position they want to display, for Windows 2000 - Windows 7. (I understand that Windows 7 processes the material in the system tray a little differently, but have not tested it yet).

Thanks for any help.

+2
source share
3 answers

There is no documented or supported way for programs to manage the positions of notification shell icons. There is even no guarantee that they will not appear at all, or if they appear, that they will appear somewhere near the clock, so your placement instructions will make some sense.

( , , , , . TraySaver, . , , .)

. - , ​​ . , , , , , .

+10

, . :

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;

, , . , .

+6

Check out this article in CodeProject , hope this helps.

This solution has very limited compatibility and is not recommended at all.

+1
source

All Articles