• 重载PreTranslateMessage响应CTreeCtrl控件的回车键后运行程序出现中断ASSERT(::IsWindow(m_hWnd));


    场景:

    在CTreeCtrl控件中编辑完节点名称后按下回车键控件、节点都没有反应,只有鼠标光标点击非该节点编辑框编辑才会生效,所以希望按下回车键也能使编辑生效(即按下回车键后CTreeCtrl控件可以响应 OnTvnEndlabeledit 函数事件。
    在网上查了资料发现重载 PreTranslateMessage 函数可以实现,需要添加回车键消息响应:

    case VK_RETURN:
    	::TranslateMessage(pMsg);
    	::DispatchMessage(pMsg);		//执行完这一行后会响应 ***OnTvnEndlabeledit*** 函数事件
    	break
    • 1
    • 2
    • 3
    • 4

    这样确实会响应 OnTvnEndlabeledit 函数事件,但是程序在执行完 OnTvnEndlabeledit 函数事件之后继续往下执行到重载函数PreTranslateMessage 返回指令后会触发中断:

    return CDialogEx::PreTranslateMessage(pMsg);
    
    • 1

    在这里插入图片描述
    中段代码最终会指示到如下所示的地方:

    //wincore.cpp
    BOOL PASCAL CWnd::WalkPreTranslateTree(HWND hWndStop, MSG* pMsg)
    {
    	ASSERT(hWndStop == NULL || ::IsWindow(hWndStop));
    	ASSERT(pMsg != NULL);
    
    	// walk from the target window up to the hWndStop window checking
    	//  if any window wants to translate this message
    
    	for (HWND hWnd = pMsg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
    	{
    		CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
    		if (pWnd != NULL)
    		{
    			// target window is a C++ window
    			if (pWnd->PreTranslateMessage(pMsg))
    				return TRUE; // trapped by target window (eg: accelerators)
    		}
    
    		// got to hWndStop window without interest
    		if (hWnd == hWndStop)
    			break;										这里最终会中断退出循环
    	}
    	return FALSE;       // no special processing
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    //thrdcore.cpp
    BOOL AfxInternalPreTranslateMessage(MSG* pMsg)
    {
    //	ASSERT_VALID(this);
    
    	CWinThread *pThread = AfxGetThread();
    	if( pThread )
    	{
    		// if this is a thread-message, short-circuit this function
    		if (pMsg->hwnd == NULL && pThread->DispatchThreadMessageEx(pMsg))
    			return TRUE;
    	}
    
    	// walk from target to main window
    	CWnd* pMainWnd = AfxGetMainWnd();
    	if (CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg))
    		return TRUE;
    
    	// in case of modeless dialogs, last chance route through main
    	//   window's accelerator table
    	if (pMainWnd != NULL)
    	{
    		 CWnd* pWnd = CWnd::FromHandle(pMsg->hwnd);
    		 if (pWnd->GetTopLevelParent() != pMainWnd)			//继续进入GetTopLevelParent
    			return pMainWnd->PreTranslateMessage(pMsg);
    	}
    
    	return FALSE;   // no special processing
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    //wincore.cpp
    CWnd* CWnd::GetTopLevelParent() const
    {
    	if (GetSafeHwnd() == NULL) // no Window attached
    		return NULL;
    
    	ASSERT_VALID(this);		//继续进入ASSERT_VALID
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    //objcore
    void AFXAPI AfxAssertValidObject(const CObject* pOb,
    	LPCSTR lpszFileName, int nLine)
    {
    	if (pOb == NULL)
    	{
    		TRACE(traceAppMsg, 0, "ASSERT_VALID fails with NULL pointer.\n");
    		if (AfxAssertFailedLine(lpszFileName, nLine))
    			AfxDebugBreak();
    		return;     // quick escape
    	}
    	if (!AfxIsValidAddress(pOb, sizeof(CObject)))
    	{
    		TRACE(traceAppMsg, 0, "ASSERT_VALID fails with illegal pointer.\n");
    		if (AfxAssertFailedLine(lpszFileName, nLine))
    			AfxDebugBreak();
    		return;     // quick escape
    	}
    
    	// check to make sure the VTable pointer is valid
    	ASSERT(sizeof(CObject) == sizeof(void*));
    	if (!AfxIsValidAddress(*(void**)pOb, sizeof(void*), FALSE))
    	{
    		TRACE(traceAppMsg, 0, "ASSERT_VALID fails with illegal vtable pointer.\n");
    		if (AfxAssertFailedLine(lpszFileName, nLine))
    			AfxDebugBreak();
    		return;     // quick escape
    	}
    
    	if (!AfxIsValidAddress(pOb, pOb->GetRuntimeClass()->m_nObjectSize, FALSE))
    	{
    		TRACE(traceAppMsg, 0, "ASSERT_VALID fails with illegal pointer.\n");
    		if (AfxAssertFailedLine(lpszFileName, nLine))
    			AfxDebugBreak();
    		return;     // quick escape
    	}
    	pOb->AssertValid();				//这里进入AssertValid
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    //wincore.cpp
    void CWnd::AssertValid() const
    {
    	if (m_hWnd == NULL)
    		return;     // null (unattached) windows are valid
    
    	// check for special wnd??? values
    	ASSERT(HWND_TOP == NULL);       // same as desktop
    	if (m_hWnd == HWND_BOTTOM)
    		ASSERT(this == &CWnd::wndBottom);
    	else if (m_hWnd == HWND_TOPMOST)
    		ASSERT(this == &CWnd::wndTopMost);
    	else if (m_hWnd == HWND_NOTOPMOST)
    		ASSERT(this == &CWnd::wndNoTopMost);
    	else
    	{
    		// should be a normal window
    		ASSERT(::IsWindow(m_hWnd));		//最终会中断在这里
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    解决方法:

    网上了解了资料发现PreTranslateMessage可以立即返回,所以修改如下代码:

    case VK_RETURN:
    	::TranslateMessage(pMsg);
    	::DispatchMessage(pMsg);		//执行完这一行后会响应 ***OnTvnEndlabeledit*** 函数事件
    	return(TRUE);	//立即终止消息
    	break
    • 1
    • 2
    • 3
    • 4
    • 5

    备注:

    如上的解决办法虽然可行,但导致该问题的原因仍旧不知,待探寻;
    其中响应OnTvnEndlabeledit 函数事件除了使用下面的代码还有另一种办法:

    ::TranslateMessage(pMsg);
    ::DispatchMessage(pMsg);
    
    • 1
    • 2

    之前说到编辑完节点后鼠标光标点击非该节点编辑框节点编辑也会生效,所以可以将这两行代码改为修改鼠标焦点的指令

    m_treeCtrl.SetFocus();		//其中m_treeCtrl也可以是其他控件
    
    • 1

    参考链接:
    MFC中的PreTranslateMessage
    解决GetDlgItem 使用时出现ASSERT(::IsWindow(m_hWnd))断言
    MFC下拉框中断出错,中断在ASSERT(::IsWindow(m_hWnd));的情况记录

  • 相关阅读:
    十大排序算法汇总
    【JavaScript】JS能力测试题:数组扁平化 | 判断质数 | 获取字符串的长度
    Android使用ANativeWindow更新surfaceView内容最简Demo
    意大利法院判定开源协议条款具有可强制执行性;一个命令即可安装 CSS 框架;LibreOffice 7.3 RC1 发布 | 开源日报
    Ubuntu22.04安装Cuda11.3和Cudnn8.5的深度学习GPU环境
    论文研读-Thread-level transactional memory(TTM)
    C语言刷题系列——1.将三个整数按从大到小输出
    3D激光线扫相机与结构光相机的区别
    如何高效获取电商数据
    C++11提供STL的emplace方法剖析二
  • 原文地址:https://blog.csdn.net/D_daytime/article/details/125996989