一种清除windows通知区域“僵尸”图标的方案——Windows7系统解决方案

本文介绍了解决Windows7通知区域出现的“僵尸”图标问题的方法。通过为图标分配唯一的GUID,确保即使进程重启也能避免重复图标的问题。此外,还提供了一种根据不同进程路径生成不同GUID的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;

}

最后附上工程地址

### 解决方案:Ubuntu 系统中 `bash fork Resource temporarily unavailable` 问题后的重新登录操作 在解决了 Ubuntu 系统中的 `bash: fork: retry: Resource temporarily unavailable` 问题之后,为了确保系统能够正常工作以及用户可以成功重新登录,需按照以下方式进行验证和处理。 --- #### 1. 验证资源限制调整的效果 在解决该问题的过程中,通常会对系统的资源限制进行了调整。此时需要确认这些设置已生效: - 使用以下命令检查当前用户的资源限制是否已被更新: ```bash ulimit -a ``` 重点关注以下几个字段: - **max user processes**: 表示允许的最大进程数。 - **open files**: 表示允许的最大文件描述符数。 如果发现某些值未按预期更改,则可能是因为修改的内容尚未应用到当前会话。可以通过注销并重新登录来激活更改[^2]。 --- #### 2. 修改配置文件以持久化资源限制 为防止下次重启后恢复默认值,应确保相关配置文件被正确编辑。主要涉及两个方面: ##### (1)用户级资源限制 编辑 `/etc/security/limits.conf` 或者对应目录下的 `.conf` 文件(如 `/etc/security/limits.d/90-nproc.conf`)。例如: ```plaintext * soft nproc 65535 * hard nproc 65535 * soft nofile 65535 * hard nofile 65535 ``` 这一步骤确保所有用户都拥有足够的进程和文件描述符配额[^2]。 ##### (2)系统级资源限制 对于更深层次的系统范围调整,可修改如下文件: - 编辑 `/etc/systemd/system.conf` 和 `/etc/systemd/user.conf` 添加或修改以下内容: ```plaintext DefaultLimitNOFILE=65535 DefaultLimitNPROC=65535 ``` 随后执行以下命令刷新 systemd 设置: ```bash sudo systemctl daemon-reload ``` 此外,还应该调整内核参数以支持更高的 PID 数量和其他必要的资源分配: ```bash echo "kernel.pid_max=65536" | sudo tee -a /etc/sysctl.conf echo "fs.file-max=100000" | sudo tee -a /etc/sysctl.conf sudo sysctl -p ``` --- #### 3. 清理多余进程与释放资源 即使完成了上述配置调整,仍可能存在大量遗留下来的无用进程占据着宝贵资源。因此有必要采取行动清理它们: - 查找消耗较多 CPU 或内存的进程列表: ```bash ps aux --sort=-%mem,-%cpu | head -n 20 ``` 针对那些不再需要的服务或应用程序逐一停止甚至彻底移除。 特别需要注意的是僵尸进程的存在——尽管本身不会占用太多实际计算能力但却阻碍新任务创建。利用下面这条指令定位此类特殊情况: ```bash ps aux | grep 'Z' ``` 一旦发现问题所在即刻予以清除: ```bash kill -9 <PID> ``` --- #### 4. 测试重新登录功能 完成以上准备工作以后便可以尝试退出现有 shell 并再次进入系统检验成果了。具体步骤如下所示: ##### 方法一:直接切换至另一账户再返回原身份 假设当前正作为管理员权限操作的话那么不妨先转换成普通模式然后再切回去看看状况如何变化。 ```bash su - normal_user_name exit ``` ##### 方法二:完全登出后再通过图形界面或者远程连接手段重试接入 如果是基于 SSH 远程访问服务器端口的话记得断开原有链接建立全新通道; 而本地物理机面前则简单得多只需点击右上角头像图标选择签退选项即可。 无论采用哪种形式均要留意观察整个过程是否存在任何异常提示信息比如重复遭遇相同的错误消息之类现象发生。 --- #### 5. 对于 Java 应用场景额外注意事项 考虑到之前提到过此故障也可能波及到运行中的 Java 程序从而抛出类似于 `java.lang.OutOfMemoryError: unable to create new native thread` 的例外情形所以在此补充几点建议帮助规避潜在风险: - 减少线程池规模设定合理阈值避免过度膨胀; - 提升单个线程堆栈尺寸缓解压力: ```bash java -Xss512k ... ``` - 加入 JVM 参数优化性能表现同时增强容器兼容特性表达式如下: ```bash export JAVA_OPTS="-XX:-UsePerfData -XX:+UseContainerSupport" ``` --- ### 示例代码片段 这里提供一段简单的 C++ 程序用来模拟多线程环境下可能出现的情况以便更好地理解原理机制背后运作逻辑关系。 ```cpp #include <iostream> #include <pthread.h> void* threadRun(void*) { std::cout << "Thread running." << std::endl; return nullptr; } int main() { int num = 0; pthread_t tid; while (pthread_create(&tid, NULL, threadRun, NULL) == 0) { printf("Created thread (%llu), total threads created: %d\n", tid, ++num); } perror("Failed to create more threads"); } ``` 编译运行上述源码可以帮助我们直观感受当达到操作系统强加给定程序所能容纳最大并发数目极限时所表现出的行为特征[^3]. --- ### 总结 综上所述,面对 Ubuntu 中因资源不足而导致无法 fork 新进程的问题,除了及时修正各项限额之外还需定期维护好整体生态环境状态才能从根本上杜绝同类事件再度上演。遵循本文介绍的方法论框架结构逐步推进直至最终达成目标。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值