小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

一種清除windows通知區(qū)域“僵尸”圖標(biāo)的方案——問(wèn)題分析

 quasiceo 2014-01-12
分類(lèi): windows開(kāi)發(fā) 2013-12-09 01:01 1342人閱讀 評(píng)論(7) 收藏 舉報(bào)

目錄(?)[+]

通知區(qū)域名稱(chēng)有趣的歷史

        假如說(shuō)到windows通知區(qū)域,可能很多人還是不清楚它是什么。如果改稱(chēng)Tray區(qū)域,可能有人就懂了。如果再白話點(diǎn),叫它“托盤(pán)”或者“系統(tǒng)托盤(pán)”,可能會(huì)有更多的人猜到它是windows什么部位?,F(xiàn)在我們揭開(kāi)它真實(shí)的面紗,以windows7系統(tǒng)為例,下圖就是它的通知區(qū)域。(轉(zhuǎn)載請(qǐng)指明出于breaksoftware的csdn博客)


        其實(shí),我們叫通知區(qū)域?yàn)椤巴斜P(pán)”或者“系統(tǒng)托盤(pán)”是錯(cuò)誤的。這個(gè)錯(cuò)誤并非來(lái)源于中文翻譯,而是來(lái)源于windows發(fā)展史上人們對(duì)其錯(cuò)誤的認(rèn)識(shí)。后來(lái),這個(gè)命名也影響了中國(guó)一批程序員。我這兒要摘錄一個(gè)微軟老員工的回憶錄《The Old New Thing》(中文名《windows編程啟示錄》)一書(shū)中關(guān)于這個(gè)錯(cuò)誤認(rèn)識(shí)起源的一段,還是蠻有意思的。

        “后來(lái),我們將通知圖標(biāo)添加到任務(wù)欄中?!?/p>

        “我認(rèn)為人們開(kāi)始將通知區(qū)域叫作系統(tǒng)托盤(pán)是因?yàn)樵赪indows95中包含了一個(gè)systray.exe的程序,這個(gè)程序在通知區(qū)域中顯示了一些圖標(biāo),如音量控制,PCMCIA(在當(dāng)時(shí)是叫這個(gè)名字)的狀態(tài)、電池的電量表等。如果你終止了systray.exe,那么這些通知圖標(biāo)也將會(huì)消失。因此人們就認(rèn)為,‘啊,systray程序一定是管理這些圖標(biāo)的組件,我敢打賭這個(gè)組件的名字就叫作“系統(tǒng)托盤(pán)”’。于是這個(gè)誤解就形成了,而我們這十幾年來(lái)一直都在努力澄清這個(gè)誤解。”

        “更糟糕的是,其他的團(tuán)隊(duì)(Shell之外的團(tuán)隊(duì))也錯(cuò)誤地使用了這個(gè)詞,并且開(kāi)始在他們自己的文檔和示例程序里面都使用了系統(tǒng)托盤(pán)這個(gè)詞,其中有一些地方甚至錯(cuò)誤地聲稱(chēng)系統(tǒng)托盤(pán)就是通知區(qū)域的正式名稱(chēng)。”

        “有人可能會(huì)問(wèn),‘你為什么要關(guān)心這個(gè)名字的正誤?既然現(xiàn)在所有的人都叫這個(gè)名字,你也可以隨波逐流嘛?!?/p>

        “如果每個(gè)人都叫錯(cuò)了你的名字,你會(huì)樂(lè)意嗎?”

        其實(shí)我覺(jué)得,如果微軟真的想徹底摒棄“系統(tǒng)托盤(pán)”這個(gè)名稱(chēng),最好是從現(xiàn)在做起,將通知區(qū)域的一些信息都修改成和Tray這個(gè)單詞無(wú)關(guān)。可是,我們使用Spy++查看Windows7任務(wù)欄的組成時(shí)就會(huì)發(fā)現(xiàn),Tray這個(gè)單詞無(wú)處不在?。?/p>



“僵尸圖標(biāo)”

        說(shuō)了這么多歷史故事,我們?cè)倩氐轿覀冞@篇博文要講述的問(wèn)題上。其實(shí)這個(gè)問(wèn)題,依舊是個(gè)歷史問(wèn)題。還好,我發(fā)現(xiàn)vista之后的系統(tǒng)上,微軟已經(jīng)意識(shí)并修復(fù)了這個(gè)設(shè)計(jì)缺陷。我們看下下面的場(chǎng)景

        

        很多使用Windows的人可能都遇到過(guò)這個(gè)問(wèn)題:通知區(qū)域出現(xiàn)了N個(gè)相同的“僵尸”圖標(biāo)。如果我們有意或者無(wú)意讓光標(biāo)劃過(guò)這些圖標(biāo)時(shí),這些圖標(biāo)會(huì)悄然消失。我們對(duì)這種現(xiàn)象,往往是疑惑一下就拋之腦后。然而,目前我在項(xiàng)目中就接到一個(gè)需求:把這些“僵尸”圖標(biāo)自動(dòng)消失。出于我們產(chǎn)品的設(shè)計(jì),我們存在出現(xiàn)這么多“僵尸”圖標(biāo)的場(chǎng)景,于是為了優(yōu)化用戶(hù)體驗(yàn),我需要找到一種方法去解決這種體驗(yàn)問(wèn)題。


