• 重载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));的情况记录

  • 相关阅读:
    结构体、枚举、位段、联合体详解
    关于四元数归一化
    MySQL事务
    勒索软件频繁升级,了解常见勒索软件很有必要
    自动化测试框架Pytest(三)——自定义allure测试报告
    LeetCode 41. First Missing Positive
    【Linux】进程控制
    C++ std::pair and std::list \ std::array
    综合布线工程测试技术
    游戏安全组件运行时发生异常1-0-0
  • 原文地址:https://blog.csdn.net/D_daytime/article/details/125996989