    Основы MFC 

    В этой главе будут рассмотрены основные элементы MFC-программы. Мы напишем 
небольшую программу, которую затем будем использовать в качестве основы для 
всех остальных примеров в книге. Таким образом, в главе будут изложены основы 
программирования с использованием библиотеки MFC. Вы узнаете об иерархии 
классов MFC, о структуре MFC-программы, о том, как создать окно и приложение. 
Поскольку иерархия классов является ядром MFC, то с нее и начнем. 

    23 

    Если вы уже умеете писать программы для Windows, у вас может возникнуть 
желание пропустить данную главу и начать читать со следующей. Но не стоит 
торопиться, ведь программы, написанные с использованием MFC, имеют ряд важных 
отличий и уникальных особенностей, с которыми вы, возможно, не знакомы. 
Поэтому, даже если вы считаете себя опытным программистом, советуем все же 
внимательно прочесть эту главу. 

    Иерархия классов MFC 

    Как уже упоминалось в главе 1, библиотека MFC содержит иерархию классов, 
написанных на языке C++. Структура иерархии представлена на рис. 2.1. В ее 
вершине находится класс CObject. Он содержит различные функции, используемые 
во время выполнения программы и предназначенные, в частности, для 
предоставления информации о текущем типе данных, а также для идентификации и 
диагностики. Применительно к CObject идентификация означает механизм, 
благодаря которому объект может быть записан на диск (или другое запоминающее 
устройство) и впоследствии восстановлен (обычно при последующем вызове 
программы). Мы не будем непосредственно использовать элементы, определенные в 
CObject, хотя в своих программах вы, конечно, можете это делать. Но поскольку 
этот класс является предком большинства других классов MFC, его свойства 
наследуются во всех порожденных классах. 
    Из рис. 2.1 видно, что некоторые классы порождаются непосредственно от 
CObject. Наиболее широко используемыми среди них являются CCmdTarget, CFile, 
CDC, CGdiOb-ject, CException и CMenu. Класс CCmdTarget предназначен для 
обработки сообщений. Если помните, в главе 1 говорилось о том, что Windows 
взаимодействует с программой через механизм сообщений, который в общем и 
реализован в CCmdTarget. Класс CFile предназначен для работы с файлами, в 
частности с файлами на диске. Класс CDC обеспечивает поддержку контекстной 
связи с устройством (под устройством здесь понимается преимущественно экран). 
Об этом мы будем говорить немного позднее, но если вкратце, то контекст 
устройства определяет некоторую экранную среду (такую как окно). jBjToj класс 
также включены функции отображения различных объектов (например линий и 
окружностей) в окне. CGdiObject является базовым классом для различных 
GDI-объектов. Такие объекты достаточно часто используются в приложениях 
Windows, поскольку позволяют хранить графические образы и реализовывать 
различные инструменты рисования, такие как "кисти" и "перья". Класс CException 
предназначен для обработки особых ситуаций, a CMenu — для создания меню. 
Помимо вышеперечисленных, есть еще несколько классов, порождаемых 
непосредственно от CObject и предназначенных для синхронизации потоков, а 
также для работы с базами данных, массивами, списками и преобразователям и типов. 
    От класса CCmdTarget порождается очень важный класс: CWnd. Он является 
базовым для создания всех типов окон, включая масштабируемые ("обычные") и 
диалоговые окна, а также различных элементов управления окна. Наиболее широко 
используемым классом, порождаемым от CWnd, является CFrameWnd. Он обеспечивает 
поддержку так называемых SDI-окон (SDI — Single Document Interface — Интерфейс 
единого документа). Такие окна рекомендуется использовать в новых 

    24      MFC: основы программирования 

    Windows-приложениях.  Как вы увидите,  в большинстве программ  главное 
окно создается именно с помощью данного класса. В классах, порождаемых от 
CFrameWnd, будет  инициализи2рвать?я^саередь сообщений программы  (о  ней речь 
пойде-Г дальше).	'                   -.••'•. 
    Другим классом, порождаемым от CCmdTarget, является CWinThread. С его 
помощью создается поток выполнения~прШГожёния и поддерживается механизм 
потоковой многозадачности. Немного позже мы рассмотрим работу с 
многопотоковыми программами. 
    От CWinThread порождается, наверное, единственный из наиболее важных 
