系统托盘的问题

来源:互联网 发布:知乎客户端电脑版 编辑:程序博客网 时间:2024/05/29 04:33
今天要求做个东东,有让程序最小化到系统托盘的部分,写下如下代码,先建立消息映射
ON_MESSAGE(WM_ICONNOTIFY,OnMinToShellNotifyIcon)
然后写下消息函数
LRESULT    OnMinToShellNotifyIcon(WPARAM wParam, LPARAM lParam)    // 产生托盘图标消息
{
    UINT uMsg = (UINT)lParam;
    CMenu menu;   
    SetMenu(&menu);
    UINT uCmd;
    switch (uMsg)
    {
        case WM_LBUTTONDOWN:           
            DeleteShellNotifyIcon(0);    //    清除托盘图标
            SetForegroundWindow();        //    让程序前置到窗口
            ShowWindow(SW_SHOWNORMAL);
            break;
        case WM_RBUTTONUP:
            //-----------弹出菜单---------------------------------
            menu.CreatePopupMenu();
            menu.AppendMenu(MF_STRING, 1100+1, _T("还原")); //1100是自己定义的,表示菜单上的项目ID,
//最好用define定义成特定的字串,如#define MY_MENU_ITEM 1100;并且要按照MS的要求定义大小。
            menu.AppendMenu(MF_STRING, 1100+2, _T("退出"));
            POINT point;
            GetCursorPos(&point);
            uCmd = menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD, point.x, point.y, this, NULL);
            switch(uCmd)    //    处理菜单消息
            {
            case 1100 + 1 :
                //AfxMessageBox("ok");
                DeleteShellNotifyIcon(0);    //    清除托盘图标
                ShowWindow(SW_SHOWNORMAL); 
                SetForegroundWindow();        //    让程序前置到窗口
                break;
            case 1100 + 2 :
                PostMessage(WM_CLOSE, 0, 0); // 退出程序
                break;
            default:
                break;
            }
        default:
              break;
    }
    return 0;
}
运行,试一下鼠标消息,正常执行,可是当鼠标在其他地方点击时(并不点击弹出菜单的还原或退出),发现菜单并不消失,除非再点击一下原来程序的界面.奇怪了,并且有时点击后菜单出来,但又马上消失,好像要加点什么代码才能让其正常,看看MSDN上有什么说明,找了找有个函数BOOL CMenu::DestroyMenu( );添加到default:下(心里感觉可能不行),果真如此。费了半天劲,这可不好搞。消失的问题不好解决,上microsoft看看,都是英文,硬着头皮看下去,找到Q135788:Menus for Notification Icons Do Not Work Correctly,原来“When you display a context menu for a notification icon (see Shell_NotifyIcon), clicking anywhere besides the menu or the window that created the menu (if it is visible) doesn't cause the menu to disappear. When this behavior is corrected, the second time this menu is displayed, it displays and then immediately disappears. ”接下来说明了解决办法,就是说在调用TrackPopupMenu前必须把当前程序作成顶层窗口,用SetForegroundWindow();同时防止点击右键时菜单出现又马上消失的问题,必须送一个空消息PostMessage(WM_NULL, 0, 0);好办得很。把上面代码改一下:
LRESULT    OnTaskbar(WPARAM wParam, LPARAM lParam)    // 产生托盘图标消息
{
    UINT uMsg = (UINT)lParam;
    CMenu menu;   
    SetMenu(&menu);
    UINT uCmd;
    switch (uMsg)
    {
        case WM_LBUTTONDOWN:           
            DeleteShellNotifyIcon(0);    //    清除托盘图标
            SetForegroundWindow();        //    让程序前置到窗口
            ShowWindow(SW_SHOWNORMAL);
            break;
        case WM_RBUTTONUP:
            //-----------弹出菜单---------------------------------
            menu.CreatePopupMenu();
            menu.AppendMenu(MF_STRING, 1100+1, _T("还原")); //1100是自己定义的,表示菜单上的项目ID,
//最好用define定义成特定的字串,如#define MY_MENU_ITEM 1100;并且要按照MS的要求定义大小。
            menu.AppendMenu(MF_STRING, 1100+2, _T("退出"));
            POINT point;
            GetCursorPos(&point);
            SetForegroundWindow(); //这里是新添加的
            uCmd = menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD, point.x, point.y, this, NULL);
            PostMessage(WM_NULL, 0, 0); //这里是新添加的
            switch(uCmd)    //    处理菜单消息
            {
            case 1100 + 1 :
                //AfxMessageBox("ok");
                DeleteShellNotifyIcon(0);    //    清除托盘图标
                ShowWindow(SW_SHOWNORMAL); 
                SetForegroundWindow();        //    让程序前置到窗口
                break;
            case 1100 + 2 :
                PostMessage(WM_CLOSE, 0, 0); // 退出程序
                break;
            default:
                break;
            }
        default:
              break;
    }
    return 0;
}
看来,这个问题莫名其妙,就两个函数解决了问题,不知道其中到底有什么毛病,还是没有说明具体问题!网络是个好东东,microsoft更是个好东东!