日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

一种清除windows通知区域“僵尸”图标的方案——问题分析

發布時間:2023/11/27 生活经验 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一种清除windows通知区域“僵尸”图标的方案——问题分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

通知區域名稱有趣的歷史

? ? ? ? 假如說到windows通知區域,可能很多人還是不清楚它是什么。如果改稱Tray區域,可能有人就懂了。如果再白話點,叫它“托盤”或者“系統托盤”,可能會有更多的人猜到它是windows什么部位。現在我們揭開它真實的面紗,以windows7系統為例,下圖就是它的通知區域。 (轉載請指明出于breaksoftware的csdn博客)


? ? ? ? 其實,我們叫通知區域為“托盤”或者“系統托盤”是錯誤的。這個錯誤并非來源于中文翻譯,而是來源于windows發展史上人們對其錯誤的認識。后來,這個命名也影響了中國一批程序員。我這兒要摘錄一個微軟老員工的回憶錄《The Old New Thing》(中文名《windows編程啟示錄》)一書中關于這個錯誤認識起源的一段,還是蠻有意思的。

? ? ? ? “后來,我們將通知圖標添加到任務欄中。”

? ? ? ? “我認為人們開始將通知區域叫作系統托盤是因為在Windows95中包含了一個systray.exe的程序,這個程序在通知區域中顯示了一些圖標,如音量控制,PCMCIA(在當時是叫這個名字)的狀態、電池的電量表等。如果你終止了systray.exe,那么這些通知圖標也將會消失。因此人們就認為,‘啊,systray程序一定是管理這些圖標的組件,我敢打賭這個組件的名字就叫作“系統托盤”’。于是這個誤解就形成了,而我們這十幾年來一直都在努力澄清這個誤解。”

? ? ? ? “更糟糕的是,其他的團隊(Shell之外的團隊)也錯誤地使用了這個詞,并且開始在他們自己的文檔和示例程序里面都使用了系統托盤這個詞,其中有一些地方甚至錯誤地聲稱系統托盤就是通知區域的正式名稱。”

? ? ? ? “有人可能會問,‘你為什么要關心這個名字的正誤?既然現在所有的人都叫這個名字,你也可以隨波逐流嘛。’”

? ? ? ? “如果每個人都叫錯了你的名字,你會樂意嗎?”

? ? ? ? 其實我覺得,如果微軟真的想徹底摒棄“系統托盤”這個名稱,最好是從現在做起,將通知區域的一些信息都修改成和Tray這個單詞無關。可是,我們使用Spy++查看Windows7任務欄的組成時就會發現,Tray這個單詞無處不在啊!



“僵尸圖標”

? ? ? ? 說了這么多歷史故事,我們再回到我們這篇博文要講述的問題上。其實這個問題,依舊是個歷史問題。還好,我發現vista之后的系統上,微軟已經意識并修復了這個設計缺陷。我們看下下面的場景

? ? ? ??

? ? ? ? 很多使用Windows的人可能都遇到過這個問題:通知區域出現了N個相同的“僵尸”圖標。如果我們有意或者無意讓光標劃過這些圖標時,這些圖標會悄然消失。我們對這種現象,往往是疑惑一下就拋之腦后。然而,目前我在項目中就接到一個需求:把這些“僵尸”圖標自動消失。出于我們產品的設計,我們存在出現這么多“僵尸”圖標的場景,于是為了優化用戶體驗,我需要找到一種方法去解決這種體驗問題。


通知區域圖標的正常生死過程

? ? ? ? 首先要分析一下這個問題出現的原因。一般來說,一個程序在創建時,可能會在通知區域創建一個圖標。

一般初始化圖標

? ? ? ? 創建圖標之前,我們需要初始化一個圖標

NOTIFYICONDATA m_NotifyIcon;
……
m_NotifyIcon.cbSize = sizeof(m_NotifyIcon);
m_NotifyIcon.uFlags = NIF_ICON | NIF_TIP;
m_NotifyIcon.uVersion = NOTIFYICON_VERSION; // xp
m_NotifyIcon.hWnd = m_hWnd;
m_NotifyIcon.hIcon = m_hIcon;
std::wstring wstrInfo = L"中A英1文"; // 故意取一個晦澀的名字
wmemcpy_s(m_NotifyIcon.szTip, ARRAYSIZE(m_NotifyIcon.szTip), wstrInfo.c_str(), wstrInfo.length()+1 );

? ? ? ?這個地方需要注意的是下面幾個參數:

  1. uFlags。我們只是設置了NIF_ICON和NIF_TIP,因為我們需要讓我們的通知區域圖標變得與眾不同,故通過指定這兩個標志分別告知系統:我們要設定圖標和Tip文字。這個屬性我們會在處理Windows7系統上“僵尸”圖標的時候再次提起。
  2. hWnd。因為我們圖標要相應用戶的點擊,并將相應消息傳遞給我們主窗口,所以我們此時要綁定主窗口句柄。這個屬性我們會在未來介紹一個特定場景時再次提到。
  3. szTip。我們故意給我們這個圖標取了一個晦澀的Tip,這樣我們在之后查找“僵尸圖標”時將有據可憑。

圖標添加到通知區域

? ? ? ? 圖標初始化后,我們要將圖標增加到通知區域
Shell_NotifyIcon(NIM_ADD, &m_NotifyIcon);