классов, q6jgaiuemjej< которому в МРС-прогтзаммах^троисходит напрямую: 
CWinApp. Хотя он расположен лишь на четвертом уровне иерархии в MFC, тем не 
менее он является одним из фундаментальных классов, поскольку предназначен для 
создания самого приложения. В частности, он позволяет управлять загрузкой, 
инициализацией, выполнением и завершением приложения. ^_каждой программе 
имеется один (и только_один) объект класса CWinApp. Как только он будет 
создан, приложение начнет выполняться. 
    В примере, описанном в данной главе, непосредственно используются лишь два 
класса из иерархии MFC. Впоследствии, конечно, будут задействованы и многие 
другие. Чтобы научиться программировать под Windows с использованием MFC, 
необходимо хорошо понимать иерархию классов библиотеки. 
    Несмотря на внушительный размер иерархии, не стоит ее пугаться. Как вы 
увидите, каждый класс связан с конкретной операцией или подсистемой Windows. 
Прочитав книгу, вы сможете без проблем работать с любым из классов библиотеки. 

    Функции-члены в MFC 

    Большинство функций, вызываемых в MFC-программе, являются членами 
рд-н?го_из_классов, определенных в библиотеке. Вот несколько примеров: 
    •    Функция, позволяющая отобразить окно, называется ShowWindow() и 
является членом класса CWnd. 
    •    Для вывода текстовой строки в окно используется функция TextOut() — 
член класса CDC. 
    • Для загрузки в память битового образа используется функция 
CBitmap::LoadBitmap(). Как уже упоминалось в главе 1, большинство функций API 
(из Win32 или Winl6) доступны через функции-члены MFC. Именно по этой причине 
последние используются так часто. Но важно помнить, что всегда можно 
обращаться непосредственно к самим API-функциям. Просто в большинстве операций 
удобнее использовать соответствующую функцию-член. 

    2. Основы MFC	25 

    Архитектура приложения 
    CDocument 
    пользовательские 
    объекты 
    CWinApp 
    COIeControtModuIe 
    пользовательские приложения 
    CDocTemplate 
    COIeDocument COIeLinkingDoc :COIeServerDoc 
    CRichEditDoc 
    СSingle DocemplatefСMu It iDocTem plate COIeObjectFactory 
    COIeTemplateServer 
    пользовательские документы 
    Особые ситуации CException Ю Archive Except ion 
    !pj^!Egggptbji... — 
    iCDBException 
    'CFileException 
    CDocltem 
    COIeCtientltem 
    • CMemoryException 
    _™_____J 
    COIeDate^urce^^l COteDropSource	[ COIeDropTarget I 
    CRichEditCnlrltem 
    пользовательские OLE-клиенты 
    COIeServerltem 
    gpleMessageFllter CCpnneciionPoInt Поддержка окон CWnd 
    пользовательские OLE-серверы 
    iCNotSupportedExceptionl ' COleException______I ICOIeDispatchExceptlonJ 
CResourceException | iCUserException ____I 
    Масштабируемые окна 
    CTTameWnd_______j 
    '?5f?Hli!2^2i_™_— пользовательские MDI-окна 
    V 
    CMDIFrameWnd 
    пользовательские MDI-оболочки 
    CMiniFrameWnd 
    пользовательские SDI-окна 
    iCptelip^^^^^^ 
    Панели элементов управления 
    CControlBar     _____ ;CDialogBar • COleResizeBar___ 
    CStatysBar    ____ 
    CToolBar 
    si^E^^ZZZIZ 
    Листы свойств CPropertySheet      __ 
    •у 
    Диалоговые окна	\ 
    ?2iaJo?™™___™™J	^ 
    CCofnmonDialog        "	I 
    ^J CnieDialog	j CFindReplacePialog | CFonlDialog 
    COIeDialog _______ ^COIeBusyDialoQ ^^^| COIeChangelconDialog J 
COieChangeSqurceDjajogJ CpleConyertDialgg J COIelnsertDialog___] ; j ; COIeLinksDialog____1 
    COIeUpdateDialog COIePasteSpecialDialggj COIePrgpertlesDlalog     ! 
