• MFC定时关机程序的实现3-最小化到托盘栏


    这个定时关机运行过后默认最小化到托盘栏最好了,不用每次都去点了。

    现在来看看如何将程序显示在托盘栏。

    首先在头文件里声明一个变量和一个消息响应函数

    1     //最小化到托盘栏
    2     //第一步,生成一个成员变量,或者一个全局变量
    3     NOTIFYICONDATA m_NOTIFYICON;
    4     //第二步,添加自定义消息响应函数
    5     afx_msg LRESULT OnNotifyIcon(WPARAM wParam,LPARAM lParam);

    然后初始化消息相关的参数

    //第三步,添加消息标识
    #define WM_NC WM_USER + 1001

    现在添加消息映射

    //第四步,添加消息映射
        ON_MESSAGE(WM_NC, &OnNotifyIcon)

    最后定义消息响应函数,这里主要是做一些相应鼠标操作,比如左键单击,右键单击等的事件

    LRESULT CAutoShutDownDlg::OnNotifyIcon(WPARAM wParam,LPARAM lParam)
    {
        ////最小化图标,,wParam接收的是图标的ID,而lParam接收的是鼠标的行为
        if (wParam == IDI_ICON1)
        {
            return 1;
        } 
        switch(lParam)
        {
        case WM_LBUTTONDOWN:
            {
                //鼠标单击图标时的动作
                if (AfxGetApp()->m_pMainWnd->IsWindowVisible())//判断窗口当前状态  
                {
                    //窗口未最小化
                    AfxGetApp()->m_pMainWnd->ShowWindow(SW_HIDE);
                } 
                else
                {
                    AfxGetApp()->m_pMainWnd->ShowWindow(SW_SHOW);
                }
            }
            break;
        case WM_RBUTTONUP:
            {
                ////右键起来时弹出快捷菜单,这里只有一个“关闭”  
                LPPOINT lp = new tagPOINT;//鼠标位置结构
                ::GetCursorPos(lp);//获得鼠标位置
                CMenu menu;
                menu.CreatePopupMenu();//声明一个弹出式菜单
                //增加菜单项“退出”,点击则发送消息WM_DESTROY给主窗口(已隐藏),将程序结束。     
                menu.AppendMenu(MF_STRING,WM_DESTROY,"退出");
                menu.TrackPopupMenu(TPM_LEFTALIGN,lp->x,lp->y,this);
                //资源回收
                HMENU hmenu = menu.Detach();
                menu.DestroyMenu();
                delete lp;
            }
            break;
        default:
            break;
        }
        return 0;
    }

    这些操作完成后还要有一个初始化操作OnInitDialog()

        //最小化到托盘代码初始化
        m_NOTIFYICON.cbSize = sizeof(NOTIFYICONDATA);//这个是必须的,指定结构大小
        m_NOTIFYICON.hIcon = AfxGetApp()->LoadIcon(IDI_ICON1);//指定在托盘显示的图标,这个图标可以自己导入
        m_NOTIFYICON.hWnd = m_hWnd;//指定窗口句柄
        m_NOTIFYICON.uID = IDR_MAINFRAME;//托盘图标ID
        m_NOTIFYICON.uCallbackMessage = WM_NC;//自定义的消息函数
        lstrcpy(m_NOTIFYICON.szTip,"定时关机");//在托盘栏显示的提示信息
        m_NOTIFYICON.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;//
        Shell_NotifyIcon(NIM_ADD,&m_NOTIFYICON);//在托盘显示图标

    最后一点就是在程序退出时销毁图标

    1     //退出程序时销毁图标
    2     Shell_NotifyIcon(NIM_DELETE,&m_NOTIFYICON);//

    这里面用到了一个结构  NOTIFYICONDATA

     1 typedef struct _NOTIFYICONDATA { 
     2     DWORD cbSize; // 结构的大小,必须在程序中给出
     3     HWND hWnd;    // 程序中将要接收托盘消息的窗口句柄
     4     UINT uID;     // 应用程序中定义的托盘图标ID,此参数用作标识
     5     UINT uFlags;  //设置属性 标记下边3个参数是否有效
     6     UINT uCallbackMessage;// 自定义的消息ID值
     7     HICON hIcon;//显示在系统托盘上的Icon的句柄
     8     #if (_WIN32_IE < 0x0500)
     9         TCHAR szTip[64;// 用于图标显示的提示字符串
    10     #else
    11         TCHAR szTip[128];
    12     #endif
    13     #if (_WIN32_IE >= 0x0500)
    14         DWORD dwState; 
    15         DWORD dwStateMask; 
    16         TCHAR szInfo[256]; 
    17         union {
    18             UINT  uTimeout; 
    19             UINT  uVersion; 
    20         } DUMMYUNIONNAME;
    21         TCHAR szInfoTitle[64]; 
    22         DWORD dwInfoFlags; 
    23     #endif
    24     #if (_WIN32_IE >= 0x600)
    25         GUID guidItem;
    26     #endif
    27 } NOTIFYICONDATA, *PNOTIFYICONDATA;

    后面的一些参数默认就好,不要配置

    还有一点就是怎么保证程序只有一个进程在运行

     有两种方法可以实现,第一通过全局互斥变量,第二通过查找窗口名

      第一,全局互斥变量

      在应用程序类中声明一个全局变量

         HANDLE hMutex;

       然后在应InitInstance()函数中添加如下代码

    1     hMutex = ::CreateMutex(NULL,TRUE,"FIRSTDLG");
    2     if(hMutex != NULL)
    3     {
    4         if (GetLastError() == ERROR_ALREADY_EXISTS)
    5         {
    6             AfxMessageBox("已经有一个程序在运行了");
    7             exit(0);
    8         }
    9     }

      第二,findwindow函数实现

      添加一个成员函数,函数定义如下,只需要在初始化时判断一下就行了

     1 BOOL CAutoShutDownApp::FirstInstance()
     2 {
     3     CWnd *pWndPrev, *pWndChild;
     4 
     5     // 通过窗口标题查找窗口是否已经打开。成功则返回指向窗口的句柄,否则为NULL
     6     pWndPrev = CWnd::FindWindow(NULL, "定时关机");
     7     if (NULL != pWndPrev)
     8     {
     9         // 存在这个窗口,获取上一次的状态
    10         pWndChild = pWndPrev->GetLastActivePopup();
    11 
    12         // 是否最小化了,还原
    13         if (pWndPrev->IsIconic())
    14             pWndPrev->ShowWindow(SW_RESTORE);
    15 
    16         //显示到最上层
    17         pWndChild->SetForegroundWindow();
    18 
    19         return FALSE;
    20     }
    21 
    22     return TRUE;
    23 }

      在初始化时进行查找,在InitInstance()函数里添加如下代码

    if (!FirstInstance())
        {
            return FALSE;
        }

    当然还有其他方法,不过这两种比较简单。

    FindWindow()函数定义如下,两个参数必须至少有一个有效
    1 static CWnd* PASCAL FindWindow(
    2    LPCTSTR lpszClassName,//窗口类名
    3    LPCTSTR lpszWindowName //窗口标题
    4 );//

     还有一个问题要说的,就是程序启动后自动隐藏的情况,原来是想着直接在里面ShowWindow(SWP_HIDE);来实现的,不过很遗憾这条语句根本不起作用,因为窗口的现实是在初始化之后的某个地方显示的。

    GetWindowPlacement,SetWindowPlacement这两个函数可以实现这个功能。

    过程如下,首先我们需要一个成员变量来保存这个窗口的一些配置信息。

      WINDOWPLACEMENT m_wp;

    在OnInitDialog中进行初始化

    1 //程序启动后自动隐藏到托盘栏
    2     GetWindowPlacement(&m_wp); //恢复时用
    3     ModifyStyleEx(WS_EX_APPWINDOW,WS_EX_TOOLWINDOW);//从任务栏中去掉.
    4 
    5     WINDOWPLACEMENT wp;//声明结构
    6     wp.length=sizeof(WINDOWPLACEMENT);//制定大小
    7     wp.flags=WPF_RESTORETOMAXIMIZED;//标志
    8     wp.showCmd=SW_HIDE;//状态
    9     SetWindowPlacement(&wp);//设置隐藏

    然后在OnNotifyIcon()函数中进行鼠标相应

     1 LRESULT CAutoShutDownDlg::OnNotifyIcon(WPARAM wParam,LPARAM lParam)
     2 {
     3     ////最小化图标,,wParam接收的是图标的ID,而lParam接收的是鼠标的行为
     4     if (wParam == IDI_ICON1)
     5     {
     6         return 1;
     7     } 
     8     switch(lParam)
     9     {
    10     case WM_LBUTTONDOWN:
    11         {
    12             //鼠标单击图标时的动作
    13             if (AfxGetApp()->m_pMainWnd->IsWindowVisible())//判断窗口当前状态  
    14             {
    15                 //窗口未最小化
    16                 AfxGetApp()->m_pMainWnd->ShowWindow(SW_HIDE);
    17             } 
    18             else
    19             {
    20                 AfxGetApp()->m_pMainWnd->ShowWindow(SW_SHOW);
    21 
    22                 m_wp.length=sizeof(WINDOWPLACEMENT);
    23                 m_wp.flags=WPF_RESTORETOMAXIMIZED;
    24                 m_wp.showCmd=SW_SHOW;
    25                 SetWindowPlacement(&m_wp);
    26             //    在这里恢复显示状态
    27             }
    28 
    29         }
    30         break;
    31     case WM_RBUTTONUP:
    32 
    33 
    34 .............................
    35 
    36 
    37 
    38 }

    现在可以实现启动后隐藏了,但是还有一个问题那就左键单击图标后,窗口显示在最上层了,但是标题栏却是未激活状态,没有重绘。所以接下来添加一个重绘框架函数

    OnNcPaint()

    void CAutoShutDownDlg::OnNcPaint()
    {
        // TODO: 在此处添加消息处理程序代码
        // 不为绘图消息调用 CDialogEx::OnNcPaint()
        static int i = 2;
        if (i>0)
        {
            i--;
            ShowWindow(SW_HIDE);
        }
        else
            CDialogEx::OnNcPaint();
    
    }

    到现在基本完成了。

     这里是源代码,这个博客园的文件上传貌似不太好用,就用百度云了,运行环境是vs2010+win7 64位

     http://pan.baidu.com/s/1i35gqET

  • 相关阅读:
    5.3 存储器、I/O和配置读写请求TLP 分类: 浅谈PCI-E 2013-07-22 16:28 413人阅读 评论(0) 收藏
    5.2 TLP的路由 分类: 浅谈PCI-E 2013-07-22 16:28 337人阅读 评论(0) 收藏
    5.1 TLP的格式 分类: 浅谈PCI-E 2013-07-22 16:27 464人阅读 评论(0) 收藏
    第5章 PCIe总线的事务层 分类: 浅谈PCI-E 2013-07-22 16:27 345人阅读 评论(0) 收藏
    1016. Phone Bills (25)
    1018. Public Bike Management (30)
    1076. Forwards on Weibo (30)
    1034. Head of a Gang (30)
    1021. Deepest Root (25)
    1013. Battle Over Cities (25)
  • 原文地址:https://www.cnblogs.com/songliquan/p/3711259.html
Copyright © 2020-2023  润新知