2008-11-05 4 views
7

시스템 트레이에 액세스 할 수있는 방법이 있습니까? 알림 아이콘을 만드는 것에 대해 이야기하는 것이 아닙니다. 용지함의 항목을 반복하고 싶습니다 (프로세스를 통해 추측 할 수 있지만 실제로 용지함에 무엇이 있는지, 프로세스는 무엇인지 확인하는 방법을 알지 못합니다). 자신의 UI.시스 트레이 액세스

답변

5

Win32 interop에 대해 어떻게 생각하십니까? 트릭을 할 수있는 C/Win32 code을 발견했습니다. (실제로, 그것은 흥미로운 문제처럼 보입니다. 그래서 나는 지금 그것을 다루려고 노력할 것입니다, 지금은 아닙니다). 메시지 펌프 후크 동안 다음

hHook=SetWindowsHookEx(WH_CALLWNDPROC,HOOKPROC(MsgProc), 
     hInstance,dwExplorerThreadId);

:

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

그런 다음 그는 그 메시지 펌프에 후크를 설정합니다

마법은 그 시스템 트레이의 윈도우에 대한 핸들을 얻을 수 있다는 것으로 보인다

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

myster : 콜백, 그는 창에 대한 몇 가지 포인터 데이터에 대한 참조를 가져옵니다 - 동적 포인터 어레이로부터 데이터를 취득 종속성 뷰어 즉 DPA_GetPtr있어, 내 검사에있어서

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

COMCTL32_332가의 Comctl32.dll 332 서수 GetProcAddress를 포인트로 정의되며 : Y는 자신의 루프이다. 나는 그곳에서 일어나는 일에 익숙하지 않지만, 의문의 여지가없는 것처럼 보인다.

나는 이걸 가지고 약간 놀아 보겠다.하지만 시작하기에 좋은 곳이다. :)

1

Mathias Rauen의 madCollection (Delphi가 아닌 C#)은 Tray Icons을 나열 할 수 있습니다.

그리고 명령 행 도구가 : 나는 또한 (공개되지 않음) 델파이 (안 Delphi.NET) 내 자신의 프로그램을 작성했습니다 Windows System Tray Scan Utility

는, 트레이 아이콘, 프로세스 이름, 툴팁 및 표시 madCollection을 사용하지 않는 다른 정보하지만 완벽하지는 않습니다. 표시 할 수없는 몇 가지 아이콘이 있으며 (다른 정보도 나열되어 있음) Windows 9x에서는 아이콘을 표시 할 수 없습니다. 나는 비스타에서 전혀 테스트하지 않았다.

1

Windows 2000에서 시스템 트레이 아이콘은 "TrayNotifyWnd"창의 자식 인 일반 도구 모음 컨트롤 (창 클래스 "ToolbarWindow32")에 있으므로 TB_BUTTONCOUNTTB_GETBUTTON과 같은 도구 모음 메시지를 보낼 수 있습니다 .

주의해야 할 사항 : 결과를 저장할 버퍼의 포인터가 필요한 TB_GETBUTTON과 같은 메시지는 의 버퍼가 시스템 트레이 프로세스 자체에 있어야합니다.. 이를 위해서는 올바른 사용 권한이 있어야하며 VirtualAllocEx을 사용하여 메모리를 할당해야합니다.

XP 나 Vista에서는 사용하지 않았습니다. 나는 변화가 일어날 것을 기대한다.

0

Windows 2000/XP에서 완벽하게 구현할 수있었습니다. 불행히도 Windows 7에서는 더 이상 실행 가능하지 않은 것으로 보입니다.

트릭은 간단했다 : 당신은 트레이 창 핸들을 찾을 수있다 :이 창은 ToolbarWindow32입니다

 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; 
    } 

때문에 다음 WinAPI를을 사용하여 버튼을 통해 열거 할 수 있습니다. '그래서 당신이 할 수있는, 불행하게도 윈도우 7 tbButton.dwData 0 동일에

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; 
     } 

: 유일한 문제는이에 사용 된 모든 구조 대상 프로세스의 주소 공간에 할당해야한다는 것입니다, 그래서 당신은 같은 것을 사용해야합니다 NotifyIcon과 대상 프로세스 간의 연결을 찾을 수 없음

관련 문제