您的位置:首页 > 其它

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

2014-03-17 19:49 295 查看
程序最小化后不能还原,一般原因是程序中至少存在一个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!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