MFC踩过的一个关于空指针导致程序运行失败的坑


1.问题描述

  • 以下窗口,未加载菜单时运行正常。

在这里插入图片描述

  • 加载完菜单提示以下内容
    在这里插入图片描述

2.分析问题

  • 代码如下,加上成员变量m_menu声明和大括号,一共才五行代码
void CTestHelperDlg::OnInitDialog(){
	... ...
	//初始化菜单
	InitMenu();
	//初始化m_tab	
	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);
	//设置m_tab
	rect.top += 25;
	rect.bottom -= 5;
	rect.left += 5;
	rect.right -= 5;
	m_tab.MoveWindow(rect);
	//设置m_dlg
	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);	

	// TODO: 在此处添加消息处理程序代码
	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消息。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值