如何“验证” CWnd* 对象?

Posted

技术标签:

【中文标题】如何“验证” CWnd* 对象?【英文标题】:How can I "validate" CWnd* object? 【发布时间】:2016-01-27 16:14:04 【问题描述】:

(最后一行有一个 TL;DR)

我正在实现一个处理程序来关闭在软件应用程序中打开的选定窗口。这是一个粗略的代码:

void CDlg_Dummy_Dialog::OnCloseWindows()

    for (int i = 0; i < m_WindowsInfo.size(); i++) 
        Window_Node *pWN = &m_WindowsInfo.at(i);
        if (pWN->checked && IsWindow(pWN->pWnd->GetSafeHwnd())) 
            pWN->pWnd->GetParentFrame()->SendMessage(WM_CLOSE);
        
    

以下是上面显示的参数的一些声明:

struct Window_Node 
    CString name;
    CString path;
    CWnd *pWnd;
    BOOL checked;
    HICON icon;
    ....
;

class CDlg_Dummy_Dialog : public CDialog 
    ...
protected:
    std::vector<struct Window_Node> m_WindowsInfo;
    ...

此外,Window_Node 可以有多个实例,具有不同的 pWnd 参数,源自单个 CDocument 类(即存在不同类型的窗口以显示文档的不同显示)。

对于此软件,如果文档的第一个窗口(在图中始终为“绿色”窗口类型)关闭,则与该文档关联的所有其他窗口将自动关闭。这就是问题发生的地方。

如果用户从同一个文档中选择多个窗口(其中有绿色窗口),它会在完成第一次迭代时关闭所有窗口,并且所有pWnd 指针现在都指向现在未分配的内存。因此,在下一次迭代尝试调用GetSafeHwnd()时,会提示内存访问冲突错误:

First-chance exception at 0x00000000521B4AD0 (mfc100d.dll) in Settle3D.exe: 0xC0000005: Access violation reading location 0x00000000136943E0.
Unhandled exception at 0x00000000521B4AD0 (mfc100d.dll) in Settle3D.exe: 0xC000041D: An unhandled exception was encountered during a user callback.

我知道,简单的解决方法是在相反方向上迭代向量。但是,我也在尝试将此方法集成到其他几个软件中,它们不一定以相同的方式组织它们的窗口。

所以,在上面所有冗长的问题之后,这里是 TL;DR:

有什么方法可以检查 CWnd* 的实例是否指向有效窗口?

【问题讨论】:

使用释放的对象是未定义的行为。没有办法从中恢复过来。您需要一种从不访问已释放对象的策略。 指针可以指向任何地方:有效位置和无效位置(地址处没有内存等)。当指针指向内存的有效区域时,更难验证。如果没有更好的数据,就无法判断指针指向的是有效对象、相同类型的错误对象还是不兼容类型的对象。 if (pWN-&gt;checked &amp;&amp; IsWindow(pWN-&gt;pWnd-&gt;GetSafeHwnd())) 您没有检查pWN 是否为非NULL,与pWN-&gt;pWnd 相同您也可以通过AfxGetApp()-&gt;m_pMainWnd 直接访问框架窗口 您需要修复您的错误。您的具体错误是:存储冗余信息。如果它不是多余的,您就不会遇到不确定指针是否有效的情况。而且绝对没有办法验证指针是否指向特定类型的对象。 @BarmakShemirani:我已经摆脱了它们,因为即使指针无效,取消引用其中任何一个也不一定返回 NULL。 【参考方案1】:

一种可能性是从您的主窗口开始,如果您发现有问题的 HWND,则递归搜索子窗口。

使用CWnd::GetWindow(GW_CHILD) 获取第一个子窗口,使用CWnd::GetWindow(GW_HWNDNEXT) 获取下一个窗口。

【讨论】:

以上是关于如何“验证” CWnd* 对象?的主要内容,如果未能解决你的问题,请参考以下文章

HWND CWND 转换

(转)CWnd与HWND的区别与转换

MFC使用的风格(CButton, CEdit, CStatic, CWnd等等)

如何正确调用Create或者CreateEx函数生成CWnd类派生类的具有WS_POPUP属性的窗口

CWnd类

有关MFC类与其窗口句柄