How to get the processes that have systray icon

只谈情不闲聊 提交于 2019-12-04 07:32:13

I checked the application on 32bit and I saw that the dwData != 0. This helped me to understand that the problem is when working on 64bit.

I replaced public UInt32 dwData; with public UInt64 dwData;.

    [ StructLayout( LayoutKind.Sequential ) ]
    internal struct TBBUTTON 
    {
        public Int32 iBitmap;
        public Int32 idCommand;
        public byte fsState;
        public byte fsStyle;
//      [ MarshalAs( UnmanagedType.ByValArray, SizeConst=2 ) ]
//      public byte[] bReserved;
        public byte bReserved1;
        public byte bReserved2;
       // public UInt32 dwData;
        public UInt64 dwData;
        public IntPtr iString;
    };  

The dwData is now larger than zero.
I succeed to get the windows handle of the button associated to the process and get the process pid:

  // window handle
  fixed (byte* pLocalBuffer = localBuffer)
  {
   ...
   ipWindowHandle = new IntPtr(iWindowHandle);

   threadId = User32.GetWindowThreadProcessId(ipWindowHandle, out processId);
   data.setProcessPid(processId);
  }

And the final result:

This solution doesn't find processes that are associated with hidden system tray icons, this is a new problem that I will need to explore :) .

New refernces that helped me to find the idea to this solution:
http://www.codeproject.com/Articles/10807/Shell-Tray-Info-Arrange-your-system-tray-icons

Which was the comment of someone named "mklencke" that gave code for 64bit:

typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);

BOOL IsWow64()
{
    static bool isset = false;
    static BOOL bIsWow64 = FALSE;

    if (isset) {
        return bIsWow64;
    }

    //IsWow64Process is not available on all supported versions of Windows.
    //Use GetModuleHandle to get a handle to the DLL that contains the function
    //and GetProcAddress to get a pointer to the function if available.

    LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
        GetModuleHandle(TEXT("kernel32")),"IsWow64Process");

    if(NULL != fnIsWow64Process)
    {
        if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
        {
            //TODO handle error?
            return FALSE;
        }
    }

    isset = true;
    return bIsWow64;
}

typedef struct _TBBUTTON64 {
    int iBitmap;
    int idCommand;
    BYTE fsState;
    BYTE fsStyle;
    BYTE bReserved[6];
    DWORD64 dwData;
    DWORD64 iString;
} TBBUTTON64, NEAR* PTBBUTTON64, *LPTBBUTTON64;
typedef const TBBUTTON64 *LPCTBBUTTON64;

bool EnumSystemTray() { 
    bool bFound = false;

    // find system tray window
    HWND trayWnd = FindWindow(_T("Shell_TrayWnd"), NULL);
    if (trayWnd) {
        trayWnd = FindWindowEx(trayWnd, NULL,_T("TrayNotifyWnd"), NULL);
        if (trayWnd) {
            trayWnd = FindWindowEx(trayWnd, NULL,_T("SysPager"), NULL);
            if (trayWnd) {              
                trayWnd = FindWindowEx(trayWnd, NULL,_T("ToolbarWindow32"), NULL);
                bFound = true;
            }
        }
    }

    ASSERT(bFound);

    DWORD dwTrayPid;
    GetWindowThreadProcessId(trayWnd, &dwTrayPid);

    int count = (int) SendMessage(trayWnd, TB_BUTTONCOUNT, 0, 0);

    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwTrayPid);
    if (!hProcess) {
        return true;
    }

    BOOL bIsWow64 = IsWow64();

    SIZE_T dwSize = bIsWow64 ? sizeof(TBBUTTON64) : sizeof(TBBUTTON);
    LPVOID lpData = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
    if (!lpData) {
        return true;
    }

    // Loop through all systray icons
    for (int i = 0; i < count; i++) {
        HWND hwnd32;

        SendMessage(trayWnd, TB_GETBUTTON, i, (LPARAM)lpData);
        if ( bIsWow64 ) {
            // Try to read memory from 64-bit Explorer process. Hope the address of the traybar data is below 4GB

            TBBUTTON64 tbb;
            if (!ReadProcessMemory(hProcess, lpData, (LPVOID)&tbb, sizeof(TBBUTTON64), NULL)) {
                continue;
            }

            DWORD64 hwnd;

            // First member of TRAYDATA structure is HWND, so we can just use the address of the struct to read the member
            if (!ReadProcessMemory(hProcess, (LPCVOID)tbb.dwData, (LPVOID)&hwnd, sizeof(DWORD64), NULL)) {
                continue;
            }

            // Hope this does not get truncated, but we shouldn't have that many windows
            hwnd32 = (HWND)hwnd;
        } else {
            TBBUTTON tbb;
            if (!ReadProcessMemory(hProcess, lpData, (LPVOID)&tbb, sizeof(TBBUTTON), NULL)) {
                continue;
            }

            DWORD32 hwnd;

            // First member of TRAYDATA structure is HWND, so we can just use the address of the struct to read the member
            if (!ReadProcessMemory(hProcess, (LPCVOID)tbb.dwData, (LPVOID)&hwnd, sizeof(DWORD32), NULL)) {
                continue;
            }

            hwnd32 = (HWND)hwnd;
        }

        DWORD dwProcessId = 0;
        GetWindowThreadProcessId(hwnd32, &dwProcessId);

        // XXX - DO SOMETHING WITH dwProcessId
    }

    VirtualFreeEx(hProcess, lpData, NULL, MEM_RELEASE);

    return true;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!