热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

怎么销毁托盘小图标?

我有一个会一直自启动的UI程序,运行时会在托盘创建个小图标。有时候程序会异常终止,图标就不能正常销毁掉了,自动重启后又会有新的图标,这样有时候连续终止几次托盘上就会有一排图标。怎么样才能取消掉
我有一个会一直自启动的UI程序,运行时会在托盘创建个小图标。有时候程序会异常终止,图标就不能正常销毁掉了,自动重启后又会有新的图标,这样有时候连续终止几次托盘上就会有一排图标。

怎么样才能取消掉无效的托盘图标,比如程序在自启动的时候能不能检查下托盘上有没有无效的图标,进而把这些图标销毁掉?

12 个解决方案

#1


自己顶个~~~

#2


可以弄一个守护程序,在这守护程序里生成菜单与托盘图标,然后原程序的托盘菜单与托盘功能就不需要写了,然后守护程序跟原程序就用消息的方式进行通信把原程序的托盘菜单的功能通过守护程序发送给原程序让其触发

#3


“程序在自启动的时候能不能检查下托盘上有没有无效的图标”
应该可以吧

#4


呵呵,没有做过,呵呵。

#5


按2楼说的,写两个程序分别控制,这样处理会更加灵活和安全。
两个程序的消息通信 可以参考 
HWND hwnd= ::FindWindow(NULL,strClientName);
COPYDATASTRUCT cd;
...
::SendMessage(hwnd, WM_COPYDATA, 0, (LPARAM)(&cd));
来实现

#6


Win32程序可以试试atexit()挂接一个结束处理。C++程序可以set_terminate挂接一个异常终止过程,毕竟多数情况下,即使被异常结束,还是可以执行到这些代码的。记得在这里DELELE NOTIFYICON。
另外一旦程序已经退出了,重新启动时,为了避免出现两个小图标,需要刷新一下通知区域。不过Windows没有这方面的API。一种hack是获取通知区域的位置,然后模拟鼠标移动经过它,这个时候Windows会自动消除失效的图标。


//handle to the Tray Notification window
HWND hwndTrayNotificationWnd;

BOOL CALLBACK EnumChildProc(      
    HWND hwnd,
    LPARAM lParam
)
{
TCHAR szWindowText[255];
::GetWindowText(hwnd,szWindowText,255);
if(0 == _tcsicmp(szWindowText,_T("Notification Area")))
{
//found the "Notification Area" window. 
//This is on Windows XP
hwndTrayNotificationWnd = hwnd;
return FALSE;
}
return TRUE;
}
void RefreshSysTrayIcons()
{
//clear the handle
hwndTrayNotificationWnd = NULL;

//locate the "Shell_TrayWnd" first
HWND hwnd = ::FindWindow(_T("Shell_TrayWnd"), NULL);

//now, locate the "Notification Area"
EnumChildWindows(hwnd,EnumChildProc,0);

//if we did not find "Notification area", fall back to "TrayNotifyWnd" This is
//for Win98
if(NULL == hwndTrayNotificationWnd)
{
hwndTrayNotificationWnd = ::FindWindowEx(hwnd,NULL,_T("TrayNotifyWnd"),NULL);
}

//the icons are nSkipPixels apart. We first try to reach the
//center of the top-left icon, from there on , adding
//nSkipPixels x axis-wise and y axis-wise shall move mouse
//to the center of the next icon
int nSkipPixels = GetSystemMetrics(SM_CXSMICON);

if(hwndTrayNotificationWnd)
{
//found it.. now, simulate mouse moves in the notification area to 
//cause a refresh

//first cache the current cursor position. 
//Since we are moving the mouse, we have to 
//restore it back to where it was.
POINT point;
GetCursorPos(&point);

INPUT input;
input.type = INPUT_MOUSE;
input.mi.dwExtraInfo = 0;
input.mi.mouseData = 0;
input.mi.time = 0;
input.mi.dwFlags = (MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE);

int nCXFullScreen = GetSystemMetrics(SM_CXSCREEN);
int nCYFullScreen = GetSystemMetrics(SM_CYSCREEN);

RECT oRect;

//moving mouse over dead tray icons will result in icons being
//shuffled around again. Now, this could lead to some icons again
//getting skipped. Hence, apply retry here.
//loop NUM_RETRIES times
int nNumRetries = 1;//tweak this for your needs

while(nNumRetries)
{
::GetWindowRect(hwndTrayNotificationWnd,&oRect);

//now send a series of mouse move messages across the 
//tray window. This is done because we don't know
//in which position the lingering tray icon actually is

//move to the center of the first icon
oRect.top += nSkipPixels/2;
oRect.left += nSkipPixels/2;

int nXPos;
for(;oRect.top < oRect.bottom; oRect.top += nSkipPixels)
{
//normalize 
input.mi.dy = (oRect.top*65535)/nCYFullScreen;
for(nXPos = oRect.left;nXPos < oRect.right; nXPos += nSkipPixels)
{
//normalize
input.mi.dx = (nXPos*65535)/nCXFullScreen;
SendInput(1,&input,sizeof(INPUT));
Sleep(1);
}
}
nNumRetries--;
}
//restore the cursor now
input.mi.dx = (point.x*65535)/nCXFullScreen;
input.mi.dy = (point.y*65535)/nCYFullScreen;
SendInput(1,&input,sizeof(INPUT));
}
}