CPageSetupDialog         | CPrintDialog	___I 
    ^COIePropertyPage 
    CPropertyPage 
    пользовательские диалоговые окна 
    Области просмотра 
    CVjew 
    'CCtrMew________j CEdHVi^________| CListView_______ CRichEditVie^r'      ^ CTreeView 
    !CScrollView   _____j 
    пользовательские области с прокруткой 
    CFqrmView_______ 
    пользовательские формы ввода 
    CDaoRecgrdyiew_   _ CRecordView_____ 
    пользовательские области просмотра записей 


    26 MFC: основы программирования 


    Классы, не порождаемые от CObject 
    Работа с файлами CFile	\л    Графические объекты J    V j fcGdiObject      
               |	•   f  Массивы -/ ' '••  CArray (template)	Поддержка модели объекта	V 
    :   CMemFile	j     i       CBitmap	j     >   CByteArray	CArchive	1 
    jCOIeStreamFile	I             CBrush	J     ; iCDWordArray	CDumpContext	1 
    CSocketFile	j              CFont	I         icdbArray	CRuntirneClass	1 
    !CStdioFile	i              CPalelte	1        ;CPtrArray	Простые типы данных	V 
    Отображение графики	! •     CPen	j         i CStringArray	CPoint 
    :CDC	j                :CRgn	|        ICUIntArray	CRect 
    ,   i fcClientDC	J          Меню	:,  t ' , CWord Array	CSize 
    ;   i {CMetaFiieDC	]        ;CMenu                              J	**       
