2008-11-05 53 views
7

有沒有一種方法(在C#中)訪問系統托盤? 我不是在討論製作通知圖標。 我想通過托盤中的項目進行迭代(我猜測通過這些過程,但我不知道如何確定托盤中的實際內容以及過程),並且還將圖標顯示在我的項目中自己的用戶界面。Systray訪問

回答

5

對Win32 interop有什麼看法?我發現C/Win32 code可能會爲你做詭計。 (其實,它看起來像一個有趣的問題,所以我可能會嘗試自己解決它,而不是現在)。

魔術似乎是他得到的句柄系統托盤中的窗口:

NotifyWnd = FindWindowEx(SysTray, 0, "TrayNotifyWnd", 0);

然後,他將在其消息泵鉤:

hHook=SetWindowsHookEx(WH_CALLWNDPROC,HOOKPROC(MsgProc), 
     hInstance,dwExplorerThreadId);
消息泵鉤期間

然後回調中,他得到一個參考有關窗口的一些指針數據:

TWDataT* twd=(TWDataT*)GetWindowLong(NotifyWnd,0);

的myster y是那麼他的循環:

 pTWIconDataT p=COMCTL32_332(twd->iconsInfo,i);

COMCTL32_332與GetProcAddress的和點定義爲序數的Comctl32.dll 332 - 根據我的依賴瀏覽器,那是DPA_GetPtr,從動態指針數組中獲取數據的檢查。我並不熟悉幕後發生的事情,但似乎並非完全不可能。

我打算自己玩一下,但希望這是一個讓你開始的好地方。 :)

1

Mathias Rauen的madCollection(對於Delphi不是c#)可以列出Tray Icons

而且還有一個命令行工具:Windows System Tray Scan Utility

我也寫(未公佈),我自己的程序在Delphi(不Delphi.NET),不使用madCollection,這說明托盤圖標,進程名稱,工具提示和其他信息,但它並不完美。有幾個圖標無法顯示(即使列出了其他信息),並且無法在Windows 9x下顯示任何圖標。我沒有在Vista下測試過它。

1

在Windows 2000中,系統托盤的圖標是一個簡單的工具欄控件(窗口類「ToolbarWindow32」),這是「TrayNotifyWnd」窗口的孩子,所以你可以把它的工具欄消息,如TB_BUTTONCOUNTTB_GETBUTTON

需要注意的是:TB_GETBUTTON等需要指向緩衝區的指針才能存儲結果,因此需要緩衝區到位於SysTray進程本身。這要求您擁有正確的權限,並且您使用VirtualAllocEx來分配內存。

我還沒有在XP或Vista上試過它。我希望事情發生了變化。

0

在Windows 2000/XP中完成它是完全可能的。 不幸的是在Windows 7中它似乎不再可行。

訣竅很簡單:你必須找到盤窗口句柄:

 static IntPtr GetSystemTrayHandle() 
    { 
     IntPtr hWndTray = FindWindow("Shell_TrayWnd", null); 
     if (hWndTray != IntPtr.Zero) 
     { 
      hWndTray = FindWindowEx(hWndTray, IntPtr.Zero, "TrayNotifyWnd", null); 
      if (hWndTray != IntPtr.Zero) 
      { 
       hWndTray = FindWindowEx(hWndTray, IntPtr.Zero, "SysPager", null); 
       if (hWndTray != IntPtr.Zero) 
       { 
        hWndTray = FindWindowEx(hWndTray, IntPtr.Zero, "ToolbarWindow32", null); 
        return hWndTray; 
       } 
      } 
     } 

     return IntPtr.Zero; 
    } 

由於這個窗口是ToolbarWindow32,那麼你必須在整個使用WinAPI的按鈕來枚舉。唯一的問題是,用於此的所有結構應在目標進程的地址空間分配,所以你不得不使用這樣的事情:

private static unsafe bool GetTBButton(IntPtr hToolbar, int i, ref TBBUTTON tbButton, ref string text, ref IntPtr ipWindowHandle) 
    { 
     // One page 
     const int BUFFER_SIZE = 0x1000; 

     byte[] localBuffer = new byte[BUFFER_SIZE]; 

     UInt32 processId = 0; 
     UInt32 threadId = User32.GetWindowThreadProcessId(hToolbar, out processId); 

     IntPtr hProcess = Kernel32.OpenProcess(ProcessRights.ALL_ACCESS, false, processId); 
     if (hProcess == IntPtr.Zero) { Debug.Assert(false); return false; } 

     IntPtr ipRemoteBuffer = Kernel32.VirtualAllocEx(
      hProcess, 
      IntPtr.Zero, 
      new UIntPtr(BUFFER_SIZE), 
      MemAllocationType.COMMIT, 
      MemoryProtection.PAGE_READWRITE); 

     if (ipRemoteBuffer == IntPtr.Zero) { Debug.Assert(false); return false; } 

     // TBButton 
     fixed (TBBUTTON* pTBButton = &tbButton) 
     { 
      IntPtr ipTBButton = new IntPtr(pTBButton); 

      int b = (int)User32.SendMessage(hToolbar, TB.GETBUTTON, (IntPtr)i, ipRemoteBuffer); 
      if (b == 0) { Debug.Assert(false); return false; } 

      // this is fixed 
      Int32 dwBytesRead = 0; 
      IntPtr ipBytesRead = new IntPtr(&dwBytesRead); 

      bool b2 = Kernel32.ReadProcessMemory(
       hProcess, 
       ipRemoteBuffer, 
       ipTBButton, 
       new UIntPtr((uint)sizeof(TBBUTTON)), 
       ipBytesRead); 

      if (!b2) { Debug.Assert(false); return false; } 
     } 

     // button text 
     fixed (byte* pLocalBuffer = localBuffer) 
     { 
      IntPtr ipLocalBuffer = new IntPtr(pLocalBuffer); 

      int chars = (int)User32.SendMessage(hToolbar, TB.GETBUTTONTEXTW, (IntPtr)tbButton.idCommand, ipRemoteBuffer); 
      if (chars == -1) { Debug.Assert(false); return false; } 

      // this is fixed 
      Int32 dwBytesRead = 0; 
      IntPtr ipBytesRead = new IntPtr(&dwBytesRead); 

      bool b4 = Kernel32.ReadProcessMemory(
       hProcess, 
       ipRemoteBuffer, 
       ipLocalBuffer, 
       new UIntPtr(BUFFER_SIZE), 
       ipBytesRead); 

      if (!b4) { Debug.Assert(false); return false; } 

      text = Marshal.PtrToStringUni(ipLocalBuffer, chars); 

      if (text == " ") text = String.Empty; 
     } 

遺憾的是在Windows 7 tbButton.dwData等於0,所以你可以」 t找到NotifyIcon和目標進程之間的任何關聯