2

(Delphiで)作成した古いアプリがいくつかありますが、さまざまな理由でシステムトレイアイコンを使用しています。ほとんどがAppControlsTacTrayIconまたは他の同様のコンポーネントを使用しています。

これが私の質問です:トレイアイコンの位置をどのように制御しますか?(つまり、システム時間に対して、たとえば、1番目の位置/「スロット」、2番目の位置/「スロット」など)。ユーザーが「アイコンを左にシフト」および「アイコンを右にシフト」できるデモ(メモリが提供されている場合はC#)を見たことを思い出しますが、それがどのように行われたかは思い出せません。

Windows 2000-Windows 7の場合、ユーザーがアイコンを表示する位置を選択できるようにしたいと思います(Windows 7はシステムトレイのものを少し異なる方法で処理することを理解していますが、まだテストしていません)。

助けてくれてありがとう。

4

3 に答える 3

10

プログラムがシェル通知アイコンの位置を制御するための文書化された方法やサポートされている方法はありません。それらがまったく表示されることを保証するものは何もありません。また、表示される場合でも、配置の指示が意味をなすように、時計の近くのどこかに表示されることを保証するものはありません.

(以前は、一部またはすべてのアイコンをハイジャックし、必要に応じて、時計の近くの領域ではなく独自のウィンドウに表示するプログラムを使用していました。それは、Mike Lin によるTraySaver でした。方法を確認したい場合は、ソースを入手できます。彼のハックはうまくいきました。)

アイコンの位置は制御できません。あなたへの私のアドバイスは、あなたのプログラムの責任にしようとしないことです。特に、そもそもあなたのプログラムにそのような機能を実際に要求した人がいない場合はなおさらです。人々があなたのプログラムのアイコンの場所を制御したい場合、おそらく他のプログラムのアイコンの場所を制御したいと思うでしょう。その場合、問題はとにかくあなたよりも大きくなります.

于 2009-12-28T23:22:38.143 に答える
6

シェル通知領域へのアクセスと変更はハックですが、可能です。最初に最上位ウィンドウを見つける必要があります。

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;

名前で通知アイコンのボタンを識別し、そのボタンを削除してから、目的の位置に挿入できるはずです。エラー処理はすべて省略されていますが、これで作業を開始できます。

于 2009-12-29T09:54:12.147 に答える
1

CodeProjectに関するこの記事をご覧ください。お役に立てば幸いです。

このソリューションの互換性は非常に限られているため、まったくお勧めできません。

于 2009-12-29T13:36:06.560 に答える