Windows获取系统托盘图标

       对于Win7系统,程序的托盘图标最终是放置在和XP一样的ToolbarWindow32工具条窗口,但是有两个地方,同样是ToolbarWindow32工具条窗口,父窗口是不一样的。在右下角可见区域,ToolbarWindow32工具条窗口的父窗口是SysPager窗口,遍历方法同XP一样。对于掩藏的ToolbarWindow32工具条窗口,必须通过点击桌面右下角的可见区域左边的一个按钮,才会显示出来,其父窗口则是一个叫做托盘溢出的窗口NotifyIconOverflowWindow。

     得到句柄的代码:

HWND FindTrayToolbarWindow()
{
    HWND hWnd = ::FindWindow(L"Shell_TrayWnd", NULL);
    if(hWnd)
    {
        hWnd = ::FindWindowEx(hWnd,NULL,L"TrayNotifyWnd", NULL);
        if(hWnd)
        {
            hWnd = ::FindWindowEx(hWnd,NULL,L"SysPager", NULL);
            if(hWnd)
            {
                hWnd = ::FindWindowEx(hWnd, NULL,L"ToolbarWindow32", NULL);
            }
        }
    }
    return hWnd;
}
//获取溢出托盘区窗口句柄
HWND FindNotifyIconOverflowWindow()
{
    HWND hWnd = NULL;

    hWnd = FindWindow(L"NotifyIconOverflowWindow", NULL);
    if (hWnd != NULL)
    {
        hWnd = FindWindowEx(hWnd, NULL, L"ToolbarWindow32", NULL);
    }

    return hWnd;
}

得到句柄后:

       给ToolbarWindow32句柄发送 TB_BUTTONCOUNT消息得到托盘窗口TBBUTTON的个数 -> 通过得到总数,用FOR循环,向每个BUTTON发送TB_GETBUTTON消息 -> 用ReadProcessMemory读取每个TBBUTTON结构 -> 再通过TBBUTTON.dwData 得到TRAYDATA结构。

TB_GETBUTTON的SendMessage是跨进程操作,lAddress要在ToolbarWindow32所在的进程中申请

void EnumNotifyWindow(HWND hWnd)
{
    DWORD dwProcessId = 0;
    GetWindowThreadProcessId(hWnd,&dwProcessId);

    HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,FALSE, dwProcessId);
    if ( hProcess==NULL ){
        return;
    }
    LPVOID lAddress = VirtualAllocEx(hProcess, 0, 4096, MEM_COMMIT, PAGE_READWRITE);
    if ( lAddress==NULL ){
        return;
    }

    DWORD lTextAdr = 0;
    BYTE buff[1024] = {0};

    HWND hwnd = NULL;
    UINT uid;
    UINT uCallbackMessage;
    int nDataOffset = sizeof(TBBUTTON) - sizeof(INT_PTR) - sizeof(DWORD_PTR);
    int nStrOffset = 18;
    //是否是64位
#ifdef _WIN64
#else
    nDataOffset+=4;
    nStrOffset+=6;
#endif

   //得到圖標個數
    int lButton = SendMessage(hWnd, TB_BUTTONCOUNT, 0, 0);
    for (int i = 0; i < lButton; i++)
    {
        //得到TBBUTTON的地址
        SendMessage(hWnd, TB_GETBUTTON, i, (LPARAM)lAddress);

        //读TBBUTTON的地址
        ReadProcessMemory(hProcess,lAddress,&tb,sizeof(TBBUTTON),0);

        //得到TRAYDATA的地址
        ReadProcessMemory(hProcess, (LPVOID)((DWORD)lAddress + nDataOffset), &lTextAdr, 4, 0);
        if ( lTextAdr!=-1 ) {
            //讀TRAYDATA的地址
            ReadProcessMemory(hProcess, (LPCVOID)lTextAdr, buff, 1024, 0);
            hwnd = (HWND)(*((DWORD*)buff));
            uid = (UINT)(*((UINT*)buff+1));
            qInfo()<<uid;
            uCallbackMessage = (UINT)(*((DWORD*)buff+2));
            qInfo()<<uCallbackMessage;

            QString strPath = QString().fromWCharArray((WCHAR *)buff + nStrOffset);
            qInfo()<<strPath;
            QString strTitle = QString().fromWCharArray((WCHAR *)buff + nStrOffset + MAX_PATH);
            qInfo()<<strTitle;

            hIcon = (HICON)(*((DWORD*)buff+6));

        }
    }

    VirtualFreeEx(hProcess, lAddress, 4096, MEM_RELEASE);
    CloseHandle(hProcess);
}

通过TB_GETBUTTON得到的是TBBUTTON结构,其dwData指向的是一个TRAYDATA

typedef struct _TBBUTTON {
int iBitmap;
int idCommand;
BYTE fsState;
BYTE fsStyle;
#ifdef _WIN64
BYTE bReserved[6]; // padding for alignment
#elif defined(_WIN32)
BYTE bReserved[2]; // padding for alignment
#endif
DWORD_PTR dwData;
INT_PTR iString;
} TBBUTTON, NEAR* PTBBUTTON, *LPTBBUTTON;
typedef const TBBUTTON *LPCTBBUTTON;
//不是全对,hicon 应该还要靠后一个指针
struct TRAYDATA
{
 HWND hWnd;
 UINT uID;
 UINT uCallbackMessage;
 DWORD Reserved1[2];
 HICON hIcon;
 DWORD Reserved2[3];
 TCHAR szExePath[MAX_PATH];
 TCHAR szTip[128];
};

   

托盘的本质是一个win32_toolbar,找到窗口句柄然后就可以调用api得到按钮。对其发消息进行图标隐藏,移动之类的可以成功, 但用下面的方式给toolbox发送点击事件则一直没有成功。

 PostMessage(GetParent(hwndTB), WM_COMMAND, idCommand, (LPARAM)hwndTB);

  hwndTB:ToolbarWindow32的句柄

参考:

https://www.codeproject.com/Articles/10807/Shell-Tray-Info-Arrange-your-system-tray-icons

http://www.qingfengju.com/article.asp?id=294

https://blog.csdn.net/bzhxuexi/article/details/25238523

https://bbs.csdn.net/topics/390253965

猜你喜欢

转载自blog.csdn.net/fxy0325/article/details/84664527