为了在某计算机上建立一个隐蔽的Wifi,所以面对可恶的托盘图标,令我不得不考虑写个程序将其Hide掉,以免后患。
于是开始了大量的谷歌与 百度,看下前人是如何去做的。站在巨人的肩膀不是看得更远嘛。
首先我们了解到托盘区似乎是个窗口性质的东西,于是乎,操起Spy++查查到底是什么情况。
很清晰的窗口所属结构,只要我们一次通过FindWindow()和FindWindowEx()依次从窗口类为Shell_TrayWnd ->SysPager ->ToolbrWindow32,得到最终句柄,然后通过发送 TB_BUTTONCOUNT消息得到托盘窗口TBBUTTON的个数 -> 通过得到总数,遍历所有按钮,向每个BUTTON发送TB_GETBUTTON消息 获得按钮 -> 用ReadProcessMemory读取每个TBBUTTON结构 -> 再通过TBBUTTON.dwData 得到TRAYDATA结构。
这里不得不提一下TRAYDATA,据说这是一个从未公开的结构
1 struct TRAYDATA { 2 HWND hwnd; 3 UINT uID; 4 UINT uCallbackMessage; 5 DWORD Reserved[2]; 6 HICON hIcon; 7 };
可我们怎么找到他呢?他的信息在TBBUTON结构中的dwData
1 typedef struct { 2 int iBitmap; 3 int idCommand; 4 BYTE fsState; 5 BYTE fsStyle; 6 #ifdef _WIN64 7 BYTE bReserved[6]; 8 #else 9 #if defined(_WIN32) 10 BYTE bReserved[2]; 11 #endif 12 #endif 13 DWORD_PTR dwData; 14 INT_PTR iString; 15 } TBBUTTON, *PTBBUTTON, *LPTBBUTTON;
然后我们可以根据他获得信息填充下NOTIFYICONDATA结构体
1 //系统定义结构体 2 typedef struct _NOTIFYICONDATA 3 { 4 DWORD cbSize; //以字节为单位的这个结构的大小 5 HWND hWnd; //接收托盘图标通知消息的窗口句柄 6 UINT uID; //应用程序定义的该图标的ID号 7 UINT uFlags; //设置该图标的属性 8 UINT uCallbackMessage; //应用程序定义的消息ID号,此消息传递给hWnd 9 HICON hIcon; //图标的句柄 10 char szTip[64]; //鼠标停留在图标上显示的提示信息 11 } NOTIFYICONDATA, *PNOTIFYICONDATA; 12 13 /* 14 该结构中,成员uFlags可以使下列之一或组合: 15 16 NIF_ICON 设置成员hIcon有效 17 NIF_MESSAGE 设置成员uCallbackMessage有效 18 NIF_TIP 设置成员szTip有效 19 */
以便我们使用Shell_NotifyIcon()函数时调用,他是在托盘上增加,删掉等作用的函数。
1 WINSHELLAPI BOOL WINAPI Shell_NotifyIcon( DWORD dwMessage, PNOTIFYICONDATA pnid); 2 /* 3 ---Pnid是NOTIFYICONDATA结构的指针; dwMessage是被传递的消息,可以是以下消息之一: 4 5 NIM_ADD 增加图标 6 NIM_DELETE 删除图标 7 NIM_MODIFY 修改图标 8 */
但是有的时候我们可能不希望删除所有的托盘图标,所以我们要判断下他的文本,在TRAYDATA结构体中的szTip来确认是哪个按钮,如果是他就删掉他,这个判断加在执行Shell_NotifyIcon()前面,如果符合,则执行Shell_NotifyIcon()。
完整代码是:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 struct TRAYDATA 2 { 3 HWND hWnd; 4 UINT uID; 5 UINT uCallbackMessage; 6 DWORD Reserved1[2]; 7 HICON hIcon; 8 DWORD Reserved2[3]; 9 TCHAR szExePath[MAX_PATH]; 10 TCHAR szTip[128]; 11 }; 12 13 //获取托盘可见区域句柄 14 HWND hWnd = NULL; 15 hWnd = ::FindWindow(_T("Shell_TrayWnd"), NULL); 16 hWnd = ::FindWindowEx(hWnd, NULL, _T("TrayNotifyWnd"), NULL); 17 hWnd = ::FindWindowEx(hWnd, NULL, _T("SysPager"), NULL); 18 hWnd = ::FindWindowEx(hWnd, NULL, _T("ToolbarWindow32"), NULL); 19 20 //获取进程 ID 21 DWORD dwPID = 0; 22 ::GetWindowThreadProcessId(hWnd, &dwPID); 23 DWORD dwCount = ::SendMessage(hWnd, TB_BUTTONCOUNT, NULL, NULL); 24 25 26 27 //打开进程 28 HANDLE hProc = ::OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, dwPID); 29 30 //申请内存 31 LPVOID pTB = ::VirtualAllocEx(hProc, NULL, sizeof(TBBUTTON), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); 32 33 TBBUTTON tb; 34 TRAYDATA td; 35 NOTIFYICONDATA nid; 36 for (DWORD i = 0; i < dwCount; i++) 37 { 38 39 ::ReadProcessMemory(hProc, pTB, &tb, sizeof(TBBUTTON), NULL); 40 41 //获取 TRAYDATA 信息 42 ::ReadProcessMemory(hProc, (LPVOID)tb.dwData, &td, sizeof(TRAYDATA), NULL); 43 //填充 NOTIFYICONDATA 结构体,调用 Shell_NotifyIcon 函数 44 //在这里可以利用判断TRAYDATA结构体中的szTip来确认是哪个按钮,然后删掉他 45 nid.cbSize = sizeof(NOTIFYICONDATA); 46 nid.hWnd = td.hWnd; 47 nid.uID = td.uID; 48 nid.uCallbackMessage = td.uCallbackMessage; 49 nid.hIcon = td.hIcon; 50 memcpy(nid.szTip, td.szTip, sizeof(nid.szTip)); 51 nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; 52 ::Shell_NotifyIcon(NIM_DELETE, &nid); //删除图标(注意这里是删除而不是隐藏) 53 //::Shell_NotifyIcon(NIM_ADD, &nid); //显示图标 54 } 55 56 //释放内存 57 ::VirtualFreeEx(hProc, pTB, sizeof(TBBUTTON), MEM_FREE); 58 VirtualFreeEx(hPro,pText,len,MEM_COMMIT); 59 60 //关闭进程句柄 61 ::CloseHandle(hProc)
参考于:http://www.codeproject.com/KB/applications/ShellTrayInfo.aspx