admin 管理员组文章数量: 887007
Windows7下“僵尸”图标的解决方案
从《一种清除windows通知区域“僵尸”图标的方案——问题分析》(以后简称《问题分析》)一文中分析的通知区域结构可以看出,Windows7的通知区域比XP通知区域多出了一个“临时”系统通知区域(转载请指明出于breaksoftware的csdn博客)
虽然我们可以在“控制面板\所有控制面板项\通知区域图标”下选择“始终在任务栏上显示所有图标和通知(A)”,来让Windows7的通知区域和XP上一致,但是我们无法让用户这么去做,因为我们给不出这样做的必要。
这个隐藏的通知区域是让我非常头疼的,《一种清除windows通知区域“僵尸”图标的方案——XP系统解决方案》一文中的所有方案都不适用于它。
在各种方法走不通的情况下,我们不妨换一种思路:保证只有一个图标。如果进程意外退出,那么在下次启动时,再次注册和新增通知区域图标时,我们先删掉原来的图标然后再新增图标,而不是简单的新增一个图标。或许有人会问,为什么XP下不这么做呢?因为XP下无法删除其他进程创建的图标。
XP下密集出现的“僵尸”图标问题,应该是引起了微软的注意。所以他们在Vista之后的系统中,给通知区域图标新增了一个GUID信息。于是,我们就可以简单的指定GUID便可以保证了图标的唯一性!
m_NotifyIcon.cbSize = sizeof(m_NotifyIcon);
m_NotifyIcon.uFlags = NIF_ICON | NIF_TIP;
if ( bWin7OrLater ) {
GUID PathGUID = {0x23977b55, 0x10e0, 0x4041, {0xb8, 0x62, 0xb1, 0x95, 0x41, 0x96, 0x36, 0x69}};
m_NotifyIcon.guidItem = PathGUID;
m_NotifyIcon.uVersion = NOTIFYICON_VERSION_4;
m_NotifyIcon.uFlags |= NIF_GUID;
}
m_NotifyIcon.hWnd = m_hWnd;
m_NotifyIcon.hIcon = m_hIcon;
看似这个问题就这么解决了,但是问题绝对不是这么简单的。我们发现,如果我们将程序A拷贝到其他目录下叫作A‘。如果A'创建了图标,并且A'进程被杀死。那么A进程可能出现无法创建和无法删除图标的情况,这样就严重影响了正常执行流程。
其实这个问题也比较好解决:去掉hWnd参数的指定。但是这个方案将导致一个缺陷:通知区域图标不能将消息传递给主界面!
一个比较好的解决方法,就是让不同目录下进程新增的图标的GUID不同。于是我们可以计算当前进程路径的MD5,方法是
……
if ( bWin7OrLater ) {
WCHAR wcharPath[MAX_PATH] = {0};
DWORD dwSize = GetModuleFileName(NULL, wcharPath, ARRAYSIZE(wcharPath) );
unsigned char md5[16] = {0};
GetMD5((const unsigned char*)wcharPath, dwSize * sizeof(WCHAR), md5, sizeof(md5));
GUID PathGUID;// = {0x23977b55, 0x10e0, 0x4041, {0xb8, 0x62, 0xb1, 0x95, 0x41, 0x96, 0x36, 0x69}};
memcpy_s(&PathGUID, sizeof(GUID), md5, sizeof(md5));
……
}
创建图标的方法是
VOID CNotificationIconDlg::ShowTrayIcon()
{
if ( FALSE == Shell_NotifyIcon(NIM_ADD, &m_NotifyIcon) ) {
if ( ERROR_NO_TOKEN == ::GetLastError()) {
for ( int i = 0; i < 64; i++) {
if ( FALSE == Shell_NotifyIcon(NIM_DELETE, &m_NotifyIcon) ) {
if ( ERROR_TIMEOUT == ::GetLastError() ) {
break;
}
}
}
if ( FALSE == Shell_NotifyIcon(NIM_ADD, &m_NotifyIcon)) {
if ( ERROR_NO_TOKEN == ::GetLastError()) {
m_NotifyIcon.uFlags ^= NIF_GUID;
}
if ( FALSE == Shell_NotifyIcon(NIM_ADD, &m_NotifyIcon) ) {
}
}
}
}
}
至此,Windows7下的图标问题也就解决了。这儿再记录一份使用advapi.dll中相关方法计算MD5的代码
#include "stdafx.h"
#include "WinMd5.h"
BOOL GetMD5(const unsigned char * buf, unsigned int unbufferlenth,
unsigned char* retMd5, unsigned int unMd5BufferSize)
{
BOOL bSuc = FALSE;
HINSTANCE hDLL = NULL;
do {
MD5_CTX ctx;
if ( unMd5BufferSize > sizeof(ctx.digest) ){
break;
}
HMODULE hDLL = LoadLibrary(L"advapi32.dll");
if ( NULL == hDLL ) {
break;
}
PMD5Init MD5Init = (PMD5Init)GetProcAddress(hDLL, "MD5Init");
PMD5Update MD5Update = (PMD5Update)GetProcAddress(hDLL, "MD5Update");
PMD5Final MD5Final = (PMD5Final)GetProcAddress(hDLL, "MD5Final");
if ( !MD5Init || !MD5Update || !MD5Final ) {
break;
}
MD5Init(&ctx);
MD5Update(&ctx, buf, unbufferlenth);
MD5Final(&ctx);
memcpy_s(retMd5, unMd5BufferSize, ctx.digest, sizeof(ctx.digest));
bSuc = TRUE;
} while (0);
if ( NULL != hDLL ) {
FreeLibrary(hDLL);
hDLL = NULL;
}
return bSuc;
}
最后附上工程地址
版权声明:本文标题:一种清除windows通知区域“僵尸”图标的方案——Windows7系统解决方案 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/jishu/1728603042h1255399.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论