在没有主窗口的MFC应用程序中创建多个对话框,它们成为彼此的子对象

时间:2010-04-28 15:53:08

标签: mfc winapi

(标题已更新) 继this问题之后,现在我更清楚地了解发生了什么......

我有一个没有主窗口的MFC应用程序,它公开了一个API来创建对话框。当我反复调用其中一些方法时,创建的对话框是彼此的父级,而不是所有对象的父级......我不知道为什么。

但是无论如何,即使在创建之后,我也无法将父级更改回NULL或CWnd :: GetDesktopWindow()...如果我调用SetParent后跟GetParent,则没有任何更改。

除了真正奇怪的问题,为什么Windows神奇地将每个对话框教育到最后创建的对话框之外,还有什么我不知道能够将这些窗口设置为桌面的孩子吗?


更新:我找到了所有这些的原因,但没有找到解决方案。从我的对话框构造函数中,我们最终进入:

BOOL CDialog::CreateIndirect(LPCDLGTEMPLATE lpDialogTemplate, CWnd* pParentWnd,
    void* lpDialogInit, HINSTANCE hInst)
{
    ASSERT(lpDialogTemplate != NULL);

    if (pParentWnd == NULL)
        pParentWnd = AfxGetMainWnd();
    m_lpDialogInit = lpDialogInit;

    return CreateDlgIndirect(lpDialogTemplate, pParentWnd, hInst);
}

注意: if (pParentWnd == NULL)pParentWnd = AfxGetMainWnd();

我的对话框构造函数中的调用堆栈如下所示:

  • mfc80d.dll! CDialog :: CreateIndirect (const DLGTEMPLATE * lpDialogTemplate = 0x005931a8,CWnd * pParentWnd = 0x00000000,void * lpDialogInit = 0x00000000,HINSTANCE__ * hInst = 0x00400000)
  • mfc80d.dll!CDialog :: CreateIndirect(void * hDialogTemplate = 0x005931a8,CWnd * pParentWnd = 0x00000000,HINSTANCE__ * hInst = 0x00400000)
  • mfc80d.dll!CDialog :: Create(const char * lpszTemplateName = 0x0000009d,CWnd * pParentWnd = 0x00000000)
  • mfc80d.dll!CDialog :: Create(unsigned int nIDTemplate = 157,CWnd * pParentWnd = 0x00000000)
  • MyApp.exe!CMyDlg :: CMyDlg(CWnd * pParent = 0x00000000)

在调试器中运行,如果我在CDialog :: CreateIndirect中手动将pParentWnd更改回0,一切正常......但我如何在第一时间停止它?

3 个答案:

答案 0 :(得分:7)

一些想法:

首先,您在整个链中传递父窗口的NULL。当MFC试图找到你的应用程序主窗口时它的预测非NULL。

我认为你有两种缓解措施:

  1. 从桌面窗口创建CWnd。 CWnd::GetDesktopWindow将为您提供一个非NULL窗口,用作禁止AfxGetMainWnd调用的父窗口。
  2. 或者追踪到AfxGetMainWnd,找出它从哪里读取主窗口,看看是否有一些设置可以防止它找到你的对话窗口。
  3. 最后一点。 MFC术语很不幸: - 在Windows上,只有子窗口有父窗口。弹出窗口或桌面窗口具有所有者窗口。 CreateWindow接受一个接受所有者的参数,或者正在创建的窗口的父级。区别很重要,因为虽然父窗口可以更改,但所有者不能。 SetParent不会更改弹出窗口或重叠窗口的所有者窗口。

答案 1 :(得分:1)

好的,找到了!

实际上有两个问题。我作为父/所有者传递NULL ...但尝试传递CWnd::GetDesktopWindow()没有帮助,所以我放弃了这个想法,直到找到CDialog::CreateIndirect的行为。这让我仔细看看我的代码,我终于发现MyDialog::MyDialog(CWnd *pParent)正在调用super::Create(NULL),而不是super::Create(pParent) ...因为我们总是在它之前将它传递给NULL从未如此明显。

再一次,难以解决的问题只是距离错字一步之遥!

答案 2 :(得分:0)

MFC一次只能创建一个窗口。至少在黑暗和遥远的过去,当MFC创建Win32窗口时,它需要将MFC CWnd实例与窗口关联。因为窗口接收的第一条消息不是带有LPVUSERDATA参数的WM_CREATE消息MFC将CWnd实例存储在线程局部变量中 - 在不合理的期望下,对CWnd :: WindowProc的下一次调用将是它开始尝试的窗口创建

我不知道如何实际编写代码来破坏这个过程。这一切都取决于你如何以不同的速度创造窗户。