怎么销毁托盘小图标?

pvlking 2013-03-12 09:27:31
我有一个会一直自启动的UI程序,运行时会在托盘创建个小图标。有时候程序会异常终止,图标就不能正常销毁掉了,自动重启后又会有新的图标,这样有时候连续终止几次托盘上就会有一排图标。

怎么样才能取消掉无效的托盘图标,比如程序在自启动的时候能不能检查下托盘上有没有无效的图标,进而把这些图标销毁掉?
...全文
427 12 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
sumos 2013-03-13
  • 打赏
  • 举报
回复
引用 9 楼 Bokutake 的回复:
引用 7 楼 zhoujielunzhimi 的回复:引用 6 楼 Bokutake 的回复:Win32程序可以试试atexit()挂接一个结束处理。C++程序可以set_terminate挂接一个异常终止过程,毕竟多数情况下,即使被异常结束,还是可以执行到这些代码的。记得在这里DELELE NOTIFYICON。 另外一旦程序已经退出了,重新启动时,为了避免出现两个小……
但是我试了下c++(vs2010)的set_terminate,根本就没用。
辰岡墨竹 2013-03-13
  • 打赏
  • 举报
回复
我说得是在任务管理器里第二个里面中止进程,这个时候似乎只有程序自己hook TerminateProcess才能阻止这个。 但是第一个标签页的结束任务则比较温和,能够让程序有机会执行退出的代码。
辰岡墨竹 2013-03-13
  • 打赏
  • 举报
回复
引用 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 <iostream>
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;
}
辰岡墨竹 2013-03-12
  • 打赏
  • 举报
回复
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));
	}
}
山伟 2013-03-12
  • 打赏
  • 举报
回复
按2楼说的,写两个程序分别控制,这样处理会更加灵活和安全。 两个程序的消息通信 可以参考 HWND hwnd= ::FindWindow(NULL,strClientName); COPYDATASTRUCT cd; ... ::SendMessage(hwnd, WM_COPYDATA, 0, (LPARAM)(&cd)); 来实现
  • 打赏
  • 举报
回复
呵呵,没有做过,呵呵。
schlafenhamster 2013-03-12
  • 打赏
  • 举报
回复
“程序在自启动的时候能不能检查下托盘上有没有无效的图标” 应该可以吧
fishion 2013-03-12
  • 打赏
  • 举报
回复
可以弄一个守护程序,在这守护程序里生成菜单与托盘图标,然后原程序的托盘菜单与托盘功能就不需要写了,然后守护程序跟原程序就用消息的方式进行通信把原程序的托盘菜单的功能通过守护程序发送给原程序让其触发
pvlking 2013-03-12
  • 打赏
  • 举报
回复
自己顶个~~~
辰岡墨竹 2013-03-12
  • 打赏
  • 举报
回复
引用 7 楼 zhoujielunzhimi 的回复:
引用 6 楼 Bokutake 的回复:Win32程序可以试试atexit()挂接一个结束处理。C++程序可以set_terminate挂接一个异常终止过程,毕竟多数情况下,即使被异常结束,还是可以执行到这些代码的。记得在这里DELELE NOTIFYICON。 另外一旦程序已经退出了,重新启动时,为了避免出现两个小图标,需要刷新一下通知区域。不过Windows没有这方……
其实,VC++是支持C++异常处理的(你说不支持,肯定是没有#include <exception>或者<eh.h>),而且MFC也是按照C++异常处理(3.0版本之前是MFC异常宏),而不直接支持SEH(结构化异常处理,有你说的SetUnhandledExceptionFilter)。微软也不建议使用SEH了,因为不是标准的东西,可以移植性不好。 http://msdn.microsoft.com/zh-cn/library/7w0chfbk%28v=vs.110%29.aspx
pvlking 2013-03-12
  • 打赏
  • 举报
回复
恩,有了两种思路,晚点实践下,先结贴了。
sumos 2013-03-12
  • 打赏
  • 举报
回复
引用 6 楼 Bokutake 的回复:
Win32程序可以试试atexit()挂接一个结束处理。C++程序可以set_terminate挂接一个异常终止过程,毕竟多数情况下,即使被异常结束,还是可以执行到这些代码的。记得在这里DELELE NOTIFYICON。 另外一旦程序已经退出了,重新启动时,为了避免出现两个小图标,需要刷新一下通知区域。不过Windows没有这方面的API。一种hack是获取通知区域的……
赞同你的思路,不过vs不支持c++的set_terminate,而是有自己的::SetUnhandledExceptionFilter

16,548

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