通知區(qū)域圖標(biāo)的正常生死過(guò)程

        首先要分析一下這個(gè)問(wèn)題出現(xiàn)的原因。一般來(lái)說(shuō),一個(gè)程序在創(chuàng)建時(shí),可能會(huì)在通知區(qū)域創(chuàng)建一個(gè)圖標(biāo)。

一般初始化圖標(biāo)

        創(chuàng)建圖標(biāo)之前,我們需要初始化一個(gè)圖標(biāo)

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

       這個(gè)地方需要注意的是下面幾個(gè)參數(shù):

  1. uFlags。我們只是設(shè)置了NIF_ICON和NIF_TIP,因?yàn)槲覀冃枰屛覀兊耐ㄖ獏^(qū)域圖標(biāo)變得與眾不同,故通過(guò)指定這兩個(gè)標(biāo)志分別告知系統(tǒng):我們要設(shè)定圖標(biāo)和Tip文字。這個(gè)屬性我們會(huì)在處理Windows7系統(tǒng)上“僵尸”圖標(biāo)的時(shí)候再次提起。
  2. hWnd。因?yàn)槲覀儓D標(biāo)要相應(yīng)用戶(hù)的點(diǎn)擊,并將相應(yīng)消息傳遞給我們主窗口,所以我們此時(shí)要綁定主窗口句柄。這個(gè)屬性我們會(huì)在未來(lái)介紹一個(gè)特定場(chǎng)景時(shí)再次提到。
  3. szTip。我們故意給我們這個(gè)圖標(biāo)取了一個(gè)晦澀的Tip,這樣我們?cè)谥蟛檎摇敖┦瑘D標(biāo)”時(shí)將有據(jù)可憑。

圖標(biāo)添加到通知區(qū)域

        圖標(biāo)初始化后,我們要將圖標(biāo)增加到通知區(qū)域
  1. Shell_NotifyIcon(NIM_ADD, &m_NotifyIcon);  

        這個(gè)圖標(biāo)是可以表明“這個(gè)進(jìn)程還活著”;而且在無(wú)界面展現(xiàn)時(shí),讓用戶(hù)方便喚起界面或者執(zhí)行相應(yīng)的功能。比如QQ的通知區(qū)域圖標(biāo),它的存在表明QQ進(jìn)程還是存在的。我們可以左鍵雙擊之,可以讓主界面展現(xiàn)出來(lái);還可以右擊之,可以出現(xiàn)很多快捷功能鍵


圖標(biāo)從通知區(qū)域剔除        

        相應(yīng)的,如果進(jìn)程退出,應(yīng)該通知系統(tǒng)通知區(qū)域:要將我設(shè)置的通知區(qū)域圖標(biāo)刪除,因?yàn)槲荫R上要退出了。

  1. Shell_NotifyIcon(NIM_DELETE, &m_NotifyIcon);  

        如果一切都如此按照規(guī)律的“正常生死”,也就沒(méi)有之前提出的問(wèn)題。可是,出于策略考慮以及一些異常情況,進(jìn)程的意外死亡還是不可避免的。這樣,如果出現(xiàn)連續(xù)的意外死亡場(chǎng)景,系統(tǒng)通知區(qū)域就會(huì)殘留很多“僵尸”圖標(biāo)。為了大戰(zhàn)這些“僵尸”,我們需要找到這些“僵尸”的家,然后對(duì)“僵尸”各個(gè)擊破。于是,我們要看下各系統(tǒng)下通知區(qū)域的樹(shù)狀結(jié)構(gòu)圖。

