执行 GetParent() 时崩溃。关闭无模式对话框

Posted

技术标签:

【中文标题】执行 GetParent() 时崩溃。关闭无模式对话框【英文标题】:Crashing while executing GetParent(). Closing of a modeless dialog box 【发布时间】:2013-06-11 19:09:14 【问题描述】:

我正在创建一个无模式对话框。该对话框从主框架窗口的菜单项中调用。

MainFrm.h

CModeless* modeless;    
bool modelessDlgOpen;     

MainFrm.cpp

void CMainFrame::OnDatabaseMLdlg()     
     
    // TODO: Add your command handler code here     
    if (modelessDlgOpen == TRUE)      
        return;     

    modelessDlgOpen = TRUE;     

    modeless = new CModeless(this);     

    //modeless->Create(IDD_MLDLG, GetDesktopWindow());     
    modeless->Create(IDD_MLDLG, this);     
    mbPoll->ShowWindow(SW_SHOW);     
     

单击菜单项时,将调用 OnDatabaseMLdlg() 函数并出现一个资源 ID 为 IDD_MLDLG 的无模式对话框。

问题是在关闭无模式对话框时。

我无法找到正确关闭/销毁此无模式对话框的正确方法。单击右上角的十字按钮后,会收到哪条消息 生成?

我尝试过的当前代码如下。 (产生只与关闭对话框相关的代码)

MLDLG.h

#pragma once     

#define WM_MLDLG_CLOSED (WM_USER + 555)     
// CModeless dialog     

class CModeless : public CDialog     
     
    DECLARE_DYNAMIC(CModeless)     

public:     
    CModeless(CWnd* pParent = NULL);   // standard constructor     
    virtual ~CModeless();      

// Dialog Data     
    enum  IDD = IDD_MLDLG ;      

protected:     
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support      

    DECLARE_MESSAGE_MAP()     
public:     
    virtual BOOL Create(UINT nIDTemplate, CWnd* pParentWnd = NULL);     
    afx_msg void OnNcDestroy();     
    virtual void PostNcDestroy();     
    CWnd* mParent;     
    afx_msg void OnBnClickedCancel();     
;     

MLDLG.cpp

void CModeless::OnNcDestroy()     
     
    CDialog::OnNcDestroy();     

    // TODO: Add your message handler code here     
     

void CModeless::PostNcDestroy()      
        
    CDialog::PostNcDestroy();     
    GetParent()->PostMessage(WM_MLDLG_CLOSED,0,0);     // **CRASHES HERE**
    delete this;     
     

void CModeless::OnBnClickedCancel()     
     
    // TODO: Add your control notification handler code here     
    //CDialog::OnCancel();     
    DestroyWindow();         
     

无法理解我做错了什么或我错过了什么?

如有需要,我可以提供更多详细信息。

提前致谢。

EDIT-20130612:附加信息:

我的构造函数如下:

CModeless::CModeless(CWnd* pParent /*=NULL*/)    
    : CDialog(CModeless::IDD, pParent)    
    
    mParent = pParent;    
    if (mParent == NULL)    
        
        MessageBox(L"mParent is NULL");   
        
    else    
        
        MessageBox(L"mParent is not NULL");    
        
    

在这里,我已经验证了 mParent 不为 NULL。

【问题讨论】:

GetParent() 是否返回 NULL?如果是这样,您对对话框 Create 函数的覆盖无法将 pParent 传递给 CDialog 构造函数。如果您要向父级发送消息,则必须保存 pParent,并确保它不为 NULL,无论哪种方式。 在构造函数中,我将 pParent 变量保存到成员变量 CWnd* mParent。我认为 GetParent 会返回相同的结果,并且比 mParent-> PostMessage() 之类的更安全。如果我错了,请纠正我。 GetParent 获取窗口的属性。它当然不会得到您的 mParent 成员变量。该属性由 CDialog::Create pParentWnd 参数设置。无论您使用自己的成员变量还是对话框的 pParentWnd(任何一种方式都可以),您都必须确保它不为 NULL。 @ScottMcP-MVP:我替换了我的 GetParent()->PostMessage(WM_MLDLG_CLOSED,0,0);使用 mParent->PostMessage(WM_MLDLG_CLOSED,0,0) 调用;它似乎工作正常。这是正确的方法吗? GetParent() 返回 NULL。 CModeless(CWnd* pParent = NULL);使用 mParent->PostMessage(...);没关系。但是你给构造函数一个默认的 NULL 参数留下了一个定时炸弹。您应该删除 = NULL,这样如果将来有人尝试使用默认版本,它将无法正常工作。 【参考方案1】:

PostNCDestroy() 被调用得很晚,此时 MFC 窗口的大部分有用状态都无效。 GetParent() 可能返回 NULL,这将导致您使用它的方式崩溃。

在调用基类实现之前尝试将PostMessage 调用移至OnDestroy()

另一种选择是缓存父级的 hWnd 并在该 hWnd 上调用 ::PostMessage()

【讨论】:

您的建议是错误且危险的。 PostNcDestroy 是对话框收到的最后一条消息,因此它是唯一安全的成员函数来执行“删除此”。更早删除会导致已删除对象尝试处理消息。 CDialog 文档说“您应该为无模式对话框覆盖 PostNCDestroy 以删除它。” 我不是有意将呼叫转移到delete this,只是将他的PostMessage 呼叫转移到OnDestroy。很抱歉造成混乱。

以上是关于执行 GetParent() 时崩溃。关闭无模式对话框的主要内容,如果未能解决你的问题,请参考以下文章

当我尝试关闭模式时 iOS 崩溃

Android Studio AVD 导致 avd 崩溃,AS 无警告关闭

关闭纵向视图控制器时应用程序崩溃

核心数据 MOC 保存暂停执行并且无法保存(无错误或崩溃)

使用自定义 IDocHostUIHandler 和关闭窗口时崩溃

关闭应用程序时 QQuickItem 析构函数/changeListeners 崩溃(Qt 5.6)