Create multiple dialogs in an MFC application without a main window, they become children

(title updated) Following from this question, I now have a clearer idea of ​​what is going on ...

I have an MFC application without a main window that provides an API for creating dialogs. When I call some of these methods repeatedly, the dialogs being created are each other's parents, not all the parent's on the desktop ... I have no idea why.

But anyway, even after creation, I cannot change the parent back to NULL or CWnd :: GetDesktopWindow () ... if I call SetParent followed by GetParent, nothing has changed.

So, aside from the really weird question of why Windows magically brings up every dialog to the last one it created, is there anything I'm missing to set these windows as children of the desktop?


UPDATED . I found the reason for all of this, but not the solution. In my dialog constructor, we ended up with:

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

      

Note: if (pParentWnd == NULL)pParentWnd = AfxGetMainWnd();

The call stack from my dialog constructor looks like this:

  • 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)

Running in the debugger, if I manually change pParentWnd back to 0 in CDialog :: CreateIndirect everything works fine ... but how can I stop this in the first place?

+2


a source to share


3 answers


Some thoughts:

First, you pass NULL for the entire parent window through the chain. It must not be NULL when MFC tries to find your main application window.

As I can see you have two mitigations:



  • Create CWnd from your desktop window. CWnd :: GetDesktopWindow will give you a non-NULL window to use as the parent window, which will prevent AfxGetMainWnd from being called.
  • Or trace to AfxGetMainWnd, find out where it reads the main window, and see if there are any settings to prevent it from being searched in the dialog.

Finally. MFC terminology is unhappy: - On Windows, only child windows have parent windows. Popup windows or dekstop windows have owner windows. CreateWindow takes a single parameter, which takes the owner or parent of the window being created. The distinction is important because although the parent window can be changed, the owner cannot. SetParent does NOT change the owner window for the popup or overlapped window.

+5


a source


OK, found it!

There were actually two problems. I was passing NULL as parent / owner ... but trying to pass CWnd::GetDesktopWindow()

didn't help, so I gave up on this idea until I find the behavior CDialog::CreateIndirect

. This made me take a look at my code and I finally noticed what MyDialog::MyDialog(CWnd *pParent)

was calling super::Create(NULL)

, not super::Create(pParent)

... because we always passed NULL to it before the error was not obvious.



So, again, the tricky problem ended up just one step away from a typo!

+1


a source


MFC can only create one window during IIRC. At least in the dark and distant past, when MFC creates a Win32 window, it needs to associate an MFC CWnd instance with the window. Because the first message the window receives is NOT a WM_CREATE message with the LPVUSERDATA parameter. MFC stores the CWnd instance in a thread local variable - in the unreasonable expectation that the next CWnd :: WindowProc call will be for the window in which it started trying to create.

I have no idea how code can be written to disrupt this process. It all depends on how you could create windows at different speeds.

0


a source







All Articles