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();
    }
}

所以调试它,逻辑说只要 pParentBarPMainFrame 不是 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
}
...

有理由相信我们的 COutputListGetOwner() 函数将 return 指向 m_wndTabs 成员的指针 CMFCTabCtrl 实例,所以如果我们在 COutputList::OnViewOutput() 中这样写:

CMFCTabCtrl * pParentTabCtrl = DYNAMIC_DOWNCAST(CMFCTabCtrl, GetOwner());

那么pParentTabCtrl将不等于nullptr.

但我不知道如何从 CMFCTabCtrl 实例中获取 CDockablePane 实例(不同的 GetTabWnd 等等不起作用(至少对我而言),并使用 Google 搜索并通过 MFCinternals 搜索也没有结果。

再次: 也许有办法从CMFCTabCtrl得到一个CDockablePane,但现在我不知道它们.


建议的解决方案

所以,我能提供的唯一解决方案是让成员:

COutputWnd        m_wndOutput;

publicCMainFrame 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 方式解决方案,但至少它有效。