Программирование на языке MFC

Мой второй блог в серии программирования

Поле m_pMainWnd


Внимательно взглянув на текст этого метода, можно заметить, что в том случае, когда поле m_pMainWnd равно нулю и приложение было загружено системой, а не OLE, работа метода немедленно завершается. При этом в отладочное окно выдается сообщение «Warning: m_pMainWnd is NULL in CWinApp::Run – quitting applica­tion.» (Предупреждение: 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;

Похожие статьи: ,