1.问题描述
- 加载完菜单提示以下内容
2.分析问题
- 代码如下,加上成员变量m_menu声明和大括号,一共才五行代码
void CTestHelperDlg::OnInitDialog(){
... ...
InitMenu();
InitTabDlg();
... ...
}
void CTestHelperDlg::InitMenu(){
m_menu.LoadMenuA(IDR_MENU);
SetMenu(&m_menu);
}
-
首先怀疑是加载菜单出了问题,检查了好几遍确认没有问题。并且屏蔽加载菜单就能正常运行。又将加载菜单的代码检查了好几遍,还是没发现问题。此时刚接触MFC的我满脑子的问号。 -
根据Visual Studio提示信息,报错出自winocc.cpp第307行。 -
此行代码m_hWnd指针为空,是系统调用执行MoveWindow函数时出的错。至此问题终于有了尽展,也确认了加载菜单没有问题。 -
打开调用堆栈发现,指向ReSize函数。ReSize是为了在调整窗口大小时,使窗口的控件自适应大小,而我自定义的函数,其中就调用了MoveWindow。 -
ReSize函数代码如下,是在触发WM_SIZE消息中调用的ReSize。而在窗口初始化之前m_dlg还未创建,故m_dlg句柄为空。在m_dlg调用MoveWindow前加个空指针判断,再次运行,程序正确运行,问题解决。 - -
OnSize自定义函数如下。
void CTestHelperDlg::ReSize(){
CRect rect;
GetClientRect(rect);
rect.top += 25;
rect.bottom -= 5;
rect.left += 5;
rect.right -= 5;
m_tab.MoveWindow(rect);
m_tab.GetClientRect(rect);
rect.top += 25;
rect.bottom -= 1;
rect.left += 1;
rect.right -= 1;
if(!m_dlg.m_hWnd)
return;
m_dlg.MoveWindow(rect);
m_dlg.ShowWindow(SW_SHOW);
}
- 问题虽已解决,但仍有一个疑问没得到答案:为什么加载菜单前没有触发空指针,加载菜单后反而触发了空指针?
3.再次分析
- 又是一翻折腾发现WM_SIZE消息被触发了两次。
- 第一次触发WM_SIZE:主窗口创建但还未创建完成时,OnSize函数中做了判断,因为主窗口m_rectDlg均为0,所以未触发ReSize。如果,没有加载菜单时WM_SIZE在程序运行前只触发这一次。
void CTestHelperDlg::OnSize(UINT nType, int cx, int cy)
{
CDialogEx::OnSize(nType, cx, cy);
if(!m_rectDlg.Height()&&!m_rectDlg.Width())
return;
ReSize();
}
- 第二次触发WM_SIZE:
1 因为加载了菜单,WM_SIZE消息又一次被触发,此时m_rectDlg已有值,故ReSize被调用。 2 而在OnInitDialog 中先加载的菜单 ,后加载的CTabCtrl 。 3 故加载菜单时,触发WM_SIZE消息时,CTabCtrl 控件上的对话框窗口m_dlg还未创建,用空指针调用MoveWindow也就出问题了。
4. 问题总结
加载菜单会额外触发一次WM_SIZE消息。
|