MFC MDI OutputWnd.cpp COutputList "Hide" 中的上下文弹出窗口由于 NULL 指针而无法工作
MFC MDI OutputWnd.cpp Context popup in COutputList "Hide" not working due to NULL Pointer
我正在对散乱函数的代码进行一些最后的清理。我的输出窗格直接取自 MFC 向导创建的开箱即用 OutputWnd.cpp
。当您右键单击带有它创建的 3 个选项卡的输出窗格时,上下文选项为 copy/clear/hide。我有复制和清晰的工作。但问题是Hide
。单击时,它会落入函数 void COutputList::OnViewOutput()
,我已对其进行调试以验证它是否落入其中。
函数如下:
void COutputList::OnViewOutput()
{
CDockablePane* pParentBar = DYNAMIC_DOWNCAST(CDockablePane, GetOwner());
CMDIFrameWndEx* pMainFrame = DYNAMIC_DOWNCAST(CMDIFrameWndEx, GetTopLevelFrame());
if (pMainFrame != nullptr && pParentBar != nullptr)
{
pMainFrame->SetFocus();
pMainFrame->ShowPane(pParentBar, FALSE, FALSE, FALSE);
pMainFrame->RecalcLayout();
}
}
所以调试它,逻辑说只要 pParentBar
和 PMainFrame
不是 nullptr
,然后隐藏输出窗格。
发生的事情是 pMainFrame
正常,但 pParentBar
返回为 nullptr
,因此窗格永远不会隐藏。我已经在我的应用程序中对此进行了广泛的尝试,甚至回到了 VS2017
中构建默认项目向导并在那里进行了未修改的测试,甚至开箱即用的解决方案也不起作用。
我查看了所有内容 Google,每个示例都具有与上面完全相同的功能,没有任何修改......这告诉我,没有人真正关心它不起作用。好吧,我想让它工作,但我不确定为什么 GetOwner()
是 returning 一个 nullptr
。我会“期望”MS 会为我们提供一些正常工作的代码,因为它在函数生成中完成了所有工作以使其工作。这就像在代码中播放 Where's Waldo
..
任何人都知道如何修复该部分或开箱即用代码中可能存在的错误吗?
谢谢。
更新:
根据 IInspectable 的问题是它是 DYNAMIC_DOWNCAST
还是 GetOwner()
我进入了这个函数,发现它是一个 _AFXWIN_INLINE
,这是用来决定的函数所有者:
_AFXWIN_INLINE CWnd* CWnd::GetOwner() const
{ return m_hWndOwner != NULL ? CWnd::FromHandle(m_hWndOwner) : GetParent(); }
似乎是一个简单的 true/false 来确定如何 GetOwner
所以我直接将它分为 true 和 false 看看是否 return 像这样:
CDockablePane* pParentBar = DYNAMIC_DOWNCAST(CDockablePane, GetParent());
和
CDockablePane* pParentBar = DYNAMIC_DOWNCAST(CDockablePane, CWnd::FromHandle(m_hWndOwner);
两个 return 都为 NULL,我不完全确定如何拆分 DYNAMIC_DOWNCAST
,因为它是指向指针函数的指针。我做了 delete
DYNAMIC_DOWNCAST
但这只是在编译时产生了更多问题。
我也试过去掉pParentBar
的if条件,当然没有句柄,当你试图执行hide时应用程序崩溃了。
欢迎就如何继续解决此问题提出建议。
试图解释这种行为
是的,你是对的。
如果我们创建一个简单的项目(基于 "MFC App" 模板,"Project Style" 为 "Visual Studio" 和 "视觉风格和颜色" as "Visual Studio 2008") , 那么
even the out of the box solution doesn't work.
为什么会这样?
在创建 COutputList
成员的下一个代码中
...
if (!m_wndOutputBuild.Create(dwStyle, rectDummy, &m_wndTabs, 2) ||
!m_wndOutputDebug.Create(dwStyle, rectDummy, &m_wndTabs, 3) ||
!m_wndOutputFind.Create(dwStyle, rectDummy, &m_wndTabs, 4))
{
TRACE0("Failed to create output windows\n");
return -1; // fail to create
}
...
有理由相信我们的 COutputList 的 GetOwner()
函数将 return 指向 m_wndTabs
成员的指针 CMFCTabCtrl
实例,所以如果我们在 COutputList::OnViewOutput()
中这样写:
CMFCTabCtrl * pParentTabCtrl = DYNAMIC_DOWNCAST(CMFCTabCtrl, GetOwner());
那么pParentTabCtrl
将不等于nullptr.
但我不知道如何从 CMFCTabCtrl
实例中获取 CDockablePane
实例(不同的 GetTabWnd
等等不起作用(至少对我而言),并使用 Google 搜索并通过 MFCinternals 搜索也没有结果。
再次: 也许有办法从CMFCTabCtrl
得到一个CDockablePane
,但现在我不知道它们.
建议的解决方案
所以,我能提供的唯一解决方案是让成员:
COutputWnd m_wndOutput;
public 在 CMainFrame
class 中(或将 CMainFrame
作为 'friend' 代表 COuputList
- 这里大致相同)。
然后实现 COutputList::OnViewOutput()
类似这样的东西:
void COutputList::OnViewOutput()
{
if (CMainFrame* pMainFrame = dynamic_cast<CMainFrame*>(GetTopLevelFrame())) {
if (CDockablePane* pOutputWnd = dynamic_cast<CDockablePane*>(&pMainFrame->m_wndOutput)) {
pMainFrame->SetFocus();
pMainFrame->ShowPane(pOutputWnd, FALSE, FALSE, FALSE);
pMainFrame->RecalcLayout();
}
}
}
当然,这不是真正的 MFC 方式解决方案,但至少它有效。
我正在对散乱函数的代码进行一些最后的清理。我的输出窗格直接取自 MFC 向导创建的开箱即用 OutputWnd.cpp
。当您右键单击带有它创建的 3 个选项卡的输出窗格时,上下文选项为 copy/clear/hide。我有复制和清晰的工作。但问题是Hide
。单击时,它会落入函数 void COutputList::OnViewOutput()
,我已对其进行调试以验证它是否落入其中。
函数如下:
void COutputList::OnViewOutput()
{
CDockablePane* pParentBar = DYNAMIC_DOWNCAST(CDockablePane, GetOwner());
CMDIFrameWndEx* pMainFrame = DYNAMIC_DOWNCAST(CMDIFrameWndEx, GetTopLevelFrame());
if (pMainFrame != nullptr && pParentBar != nullptr)
{
pMainFrame->SetFocus();
pMainFrame->ShowPane(pParentBar, FALSE, FALSE, FALSE);
pMainFrame->RecalcLayout();
}
}
所以调试它,逻辑说只要 pParentBar
和 PMainFrame
不是 nullptr
,然后隐藏输出窗格。
发生的事情是 pMainFrame
正常,但 pParentBar
返回为 nullptr
,因此窗格永远不会隐藏。我已经在我的应用程序中对此进行了广泛的尝试,甚至回到了 VS2017
中构建默认项目向导并在那里进行了未修改的测试,甚至开箱即用的解决方案也不起作用。
我查看了所有内容 Google,每个示例都具有与上面完全相同的功能,没有任何修改......这告诉我,没有人真正关心它不起作用。好吧,我想让它工作,但我不确定为什么 GetOwner()
是 returning 一个 nullptr
。我会“期望”MS 会为我们提供一些正常工作的代码,因为它在函数生成中完成了所有工作以使其工作。这就像在代码中播放 Where's Waldo
..
任何人都知道如何修复该部分或开箱即用代码中可能存在的错误吗?
谢谢。
更新:
根据 IInspectable 的问题是它是 DYNAMIC_DOWNCAST
还是 GetOwner()
我进入了这个函数,发现它是一个 _AFXWIN_INLINE
,这是用来决定的函数所有者:
_AFXWIN_INLINE CWnd* CWnd::GetOwner() const
{ return m_hWndOwner != NULL ? CWnd::FromHandle(m_hWndOwner) : GetParent(); }
似乎是一个简单的 true/false 来确定如何 GetOwner
所以我直接将它分为 true 和 false 看看是否 return 像这样:
CDockablePane* pParentBar = DYNAMIC_DOWNCAST(CDockablePane, GetParent());
和
CDockablePane* pParentBar = DYNAMIC_DOWNCAST(CDockablePane, CWnd::FromHandle(m_hWndOwner);
两个 return 都为 NULL,我不完全确定如何拆分 DYNAMIC_DOWNCAST
,因为它是指向指针函数的指针。我做了 delete
DYNAMIC_DOWNCAST
但这只是在编译时产生了更多问题。
我也试过去掉pParentBar
的if条件,当然没有句柄,当你试图执行hide时应用程序崩溃了。
欢迎就如何继续解决此问题提出建议。
试图解释这种行为
是的,你是对的。
如果我们创建一个简单的项目(基于 "MFC App" 模板,"Project Style" 为 "Visual Studio" 和 "视觉风格和颜色" as "Visual Studio 2008") , 那么
even the out of the box solution doesn't work.
为什么会这样?
在创建 COutputList
成员的下一个代码中
...
if (!m_wndOutputBuild.Create(dwStyle, rectDummy, &m_wndTabs, 2) ||
!m_wndOutputDebug.Create(dwStyle, rectDummy, &m_wndTabs, 3) ||
!m_wndOutputFind.Create(dwStyle, rectDummy, &m_wndTabs, 4))
{
TRACE0("Failed to create output windows\n");
return -1; // fail to create
}
...
有理由相信我们的 COutputList 的 GetOwner()
函数将 return 指向 m_wndTabs
成员的指针 CMFCTabCtrl
实例,所以如果我们在 COutputList::OnViewOutput()
中这样写:
CMFCTabCtrl * pParentTabCtrl = DYNAMIC_DOWNCAST(CMFCTabCtrl, GetOwner());
那么pParentTabCtrl
将不等于nullptr.
但我不知道如何从 CMFCTabCtrl
实例中获取 CDockablePane
实例(不同的 GetTabWnd
等等不起作用(至少对我而言),并使用 Google 搜索并通过 MFCinternals 搜索也没有结果。
再次: 也许有办法从CMFCTabCtrl
得到一个CDockablePane
,但现在我不知道它们.
建议的解决方案
所以,我能提供的唯一解决方案是让成员:
COutputWnd m_wndOutput;
public 在 CMainFrame
class 中(或将 CMainFrame
作为 'friend' 代表 COuputList
- 这里大致相同)。
然后实现 COutputList::OnViewOutput()
类似这样的东西:
void COutputList::OnViewOutput()
{
if (CMainFrame* pMainFrame = dynamic_cast<CMainFrame*>(GetTopLevelFrame())) {
if (CDockablePane* pOutputWnd = dynamic_cast<CDockablePane*>(&pMainFrame->m_wndOutput)) {
pMainFrame->SetFocus();
pMainFrame->ShowPane(pOutputWnd, FALSE, FALSE, FALSE);
pMainFrame->RecalcLayout();
}
}
}
当然,这不是真正的 MFC 方式解决方案,但至少它有效。