使用 WM_PARENTNOTIFY 检测子 CButton 控件何时添加到 CDialog

Detect when a child CButton control is added to CDialog using WM_PARENTNOTIFY

合作对象:

我正在尝试修改 MFC 项目,以便 CDialog 派生 class 检测何时向其添加子控件(CButton 派生 class是)。最好获取这些 CButton 的句柄 (HWND) 以进一步处理它们,就像我可以使用以下代码从父对话框 window 中获取一样:

HWND handleParent = ::GetTopWindow(this->GetSafeHwnd());

我读过一种方法,通过处理 WM_PARENTNOTIFY,但我无法使用主事件函数以任何方式触发它:OnParentNotify(或来自某些来源的 WindowProc)。

我已经完成了以下操作,至少 OnParentNotify:

  1. 添加了消息导出:

ON_WM_PARENTNOTIFY()

  1. 在成员函数 DerivedDialog::OnInitDialog() 中从所有可能的控制句柄中删除了 WS_EX_NOPARENTNOTIFY 样式,在 CDialog::OnInitDialog() 代码行之后:
CDialog::OnInitDialog();

HWND hwnd = ::GetTopWindow(this->GetSafeHwnd());
while (hwnd)
{
    LONG lExStyle;
    lExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);

    if (lExStyle & WS_EX_NOPARENTNOTIFY)
    {
        lExStyle &= ~WS_EX_NOPARENTNOTIFY;
        SetWindowLong(hwnd, GWL_EXSTYLE, lExStyle);
    }

    hwnd = ::GetNextWindow(hwnd, GW_HWNDNEXT);
}
  1. 声明和定义的函数只是为了看它是否被调用:
OnParentNotify(UINT message, LPARAM lParam)
{

CDialog::OnParentNotify(message, lParam)
{
    switch (LOWORD(message))
    {
        case WM_CREATE:
        {
            int a = 3;
            int b = 2;
        }
        break;
        case WM_PARENTNOTIFY:
        {
            int c = 1;
            int d = 0;
        }
    }
}

不幸的是,只有 WM_CREATE 被调用一次(不要认为它是相关的或正确的,因为我有 2 个按钮必须添加到对话框..所以我希望 2 WM_CREATES 如果是这样吗??)。

我真的不确定如何触发调用该消息。任何提示都会非常有帮助!

来自 MSDN documentation:

The system also sends WM_PARENTNOTIFY messages when it creates and destroys a window, but not for controls created from a dialog box template. The system prevents these messages by specifying the WS_EX_NOPARENTNOTIFY style when creating the controls. An application cannot override this default behavior unless it creates its own controls for the dialog box.

据此,所有从对话框模板创建的按钮都不会收到 WM_PARENTNOTIFY。 (您在 DerivedDialog::OnInitDialog() 中的代码没有任何影响)。

如果您动态创建按钮(或 child 控件),WM_PARENTNOTIFY 会起作用。

示例(添加到您现有的代码):

  1. 在对话框中添加 CButton m_sampleButton 成员 header。
  2. 将创建添加到OnInitDialog代码

    m_sampleButton.Create(L"Sample", WS_CHILD|WS_VISIBLE, CRect(10, 10, 100, 100), this, 10);
    

编辑:(灵感来自@Adrian 评论)

另一种解决方案可能是覆盖按钮派生的 class 的 PreSubclassWindow 功能,并将 user-defined 消息发布到 parent window。

按钮class:

#define CUSTOM_CREATE_NOTIFY WM_USER+1001 // (add to header file)

void CCustomButton::PreSubclassWindow()
{   
    CButton::PreSubclassWindow();

    GetParent()->PostMessage(CUSTOM_CREATE_NOTIFY, (WPARAM)m_hWnd);
}

对话框class:

// add to message map
ON_MESSAGE(CUSTOM_CREATE_NOTIFY, OnCustomNotify)

LRESULT CMFCApplication2Dlg::OnCustomNotify(WPARAM wParam, LPARAM)
{   
    // wparam is the HWND to the button.

    return 0;
}