

Программирование на языке MFC
Мой второй блог в серии программирования
Поле m_pMainWnd
Внимательно взглянув на текст этого метода, можно заметить, что в том случае, когда поле m_pMainWnd равно нулю и приложение было загружено системой, а не OLE, работа метода немедленно завершается. При этом в отладочное окно выдается сообщение «Warning: m_pMainWnd is NULL in CWinApp::Run – quitting application.» (Предупреждение: m_pMainWnd равно NULL в методе CWinApp::Run – приложение завершается). Возникает вопрос: что же мы сделали не так, и почему возникла ошибка? Заглянув в список полей нашего объекта-приложения, мы увидим, что поле m_pMainWnd приложение наследует от класса CWinThread. В описании класса CWinThread можно найти следующую запись:
CWnd* m_pMainWnd; // main window
//(usually same AfxGetApp()->m_pMainWnd)
Другими словами, поле m_pMainWnd должно хранить указатель на объект класса CWnd, который должен быть ассоциирован с окном, являющимся ГЛАВНЫМ окном приложения. Но где должен быть создан этот объект? У нас есть две возможности – метод Ini-tApplicationQ и метод lnitlnstance(). Так как метод InitApplicationQ используется MFC для других целей (инициализация менеджера документов), то, чтобы не переписывать метод lnitApplication(), лучше всего будет создать объект класса CWnd в переопределенном методе lnitlnstance(). Отсюда делаем еще один вывод: объект класса CWnd, который будет ассоциирован с главным окном приложения, целесообразно создавать в переопределенном методе InitlnstanceQ приложения.
А теперь давайте еще немного порассуждаем. Если наши рассуждения верны, то объект класса CWnd будет создан во время отработки метода InitlnstanceQ приложения. Но объект приложения будет создан ранее, во время отработки startup-кода! Инициализацией полей класса, в том числе и поля m_pWinMain, должен, естественно, заниматься конструктор класса. Но конструктор класса CWinThread отрабатывает раньше конструктора класса CWinApp и, тем более, раньше метода lnitlnstance() приложения. Следовательно, поле m_pMainWnd после создания объекта приложения остается неинициализированным или содержит неверную информацию. Значит, после того, как в методе InitlnstanceQ будет создано главное окно приложения, полю m_pMainWnd необходимо присвоить значение указателя на ассоциированный с окном объект. В противном случае программа, увы, работать не будет!
Что ж, попробуем немного изменить нашу программу и добавить в нее переопределенный метод lnitlnstance(), в котором будет создан объект класса CWnd. Текст измененной программы:
#include <afxwin.h>
class CExampleApp : public CWinApp {
BOOL Initlnstance() ;
};
class CMainWnd : public CWnd {
};
BOOL CExampleApp::Initlnstance() {
CMainWnd* pMainWnd = new CMainWnd; m_pMainWnd = pMainWnd; return TRUE;
}
CExampleApp theApp;
Похожие статьи: CWinApp, lnitlnstance
