Создание нескольких диалогов в приложении MFC без основного окна, они становятся дочерними элементами друг друга - PullRequest
2 голосов
/ 28 апреля 2010

(название обновлено) Исходя из этого вопроса, теперь у меня есть более четкое представление о том, что происходит ...

У меня есть приложение 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, недействительно * lpDialogInit = 0x00000000, HINSTANCE 0 * 10 000 * h0)
  • 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 (без знака int nIDTemplate = 157, CWnd * pParentWnd = 0x00000000)
  • MyApp.exe! CMyDlg :: CMyDlg (CWnd * pParent = 0x00000000)

При запуске в отладчике, если я вручную изменяю pParentWnd обратно на 0 в CDialog :: CreateIndirect, все работает нормально ... но как я могу остановить это в первую очередь?

Ответы [ 3 ]

7 голосов
/ 29 апреля 2010

Некоторые мысли:

Во-первых, вы передаете NULL для родительского окна весь путь по цепочке. Он становится ненулевым, когда MFC пытается найти главное окно ваших приложений.

На мой взгляд, у вас есть два смягчения:

  1. Создать CWnd из окна рабочего стола. CWnd :: GetDesktopWindow даст вам ненулевое окно для использования в качестве родительского окна, которое будет блокировать вызов AfxGetMainWnd.
  2. Или проследите в AfxGetMainWnd, выясните, откуда оно читает главное окно, и посмотрите, есть ли какие-то настройки, чтобы он не мог найти ваше диалоговое окно.

На последнем замечании. Терминология MFC вызывает сожаление: - В Windows только дочерние окна имеют родительские окна. Всплывающие окна или окна рабочего стола имеют окна владельца. CreateWindow принимает единственный параметр, который принимает владельца или родителя создаваемого окна. Различие важно, потому что, хотя родительское окно может быть изменено, владелец не может. SetParent НЕ изменит окно владельца для всплывающего или перекрывающегося окна.

1 голос
/ 29 апреля 2010

ОК, нашел!

На самом деле возникли две проблемы.Я передавал NULL как родитель / владелец ... но попытка передать CWnd::GetDesktopWindow() не помогла, поэтому я отказался от этой идеи, пока не нашел поведение CDialog::CreateIndirect.Это заставило меня поближе взглянуть на мой код, и я, наконец, заметил, что MyDialog::MyDialog(CWnd *pParent) вызывает super::Create(NULL), а не super::Create(pParent) ... потому что мы всегда пропускали его NULL, прежде чем ошибка никогда не была очевидна.

Итак, еще раз, трудная проблема оказалась всего в одном шаге от опечатки!

0 голосов
/ 29 апреля 2010

MFC может создавать только одно окно за раз IIRC. По крайней мере, в темноте и в далеком прошлом, когда MFC создает окно Win32, ему необходимо связать экземпляр MFC CWnd с окном. Поскольку первое сообщение, которое получает окно, НЕ является сообщением WM_CREATE с параметром LPVUSERDATA, MFC сохранил экземпляр CWnd в локальной переменной потока - в не безосновательном ожидании, что следующий вызов CWnd :: WindowProc будет для окна, которое он начал пытаться создать.

Я понятия не имею, как можно написать код для подрыва этого процесса. Все зависит от того, как вы могли бы создавать окна с разными скоростями.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...