массивы типов,	CString 
    i jCPaintDC	i _ [         Поддержка ODBC	у       : пользователем	CTime 
    fcWindowDC	|         CDatabase                      j	Списки	. /      CTimeSpan 
    Поддержка элементов	, ,'  'CRecordset                    |	CList (template)	Структуры	v 
    ClmageList	пользовательские j                   наборы 
записей	CPtrList	CCommandLinelnfo CCreateContext 
    CLongBinary                      |	iCStringList	CFileStatus 
    Поддержка ОАО	списки типов,	CMemoryState 
    CDaoDatabase                j	задаваемых пользователем	CPrintlnfo 
    ............                                                    
)	CDaoOueryDef                [		Классы поддержки	V 
    »»«*«**»««««.                    Элементы управления i CAnimateCtrl 
jCButton iCBitmapButton	'y'       CDaoRecordset              j iCDaoTableDef   
              j CDaoWorkspace             | ^J          Синхронизация	• [СМар 
(template) ICMapWordToPtr CMapPtrToWord	CCmdUI CDaoFieldExchange CDataExchange CFieldExchange 
    CComboBox CEdit CHeaderCtrl ICHotKeyCtrl	CSyncObject                    i 
CCriticalSection            _J CEvent CMutex	CMapWordToOb CMapStringToPtr 
:CMapStringToOb	COIeDataObject COIeDispatchDriver CPropExchange CRectTracker 
    CListBox	CSemaphore		CWaitCursor 
    CCheckListBox	Поддержка                          (	,   '   типов, задаваемых	Типизированные	•i 
    :CDragListBox	—           CAsyncSockel                 j	•*        
пользователем	коллекции CTypedPtrArray             | 
    CListCtrl	CSocket		CTypedPtrList                   | 
    | CProgressCtrl 
    Шаблоны OLE-типов	V 
    CFontHolder                   J 
    jCScrollBar                      v			CPictureHolder                | 
    ;CSIiderCtrl 
    ;CSpinButtonCtrl			OLE-автоматизации	,/ 
    ;CStatic			COIeCurrency                   j 
    ;CStatusBarCtrl			COIeDateTime      ____ j 
    CTabCtrl			COIeDateTimeSpa         J 
    jCToolBarCttl			COIeVariant                      | 
    iCToolTipCtrl			Синхронизация 
    iCTreeCtrl			CMultiLock                       J 
    CSingleLock                      | 

    Puc. 2.1. Иерархия классов библиотеки MFC 
    (Структура иерархии напечатана с разрешения Microsoft Corporation) 


    2. Основы MFC  27 


    Глобальные функции в MFC 

    В большинстве случаев взаимодействие с Windows осуществляется через 
функции-члены классов MFC. Однако это не обязательное правило. В библиотеке 
есть и ряд глобальных функций, которые также можно свободно использовать. Все 
они начинаются с префикса Afx. Например, одной из наиболее широко используемых 
"функций является AfxMessageBox(). В главе 4 будет показано, как с ее помощью 
отобразить на экране окно сообщения. Поскольку этот тип окон является заранее 
определенным, такое окно можно отображать независимо от других окон 
приложения. (В противном случае необходимо использовать соответствующую 
функцию-член.) Иначе говоря, Afx-функции могут быть либо независимыми, либо 
перекрываться иерархией классов. 

    Файл AFXWIN.H 
    Все MFC-программы должны включать файл AFXWIN.H. В нем (а также в 
различных вспомогательных файлах) содержатся описания классов библиотеки MFC. 
Он автоматически подключает большинство других библиотечных файлов, 
относящихся к MFC, в том числе файл WINDOWS.H. Как известно, этот файл 
используется в обычных Windows-программах. В нем содержатся прототипы 
API-функций и определены многочисленные константы. Включая файл AFXWIN.H в 
свою программу, вы тем самым подготавливаете все необходимое для создания Windows-приложения. 

    Каркас MFC-программы 

    Теперь мы приступим к созданию небольшого приложения с использованием MFC. 
Как уже было сказано, все MFC-программы имеют много общих элементов. В данном 
параграфе мы напишем простую программу, которая послужит основой для написания 
всех остальных программ, приведенных в книге. 
    В простейшем случае программа, написанная с использованием MFC, содержит 
два класса, порождаемые от классов иерархии библиотеки: класс, предназначенный 
для создания приложения, и класс, предназначенный для создания окна. Другими 
словами, для создания минимальной программы необходимо породить один класс, 
определяющий непосредственно приложение, и второй класс, определяющий главное 
окно приложения. Первый порождается от CWinApp, второй — от CFrameWnd. Хотя в 
программе могут, при необходимости, наследоваться любые классы, но эти два 
обязательны для любой программы. 
    Кроме создания вышеупомянутых классов, в программе также должна быть 
организованаГобработка всех сообщений, поступающих от Windows. Поскольку в 
данном примере не производится ничего, кроме отображения окна, нет и 
необходимости отвечать на каждое сообщение. Однако механизм обработки 
сообщений все же должен присутствовать. 
    Для создания MFC-программы необходимо выполнить следующие действия: 
    1.    От CFrameWnd породить класс, определяющий окно. 
    2.    От CWinApp породить класс, определяющий приложение. 

    28	MFC: основы программирования 

    3.    Создать очередь сообщений. 
    4.    Переопределить функцию InitlnstanceQ класса CWinApp. 
    5.    Создать экземпляр класса, определяющего приложение. 
    Прежде чем продолжить чтение, протестируйте данный пример. В нем создается 
стандартное окно, содержащее заголовок, системное меню, а также кнопки 
минимизации, максимизации и закрытия. Таким образом, это окно можно 
сворачивать, раскрывать на весь экран, перемещать, масштабировать и закрывать. 

    // Минимальная MFC-программа tinclude <afxwin.h> 
    // Порождение основных классов 
    // Это класс, предназначенный для создания главного окна class CMainWin : 
public CFrameWnd      J { public: 
    CMainWin () ;	"2 
    DECLAREjyiESSAGE_MAP ()	-^ } 
    //   Создание   окна	/ijjjjjtfi CMainWin:: CMainWin ()        М^+ЛА^^ЩУ'*^fa. 
    Create(NULL, "An MFC Application Skeleton"); 
    } 
    // Это класс, предназначенный для создания приложения class САрр : public CWinApp	0. 
    public: 
    BOOL Initlnstance (); } 
    // Инициализация приложения 
    BOOL САрр::Initlnstance ()	Ц
    { 
    m_pMainWnd = new__CMainWin; 
    m_pMainWnd->ShowWindow (m_nCmdShow) ;  "WAfjhr  r^Jt* 
    m_pMainWnd->UpdateWindow();	f О 
    return TRUE; } 
    // Это очередь сообщений приложения BEGIN_MESSAGE_MAP(CMainWin, CFrameWnd) 
   "2 END_MESSAGE_MAP()	"* 
    САрр Арр; // создание экземпляра приложения 
    ,———————	_j 


    2. Основы MFC	29 

    Результат выполнения программы показан на рис. 2.2. Давайте пошагово 
проследим весь процесс. 
    Как видите, почти весь код в примере предназначен для порождения двух 
классов от базовых классов, определенных в MFC. Мы уже упоминали о том, что 
практически вес приложения Windows должны порождать по крайней мере два 
класса. Первый класс предназначен для создания главного окна приложения, а 
второй — для создания самого приложения. Приложение начинает выполняться, 
когда создается экземпляр объекта второго типа. 

    Ш An MFC Application Skeleton 

    Рис. 2.2. Окно, создаваемое в примере 

    Для создания стандартного окна в приложении должен наследоваться класс 
CFrameWnd. В примере порождаемый класс называется CMainWin. Он содержит два 
члена: конструктор CMainWin() _и макрос DECLARE_MESSAGE_MAP(). В макросе 
объявляется очередь сообщений для класса CMainWin, что позволяет организовать 
обработку сообщений. Для любого окна, в котором обрабатываются сообщения, 
необходимо применять этот макрос. Кроме того, он должен быть последним членом, 
объявляемым в классе. (В противном случае следующий член должен быть объявлен 
с помощью оператора доступа ::.) 
    Само окно создастся в конструкторе CMainWin с помощью вызова функции-члена 
Create(). Как описывалось ранее, класс CFrameWnd является потомком класса 
CWnd, который, в свою очередь, порождается от CCmdTarget, а тот — от CObject. 
Это означает, что любой класс, порождаемый от CFrameWnd, имеет доступ ко всем 
функциям-членам и переменным, объявленным в пределах этой иерархии. Поскольку 
в книге нам понадобятся лишь некоторые из них, то полностью изучить их вы 
сможете лишь при написании своих собственных программ. И тем не менее, одна функция, 

    30 MFC: основы программирования 

    Create(), используется почти во всех приложениях. Она предназначена для 
создания окна и является членом класса CFrameWnd. В примере приведен наиболее 
простой случай ее использования. Мы еще рассмотрим эту функцию более подробно, 
но даже сейчас очевидно, что второй параметр определяет заголовок окна. 
    Класс САрр, предназначенный для создания приложения, порождается от 
CWinApp. Как уже упоминалось, этот класс отвечает за работу программы. Он 
является потомком класса CWinThread, который, в свою очередь, порождается от 
CCmdTarget. CWinApp содержит ряд переменных и функций-членов, из которых 
только одна, InitlnstanccQ, используется в примере. Ее прототип таков: 

    virtual BOOL CWinApp::Initlnstance(); 

    Initlnstance() — это виртуальная функция, которая должна переопределяться 
в классе, ответственном за создание приложения. Она вызывается каждый раз при 
запуске программы. Внутри Initlnstance() выполняются все действия, связанные с 
инициализацией приложения. Функция должна возвращать ненулевое значение при 
успешном завершении и ноль в противном случае. 
    Внутри Initlnstance() содержатся три команды. Сначала создается объект 
типа CMainWin 1\_указателъ начнет запоминается в переменной m_pMainWnd. Эта 
переменная является членом класса CWinThread, неявно наследуемым в САрр. Она 
имеет тип _CWnd* и используется почти во всех MFC-программах, потому что 
содержит указатель на объект главного окна программы. Через нее будут 
вызываться различные функции-члены, связанные с главным окном, как это 
показано в следующих двух строках примера. 
    Когда главное окно создано, через m_pMainWnd вызываются две функции, 
являющиеся членами класса CWnd. Первая из них называется ShowWindow(). Ее 
прототип выглядит следующим образом: 

    BOOL CWnd::ShowWindow(int How); 

    Функция ShowWindow() определяет, каким образом будет отображено на экране 
главное окно приложения. Режим отображения задается параметром How. При, 
первом вызове в качестве параметра необходимо передать переменную m_nCmdShow. 
Она является членом класса CWinApp и определяет, как будет выглядеть главное 
окно при запуске приложения. При последующих вызовах функции можно задать 
другие режимы либо закрыть окно. Значения, которые может принимать параметр 
How, приведены в табл. 2.1. 

    Таблица 2.1. Режимы отображения 

    Константа отображения	Действие 

    SW_HIDE	Окно закрывается 
    SW_MAXIMIZE	Окно раскрывается на весь экран 
    SW_MINIM1ZE	Окно сворачивается в пиктограмму 
    SW_SHOW	Окно отображается 
    SW_RESTORE	Окно приводится к нормальному размеру 


    2. Основы MFC	31 

    Функция ShowWindow() возвращает признак предыдущего состояния окна. Если 
оно было на экране, то результат ненулевой, в противном случае значением 
функции будет ноль. 
    Следующая функция, вызываемая в Initlnstance(), называется UpdateWindow(). 
Она также является членом класса CWnd. Хотя, с технической точки зрения, для 
такой простой программы нет необходимости в вызове этой функции, он все же 
присутствует, потому что данная функция используется в большинстве приложений 
Windows. Фактически, она указывает Windows на необходимость послать программе 
сообщение о том, что содержимое главного окна нужно обновить. (Это сообщение 
будет рассмотрено в следующей главе.) 
    В конце программы помещены довольно странные команды: 

    BEGIN_MESSAGE_MAP(CMainWin, CFrameWnd) END_MESSAGE_MAP() 

    Это так называемая очередь сообщений главного окна. Каждое приложение 
Windows принимает и обрабатывает сообщения. В пределах данной очереди должны 
содержаться вызовы функций, ответственных за обработку поступающих сообщений. 
В нашем примере ни один из них в очередь не помещен, так как обработка 
сообщений не ведется. Однако именно она является важнейшей, если не основной, 
частью любого приложения Windows. 
    До сего момента был определен лишь вид главного окна и заложена основа 
приложения, но сами они не существуют до тех пор, пока не создан экземпляр 
объекта класса, производного от CWinApp. Это выполняется следующей инструкцией: 

    САрр  Арр; 

    Как уже упоминалось, в программе может быть лишь один объект класса 
CWinApp. Приложение начинает выполняться только после объявления данного объекта. 
    Прежде чем читать дальше, наберите эту программу, откомпилируйте ее и 
запустите. Таким образом вы сможете правильно установить все опции 
компилятора, необходимые для компиляции MFC-программ. 

    Использование файла определений 

    При написании MFC-программ в Windows 3.1 необходимо для каждой из них 
создавать файл определений. Его создание, не требуется в новых версиях 
библиотеки, а также при компиляции программ под Windows 95 или Windows NT (это 
справедливо для любой полностью 32-разрядной системы). В этом файле содержатся 
определения различных параметров, используемых программой, например размер 
памяти, требуемой для стека и "кучи". Некоторые компиляторы автоматически 
генерируют подобную информацию, если файла определений не существует. 
Поскольку такие файлы уже отошли в прошлое, мы не будем тратить на них время. 
Если же вам нужен файл определений, то следующий пример может быть использован 
для всех программ, приведенных в книге. Правда, прежде чем его использовать, 
просмотрите справочное руководство к компилятору в части, касающейся деталей 
реализации файла. 

    DESCRIPTION 'Skeleton Program' EXETYPE WINDOWS 


    32	MFC: основы программирования 


    CODE PRELOAD MOVEABLE DISCARDABLE DATA PRELOAD MOVABLE MULTIPLE HEAPSIZE 
8192 STACKSIZE 8192 

    Все файлы определений имеют расширение DEF. Например, данная программа 
может называться SKEL.DEF. 

    Подробнее о создании масштабируемых окон 

    В предыдущем примере было создано стандартное масштабируемое окно. Для 
простых программ этого может быть вполне достаточно, но, как правило, в 
главном окне должны находиться различные элементы управления. К счастью, их 
легко можно получить с помощью функции Create(). Ее прототип таков: 

BOOL CFrameWnd::Create(LPCSTR  ClassName,   //  имя   класса  окна 
LPCSTR  Title,   //   заголовок   окна 
DWORD  Style=WS_OVERLAPPEDWINDOW,   //   стиль 
const  RECT   &XYsize=rectDefault,   //   позиция   и  размер CWnd   
*Parent=NULL,   //   окно-предок 
LPCSTR  MenuName=NULL,   //   название главного  меню 
DWORD  FxStyle=0,   //   спецификатор расширенного   стиля 
CCreateContext   *Context=NULL,   //   дополнительная 
    //   структура   контекста ); 

    Как видите, все параметры, кйрме первых двух, содержат значения по 
умолчанию. Поэтому в примере мы могли использовать очень простую форму функции 
Create(). "" Первый параметр, ClassName, определяет указатель на имя класса 
окна. В данном контексте термин ''клас?"_не__связан_с,.аодятием класса в C++, 
а означает, скорее, стиль. Когда этот параметр равен NULL (а так, чаще всего, 
и есть), для окна используется стандартный класс, определенный в библиотеке 
MFC. Можно, однако, зарегистрировать собственное имя класса окна с помощью 
функции AfxRegis-terWndClass(). Эта функция создает класс окна согласно 
заданной спецификации и возвращает указатель на его имя, которое можно 
использовать в качестве первого параметра функции CreateQ. Конечно, проще 
работать со стандартным классом окна, определенным в CFrameWnd, что и 
демонстрируется в большинстве примеров книги. 
    Заголовок окна — это строка, на которую указывает параметр Title. Это 
может быть и пустая строка, но, как правило, окно все же имеет заголовок. 
Стиль (или тип) создаваемого окна задается значением параметра Style. 
Константа \VS_OVER-LAPPEDWINDOW определяет стандартное окно, в котором имеется 
системное меню, рамка, кнопки минимизации, максимизации и закрытия. Таков 
стиль по умолчанию, если параметр Style не задан. Хотя этот стиль является 
наиболее общим, можно определить другой стиль по собственным критериям. Для 
этого достаточно с помощью операции побитового ИЛИ объединить несколько 
констант. Наиболее часто используемые константы приведены в табл. 2.2. 

    2. Основы MFC	33 


    Таблица 2.2. Стили масштабируемых окон 

    Константа стиля	Элемент окна 

    WS_OVERLAPPED	Стандартное окно с рамкой 
    WS_MAXIMIZEBOX	Кнопка максимизации 
    WS MINIMIZEBOX	Кнопка минимизации 
    WS_SYSMENU	Системное меню 
    WS_HSCROLL	Горизонтальная полоса прокрутки 
    WS_VSCROLL	Вертикальная полоса прокрутки 

    Начальное расположение и размер окна определяются параметром XYsize. Если 
он не указан (в большинстве случаев), то оба значения будут выбраны Windows. 
Однако их можно задаваТь"1Гявйо," передавая в качестве параметра ссылку на 
структуру типа RECT. Тип RECT объявлен следующим образом: 

    typedef struct tagRECT { 
    LONG left; 
    LONG top; 
    LONG right; 
    LONG bottom; } RECT; 

    Здесь необходимо определить координаты верхнего левого угла окна в 
переменных left и top, а также координаты нижнего правого угла в переменных 
right и bottom. Однако нужно помнить, что данные параметры задаются в 
абсолютных единицах (в данном случае в пикселях). Это означает, что координаты 
заданы по отношению к экрану. Дальше будет показано, что при выводе информации 
в окно используются относительные координаты, связанные с окном согласно 
установленному режиму отображения. Нодоскольку позиция окна относится ко всему 
экрану, то, естественно, в функции Create() требуется задавать абсолютные координаты. 
    Параметр Parent содержит указатель на окно, являющееся предком окна, 
создаваемого функцией Create(). Так как главное окно находится на верхнем 
уровне иерархии окон программы, то в данном случае параметр должен иметь 
значение NULL. 
    Хотя в примере не создается главное меню, в большинстве реальных программ 
оно есть. В этом случае название меню необходимо указывать в параметре 
MenuName. (О меню будет сказано чуть позже.) 
    Атрибуты расширенного стиля задаются в параметре ExStyle. Если таковых 
нет, указывается NULL. (О расширенных стилях также будет идти речь.) 
    Последний параметр, Context, обычно равен NULL. Это указатель на структуру 
типа CCreateContext. Создание структур контекста является специальной задачей 
программирования, поэтому используется редко. 
    Функция CreateQ возвращает ненулевое значение, если окно создано, и ноль, 
если создать окно невозможно. 

    34	MFC: основы программирования 

    Чтобы  проверить,   как используются дополнительные  параметры  в функции 
Create(), замените в примере конструктор CMainWinQ следующим кодом: 

    CMainWin::CMainWin() { 
    RECT   r; 
    г.top  =   10;   г.left  =   10; 
    г.bottom = г.right = 200; 
    Create (NULL, "A Small Window", 
    WSJDVERLAPPEDWINDOW, r); } 

    В этом случае будет создано стандартное окно, верхний левый угол которого 
имеет координаты (10,10), а правый нижний — (200,200). Окно изображено на рис. 2.3. 

    Рис. 2.3. Новое окно 


    Подробнее о классе CWinApp 

    Кроме функции Initlnstance() и переменной mjnCmdShow класс CWinApp 
содержит еще несколько членов, которые могут оказаться полезными: 
    •    Все параметры, передаваемые приложению в командной строке, адресуются 
указателем, содержащимся в переменной m_IpCmdLine. 
    •    Название приложения содержится в строке, адресуемой с помощью 
переменной m_pszAppName. 
    •    Если приложение становится неактивным, оно вызывает функцию OnldleQ. 
Ее можно переопределить,, чт§&ы_позволить приложению выполнять различные 
фоновые действия. 
    Некоторые из членов класса CWinApp будут использованы в примерах книги. 

    2. Основы MFC 35 


    Организация исходного кода программы 

    Хотя наш пример очень мал, большинство Windows-программ весьма велики. 
Даже примеры в данной книге часто занимают несколько страниц. Поэтому с целью 
упрощения организации MFC-программ была разработана методика управления 
файлами, признанная среди программистов, использующих библиотеку MFC. Согласно 
этой методике, объявления полей данных и прототипы функций-членов порождаемых 
классов должны содержаться в одном файле, а определения функций-членов — в 
другом. Первый файл можно назвать, например, CLASSES.H и затем включить во 
второй файл. Поскольку большинство реальных проектов состоят из множества 
исходных файлов, такая методика оказывается особенно полезной, потому что 
позволяет легко, без дублирования кода включать описания классов во все файлы проекта. 
    С учетов всего вышесказанного, давайте применим такую методику для нашего 
примера. Сначала вынесем все объявления в отдельный файл, который назовем SKEL.H: 

    //В этом файле порождаются основные классы 
    ,',' Это класс для создания главного окна class CMainWin : public 
CFrameWnd { public: 
    CMainWin(); 
    DECLARE_MESSAGE_MAP() 
    }; 
    // Это класс для создания приложения class CApp : public CWinApp { public: 
    BOOL Initlnstance (); }; 
    Затем определения функций-членов и базовый код мы поместим в другой файл: 
    // Минимальная MFC-программа #include <afxwin.h> tinclude "skel.h" 
    // Создание окна CMainWin::CMainWin() { 
    Create(NULL, "An MFC Application Skeleton"); 
    // Инициализация приложения BOOL CApp::Initlnstance () { 
    m_pMainWnd = new CMainWin; 


    36	MFC: основы программирования 


    m_pMainWnd->ShowWindow(m_nCmdShow); m_pMainWnd->UpdateWindow(); 
    return TRUE; } 
    //   Это  очередь   сообщений  приложения BEGIN_MESSAGE_MAP(CMainWin,   
CFrameWnd) END_MESSAGE_MAP() 
    CApp  App;   //   создание   экземпляра  приложения 

    Как видите, в данный файл сначала включается библиотека AFXWIN.H, а затем 
файл SKEL.H. Порядок включения важен, потому что в SKEL.H требуется 
тлиформация и^М^ШШГ"•"•""' 
    Поскольку такой стиль написания программ для Windows является 
общепринятым, мы будем использовать его в книге. Кроме того, он достаточно 
эффективен. Конечно, в своих программах вы можете руководствоваться другими 
принципами организации. Выбор, как всегда, остается за вами. 

    37