? ? ? ? 這個圖標是可以表明“這個進程還活著”;而且在無界面展現時,讓用戶方便喚起界面或者執行相應的功能。比如QQ的通知區域圖標,它的存在表明QQ進程還是存在的。我們可以左鍵雙擊之,可以讓主界面展現出來;還可以右擊之,可以出現很多快捷功能鍵


圖標從通知區域剔除 ? ? ? ?

? ? ? ? 相應的,如果進程退出,應該通知系統通知區域:要將我設置的通知區域圖標刪除,因為我馬上要退出了。

Shell_NotifyIcon(NIM_DELETE, &m_NotifyIcon);

? ? ? ? 如果一切都如此按照規律的“正常生死”,也就沒有之前提出的問題。可是,出于策略考慮以及一些異常情況,進程的意外死亡還是不可避免的。這樣,如果出現連續的意外死亡場景,系統通知區域就會殘留很多“僵尸”圖標。為了大戰這些“僵尸”,我們需要找到這些“僵尸”的家,然后對“僵尸”各個擊破。于是,我們要看下各系統下通知區域的樹狀結構圖。

XP、Win7下通知區域的結構

? ? ? ? 先使用SPY++看下XP下任務欄即通知區域的結構

      #32769 (桌面)- Shell_TrayWnd- Button- TrayNotifyWnd- TrayClockWClass- SysPager- ToolbarWindow32(我們關心的,其直接顯示在桌面上)- Button- CiceroUIWndFrame- MSTaskSwWClass- ToolbarWindow32- ReBarWindow32

? ? ? ? SysPager下類名為ToolbarWindow32的控件就是系統通知區域。非常慶幸,XP下只有這么一個通知區域,而且這個通知區域一直是可見的(Win7下有個不可見的通知區域)。

? ? ? ? 再看下Win7的通知區域結構

#32769 (桌面)- Shell_TrayWnd- TrayNotifyWnd- TrayClockWClass- TrayShowDesktopButtonWClass- SysPager- ToolbarWindow32(我們關心的,其直接顯示在桌面上)- ToolbarWindow32(其隱藏在桌面上,通過SendTimeout發送TB_BUTTONCOUNT不能獲取其個數)- Button- ReBarWindow32- CiceroUIWndFrame- MSTaskSwWClass- MSTaskListWClass
? ? ? ? Win7的通知區域相對于XP有點復雜,其中我們一直可見的通知區域的樹狀結構和XP上是一致的。但是Win7上多出了一個隱藏的通知區域,它和SysPager同級


? ? ? ? 針對XP和Win7上都可見的通知區域,我們可以通過如下代碼找到相應區域去清理

VOID CKillRunProcessDlg::VisitNotificationArea()
{HWND hwndChildAfter = NULL;DWORD dwMaxLoopCount = MAXLOOPCOUNT;do {// 保守性編程,防止死循環dwMaxLoopCount--;HWND hTrayWnd = NULL;hTrayWnd = ::FindWindowEx( NULL, hwndChildAfter, L"Shell_TrayWnd", NULL);if ( NULL == hTrayWnd ) {break;}// 找到了窗口類為 Shell_TrayWnd的窗口,// 但是不保證找到的就是Notification所在區域的,// 所以記錄下當前找到的,之后繼續找hwndChildAfter = hTrayWnd;HWND hTrayNotifyWnd = ::FindWindowEx(hTrayWnd, NULL, L"TrayNotifyWnd", NULL );if ( NULL == hTrayNotifyWnd ) {// 繼續找符合條件的Shell_TrayWnd類,然后再在其下找類為TrayNotifyWnd的子窗口continue;}// 這個窗口只能在Win7系統中可以找到HWND hToolBar32Ex = ::FindWindowEx( hTrayNotifyWnd, NULL, L"ToolbarWindow32", NULL );// 在win7 xp下都可以找到該樹結構HWND hSysPager = ::FindWindowEx( hTrayNotifyWnd, NULL, L"SysPager", NULL );HWND hToolBar32Showed = NULL;if ( NULL != hSysPager ) {  hToolBar32Showed = ::FindWindowEx( hSysPager, NULL, L"ToolbarWindow32", NULL );}else {// 找不到該樹結構// 則繼續找符合條件的Shell_TrayWnd類,然后再在其下找類為TrayNotifyWnd的子窗口continue;;}if ( m_bVistaLater ) {if ( NULL == hToolBar32Showed || NULL == hToolBar32Ex ) {// 都要有,否則不是合法的continue;}}else {if ( NULL == hToolBar32Showed ) {continue;}}if ( FALSE == IsExplorerProcess(hToolBar32Showed) ) {if ( ERROR_NOT_FOUND != ::GetLastError() ) {// 不是Explorer進程,則繼續尋找continue;}}if ( NULL != hToolBar32Showed ) {// 清理通知區域CleareIcons(hToolBar32Showed);}} while ( dwMaxLoopCount > 0 );
}

? ? ? ? 鑒于XP的通知區域的結構簡單性,我決定先從XP系統入手。其實XP上的解決方案是多種的,也是非常有意思的。詳細的分析過程可以參看下篇博文《一種清除windows通知區域“僵尸”圖標的方案——XP系統解決方案》。

總結

以上是生活随笔為你收集整理的一种清除windows通知区域“僵尸”图标的方案——问题分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。