VC/MFC 程序最小化后不能还原的原因与解决方法

程序最小化后不能还原,一般原因是程序中至少存在一个Popup类型的窗口引起的,因为Popup类型的子窗口即使由于父窗口的隐藏而隐藏,其WS_VISIBLE属性仍然是可见的,当用户再次点击任务栏的程序图标时,Popup窗口会拦截系统(还原)消息,使主程序框架无法接收到系统消息,从而导致主程序无法正常还原。如果将其修改为Child类型的窗口,那么主程序的最小化和还原的功能就可以正常了。不过在实际项目中,往往就需要一个Popup类型的窗口作为子窗口(Popup类型的窗口也可以有父窗口),那么这又如何解决程序最小化后不能还原的问题呢?根据以上分析的原理,只要在主程序最小化时,相应也隐藏掉Popup窗口(ShowWindow(SW_HIDE)),这样系统消息就能够正确传递了;当主程序还原时,再将隐藏的Popup窗口显示出来,这样就既不影响程序的显示效果,又能解决问题了!具体方法如下:

    首先需要在主程序(如MainFrame)中拦截系统消息(响应最大化,最小化,还原,关闭等消息的地方)。其消息为WM_SYSCOMMAND.如在MainFrame.h头文件中加入afx_msg void OnSysCommand(UIND nID,LPARAM lParam);在MainFrame.cpp的BEGIN_MAP与END_MAP之间加入ON_WM_SYSCOMMAND,响应函数为

void CMainFrame::OnSysCommand(UIND nID,LPARAM lParam){}。

    其次根据系统消息对Popup窗口进行隐藏与显示操作,代码如下:

CWnd* m_pPopupWnd;/// Popup类型的窗口指针
void CMainFrame::OnSysCommand(UIND nID,LPARAM lParam)
{
    static BOOL s_bDialogVisible = FALSE;
    /// 如果是最小化消息
    if(SC_MINIMIZE == nID)
    {
       if(NULL != m_pPopupWnd && ::IsWindow(m_pPopupWnd->m_hWnd))
       {
          if(::IsWindowVisible(m_pPopupWnd->m_hWnd))
          {
             s_bDialogVisible = TRUE;
             /// 隐藏Popup类型窗口或具有Popup类型窗口的父窗口
             m_pPopupWnd->ShowWindow(SW_HIDE);
          }
       }
    }
    else    
    {
       if(NULL != m_pPopupWnd && ::IsWindow(m_pPopupWnd->m_hWnd))
       {
          if(TRUE == s_bDialogVisible)
          {
             s_bDialogVisible = FALSE;
             /// 显示Popup类型窗口或具有Popup类型窗口的父窗口
             m_pPopupWnd->ShowWindow(SW_SHOW);
          }
       }
    }
    CWnd::OnSyscommand(nID,lParam);
}

      方法二:拦截系统的还原消息,对其进行自定义的操作,如先设置为活动窗口,然后继续执行还原操作。

   BOOL PreTranslateMessage(MSG* pMsg)
   {
        ASSERT(pMsg);
         /// 如果是激活窗口消息
        if(pMsg->message == WS_APPACTIVE)
          {
              /// 如果是按下左键
              if(pMsg->wParam == VK_LBUTTON)
              {
                 ASSERT(AfxGetMainFrame());
                 /// 激活主窗口
                 SetActiveWindow(AfxGetMainFrame()->m_hWnd);
              }
          }
       /// 可继续向基类传递消息
       return   C**APP::PreTranslateMessage(pMsg);
   }


上半部分文档转至:http://blog.sina.com.cn/s/blog_4b44e1c00100mdkl.html


经测试:在XP上会出现点击任务栏无法还原窗体的情况,Win7上则不会出现。

但是我在程序中遇到这样的问题:


本程序只准用户同时运行一个,肯定会对其加入控制,这种情况在Win7下会有这样的情况,当右击用户栏程序的时候,由于二次运行将不再启动程序,而是将原来最小化的程序显示出来,如上图所示。而这样的话,将不发送WM_SYSCOMMAND消息,也就意味着开始隐藏的Popup窗体在这种情况下将不再显示出来,并不能达到想要的要求,而上面的思路将进入死胡同。经过分析,这种情况是程序启动不成功导致,如果通过进程间通信去解决这个问题,将增加大量的工作,得不偿失啊。回过头来从源头出发重新分析问题,想到了在OnSize()函数上面做文章:

CWnd::OnSize

afx_msg void OnSize(
   UINT nType,
   int cx,
   int cy 
);

参数:
  nType
指定请求的调整大小的类型。 此参数可以是下列值之一:
 SIZE_MAXIMIZED 窗口最大化。
 SIZE_MINIMIZED 窗口最小化。
 SIZE_RESTORED 窗口已调整大小,但是,SIZE_MINIMIZED 和 SIZE_MAXIMIZED 不适用。
在某些其他窗口最大化时,SIZE_MAXHIDE 发送到所有弹出窗口。
在某些其他窗口将还原为其以前的大小时,SIZE_MAXSHOW 发送到所有弹出窗口。
  cx
指定工作区的新的宽度。
  cy
指定工作区的新的高度。

看来可行,解决步骤如下:

1.在主窗体中添加ON_WM_SIZE消息;

2.参照OnSysCommand函数修改OnSize()函数,代码如下:

void CMainFrame::OnSize(UINT nType, int cx, int cy)
{
	CDialog::OnSize(nType, cx, cy);

	// TODO: 在此处添加消息处理程序代码
	static BOOL s_bDialogVisible = FALSE;
	if(SIZE_MINIMIZED  == nType)
	{
		if(NULL != m_pPopupWnd && ::IsWindow(m_pPopupWnd.m_hWnd))
		{
			if(::IsWindowVisible(m_pPopupWnd.m_hWnd))
			{
				s_bDialogVisible = TRUE;
				/// 隐藏有Popup类型窗口或具有Popup类型窗口的父窗口
				m_pPopupWnd.ShowWindow(SW_HIDE);
			}
		}
	}
	else if(SIZE_RESTORED == nType)
	{
		if(NULL != m_pPopupWnd && ::IsWindow(m_pPopupWnd.m_hWnd))
		{
			if(TRUE == s_bDialogVisible)
			{
				s_bDialogVisible = FALSE;
				/// 显示有Popup类型窗口或具有Popup类型窗口的父窗口
				m_pPopupWnd.ShowWindow(SW_SHOW);
			}
		}
	}
}

运行效果很满意,一切OK!!!

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值