XP、Win7下通知區(qū)域的結(jié)構(gòu)

        先使用SPY++看下XP下任務(wù)欄即通知區(qū)域的結(jié)構(gòu)

  1. #32769 (桌面)  
  2.   - Shell_TrayWnd  
  3.     - Button  
  4.     - TrayNotifyWnd  
  5.       - TrayClockWClass  
  6.       - SysPager  
  7.           - ToolbarWindow32(我們關(guān)心的,其直接顯示在桌面上)  
  8.       - Button  
  9.         - CiceroUIWndFrame  
  10.         - MSTaskSwWClass  
  11.           - ToolbarWindow32  
  12.     - ReBarWindow32  

        SysPager下類(lèi)名為T(mén)oolbarWindow32的控件就是系統(tǒng)通知區(qū)域。非常慶幸,XP下只有這么一個(gè)通知區(qū)域,而且這個(gè)通知區(qū)域一直是可見(jiàn)的(Win7下有個(gè)不可見(jiàn)的通知區(qū)域)。

        再看下Win7的通知區(qū)域結(jié)構(gòu)

  1. #32769 (桌面)  
  2.   - Shell_TrayWnd  
  3.     - TrayNotifyWnd  
  4.       - TrayClockWClass  
  5.       - TrayShowDesktopButtonWClass  
  6.       - SysPager  
  7.         - ToolbarWindow32(我們關(guān)心的,其直接顯示在桌面上)  
  8.       - ToolbarWindow32(其隱藏在桌面上,通過(guò)SendTimeout發(fā)送TB_BUTTONCOUNT不能獲取其個(gè)數(shù))  
  9.       - Button  
  10.     - ReBarWindow32  
  11.       - CiceroUIWndFrame  
  12.       - MSTaskSwWClass  
  13.         - MSTaskListWClass  
        Win7的通知區(qū)域相對(duì)于XP有點(diǎn)復(fù)雜,其中我們一直可見(jiàn)的通知區(qū)域的樹(shù)狀結(jié)構(gòu)和XP上是一致的。但是Win7上多出了一個(gè)隱藏的通知區(qū)域,它和SysPager同級(jí)


        針對(duì)XP和Win7上都可見(jiàn)的通知區(qū)域,我們可以通過(guò)如下代碼找到相應(yīng)區(qū)域去清理

  1. VOID CKillRunProcessDlg::VisitNotificationArea()  
  2. {  
  3.     HWND hwndChildAfter = NULL;  
  4.     DWORD dwMaxLoopCount = MAXLOOPCOUNT;  
  5.     do {  
  6.         // 保守性編程,防止死循環(huán)  
  7.         dwMaxLoopCount--;  
  8.         HWND hTrayWnd = NULL;  
  9.         hTrayWnd = ::FindWindowEx( NULL, hwndChildAfter, L"Shell_TrayWnd", NULL);  
  10.         if ( NULL == hTrayWnd ) {  
  11.             break;  
  12.         }  
  13.   
  14.         // 找到了窗口類(lèi)為 Shell_TrayWnd的窗口,  
  15.         // 但是不保證找到的就是Notification所在區(qū)域的,  
  16.         // 所以記錄下當(dāng)前找到的,之后繼續(xù)找  
  17.         hwndChildAfter = hTrayWnd;  
  18.   
  19.         HWND hTrayNotifyWnd = ::FindWindowEx(hTrayWnd, NULL, L"TrayNotifyWnd", NULL );  
  20.         if ( NULL == hTrayNotifyWnd ) {  
  21.             // 繼續(xù)找符合條件的Shell_TrayWnd類(lèi),然后再在其下找類(lèi)為T(mén)rayNotifyWnd的子窗口  
  22.             continue;  
  23.         }  
  24.   
  25.         // 這個(gè)窗口只能在Win7系統(tǒng)中可以找到  
  26.         HWND hToolBar32Ex = ::FindWindowEx( hTrayNotifyWnd, NULL, L"ToolbarWindow32", NULL );  
  27.           
  28.         // 在win7 xp下都可以找到該樹(shù)結(jié)構(gòu)  
  29.         HWND hSysPager = ::FindWindowEx( hTrayNotifyWnd, NULL, L"SysPager", NULL );  
  30.         HWND hToolBar32Showed = NULL;  
  31.         if ( NULL != hSysPager ) {    
  32.             hToolBar32Showed = ::FindWindowEx( hSysPager, NULL, L"ToolbarWindow32", NULL );  
  33.         }  
  34.         else {  
  35.             // 找不到該樹(shù)結(jié)構(gòu)  
  36.             // 則繼續(xù)找符合條件的Shell_TrayWnd類(lèi),然后再在其下找類(lèi)為T(mén)rayNotifyWnd的子窗口  
  37.             continue;;  
  38.         }  
  39.   
  40.         if ( m_bVistaLater ) {  
  41.             if ( NULL == hToolBar32Showed || NULL == hToolBar32Ex ) {  
  42.                 // 都要有,否則不是合法的  
  43.                 continue;  
  44.             }  
  45.         }  
  46.         else {  
  47.             if ( NULL == hToolBar32Showed ) {  
  48.                 continue;  
  49.             }  
  50.         }  
  51.   
  52.         if ( FALSE == IsExplorerProcess(hToolBar32Showed) ) {  
  53.             if ( ERROR_NOT_FOUND != ::GetLastError() ) {  
  54.                 // 不是Explorer進(jìn)程,則繼續(xù)尋找  
  55.                 continue;  
  56.             }  
  57.         }  
  58.   
  59.         if ( NULL != hToolBar32Showed ) {  
  60.             // 清理通知區(qū)域  
  61.             CleareIcons(hToolBar32Showed);  
  62.         }  
  63.   
  64.     } while ( dwMaxLoopCount > 0 );  
  65. }  

        鑒于XP的通知區(qū)域的結(jié)構(gòu)簡(jiǎn)單性,我決定先從XP系統(tǒng)入手。其實(shí)XP上的解決方案是多種的,也是非常有意思的。詳細(xì)的分析過(guò)程可以參看下篇博文《一種清除windows通知區(qū)域“僵尸”圖標(biāo)的方案——XP系統(tǒng)解決方案》。

更多 2

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多