#7


引用 6 楼 Bokutake 的回复:
Win32程序可以试试atexit()挂接一个结束处理。C++程序可以set_terminate挂接一个异常终止过程,毕竟多数情况下,即使被异常结束,还是可以执行到这些代码的。记得在这里DELELE NOTIFYICON。
另外一旦程序已经退出了,重新启动时,为了避免出现两个小图标,需要刷新一下通知区域。不过Windows没有这方面的API。一种hack是获取通知区域的……

赞同你的思路,不过vs不支持c++的set_terminate,而是有自己的::SetUnhandledExceptionFilter

#8


恩,有了两种思路,晚点实践下,先结贴了。

#9


引用 7 楼 zhoujielunzhimi 的回复:
引用 6 楼 Bokutake 的回复:Win32程序可以试试atexit()挂接一个结束处理。C++程序可以set_terminate挂接一个异常终止过程,毕竟多数情况下,即使被异常结束,还是可以执行到这些代码的。记得在这里DELELE NOTIFYICON。
另外一旦程序已经退出了,重新启动时,为了避免出现两个小图标,需要刷新一下通知区域。不过Windows没有这方……


其实,VC++是支持C++异常处理的(你说不支持,肯定是没有#include 或者),而且MFC也是按照C++异常处理(3.0版本之前是MFC异常宏),而不直接支持SEH(结构化异常处理,有你说的SetUnhandledExceptionFilter)。微软也不建议使用SEH了,因为不是标准的东西,可以移植性不好。
http://msdn.microsoft.com/zh-cn/library/7w0chfbk%28v=vs.110%29.aspx

#10


引用 9 楼 Bokutake 的回复:
引用 7 楼 zhoujielunzhimi 的回复:引用 6 楼 Bokutake 的回复:Win32程序可以试试atexit()挂接一个结束处理。C++程序可以set_terminate挂接一个异常终止过程,毕竟多数情况下,即使被异常结束,还是可以执行到这些代码的。记得在这里DELELE NOTIFYICON。
另外一旦程序已经退出了,重新启动时,为了避免出现两个小……

但是我试了下c++(vs2010)的set_terminate,根本就没用。

#11


引用 10 楼 zhoujielunzhimi 的回复:
引用 9 楼 Bokutake 的回复:引用 7 楼 zhoujielunzhimi 的回复:引用 6 楼 Bokutake 的回复:Win32程序可以试试atexit()挂接一个结束处理。C++程序可以set_terminate挂接一个异常终止过程,毕竟多数情况下,即使被异常结束,还是可以执行到这些代码的。记得在这里DELELE NOTIFYICON。
另外一旦程序已……

我试了一下,是可以的。只不过你不能同时用VC的调试器,也就是Ctrl+F5直接执行,不论是Debug还是Release版本都调用了异常中止函数。但是无论是atexit还是set_terminate对于外界的强行中止都不起作用。

#include "stdafx.h"
#include 
using namespace std;

void term_func() {
   cout << "term_func was called by terminate." << endl;
   exit( -1 );
}

int _tmain(int argc, _TCHAR* argv[])
{
   try
   {
      set_terminate( term_func );
      throw "Out of memory!"; // No catch handler for this exception
   }
   catch( int )
   {
      cout << "Integer exception raised." << endl;
   }
return 0;
}

#12


我说得是在任务管理器里第二个里面中止进程,这个时候似乎只有程序自己hook TerminateProcess才能阻止这个。
但是第一个标签页的结束任务则比较温和,能够让程序有机会执行退出的代码。

推荐阅读
  • Android获取app应用程序大小的方法
    Android获取app应用程序大小的方法-Android对这种方法进行了封装,我们没有权限去调用这个方法,所以我们只能通过AIDL,然后利用Java的反射机制去调用系统级的方法。 ... [详细]
  • 【技术分享】一个 ELF 蠕虫分析
    【技术分享】一个 ELF 蠕虫分析 ... [详细]
  • Project2.cpp:定义应用程序的入口点。#includeframework.h#includeProject2.h#defineMAX_LOADSTRING100全 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
  • 使用eclipse创建一个Java项目的步骤
    本文介绍了使用eclipse创建一个Java项目的步骤,包括启动eclipse、选择New Project命令、在对话框中输入项目名称等。同时还介绍了Java Settings对话框中的一些选项,以及如何修改Java程序的输出目录。 ... [详细]
  • 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
    本文旨在全面介绍Windows内存管理机制及C++内存分配实例中的内存映射文件。通过对内存映射文件的使用场合和与虚拟内存的区别进行解析,帮助读者更好地理解操作系统的内存管理机制。同时,本文还提供了相关章节的链接,方便读者深入学习Windows内存管理及C++内存分配实例的其他内容。 ... [详细]
  • 解决Sharepoint 2013运行状况分析出现的“一个或多个服务器未响应”问题的方法
    本文介绍了解决Sharepoint 2013运行状况分析中出现的“一个或多个服务器未响应”问题的方法。对于有高要求的客户来说,系统检测问题的存在是不可接受的。文章详细描述了解决该问题的步骤,包括删除服务器、处理分布式缓存留下的记录以及使用代码等方法。同时还提供了相关关键词和错误提示信息,以帮助读者更好地理解和解决该问题。 ... [详细]
  • 本文总结了在编写JS代码时,不同浏览器间的兼容性差异,并提供了相应的解决方法。其中包括阻止默认事件的代码示例和猎取兄弟节点的函数。这些方法可以帮助开发者在不同浏览器上实现一致的功能。 ... [详细]
  • 本文介绍了使用readlink命令获取文件的完整路径的简单方法,并提供了一个示例命令来打印文件的完整路径。共有28种解决方案可供选择。 ... [详细]
  • Python脚本编写创建输出数据库并添加模型和场数据的方法
    本文介绍了使用Python脚本编写创建输出数据库并添加模型数据和场数据的方法。首先导入相应模块,然后创建输出数据库并添加材料属性、截面、部件实例、分析步和帧、节点和单元等对象。接着向输出数据库中添加场数据和历程数据,本例中只添加了节点位移。最后保存数据库文件并关闭文件。文章还提供了部分代码和Abaqus操作步骤。另外,作者还建立了关于Abaqus的学习交流群,欢迎加入并提问。 ... [详细]
  • {moduleinfo:{card_count:[{count_phone:1,count:1}],search_count:[{count_phone:4 ... [详细]
  • 以管理员身份打开命令行粘贴上面 ... [详细]
  • 学习笔记17:Opencv处理调整图片亮度和对比度
    一、理论基础在数学中我们学过线性理论,在图像亮度和对比度调节中同样适用,看下面这个公式:在图像像素中其中:参数f(x)表示源图像像素。参数g(x)表示输出图像像素。 ... [详细]
author-avatar
胡鹏锦_289
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有