Академический Документы
Профессиональный Документы
Культура Документы
Макаревич Л. Г.
Литература
Нортон П., Макгрегор Р. WINDOWS 95/NT 4. Программирование с
помощью MFC. в 2-х книгах: Пер. с англ. "СК Пресс", 1998.
Тосс В. Visual C++ 5. Энциклопедия пользователя: Пер. с англ.
К.:"Диасофт", 1998.-688 с. , ил.
Грегори К. Использование Visual C++ 5. Специальное издание.: Пер. с
англ. - К.:Диалектика, 1997.-816 с. , ил.
Тихомиров Ю. Visual C++6. - СПб.:БХВ - Санкт-Петербург, 1998. - 496
с., ил.
Мешков А., Тихомиров Ю. Visual C++ и MFC. программирование для
Windows NT и Windows 95. В 3-х томах. Срб.:-BHV-Санкт-Петербург,
1997.
Фролов А. В., Фролов Г. В. Microsoft Visual C++ и MFC.
Программирование для Windows 95 и Windows NT. - М.:ДИАЛОГ-
МИФИ, 1996. - 288 с. - (Библиотека системного программиста; Т. 24)
Фролов А. В., Фролов Г. В. Microsoft Visual C++ и MFC.
Программирование для Windows 95 и Windows NT. - М.:ДИАЛОГ-
МИФИ, 1997. - 272 с. - (Библиотека системного программиста; Т. 28)
Круглински Д., Уингоу С., Шеферд Дж. Программирование на Microsoft
Visual C++ 6.0 для профессионалов. Пер. с англ. –
СПб:Питер;М:Русская редакция, 2001. – 864 с.: ил.
Информация в Интернет
ftp://ermak.cs.nstu.ru/metodic/makar/MFC
www.codenet.ru
www.codeguru.com
www.firststeps.ru
www.realcoding.net
www.codegu.ru
www.rsdn.ru
Технология программирования 2004.doc
Секунов Н. Самоучитель Visual С++
Программирование для Windows
Windows 3.0 – 1990
Независимость программ от аппаратуры
Стандартный графический интерфейс
Совместимость с предыдущими версиями
Многозадачность
Встраиваемые объекты ( Clipboard, OLE, COM, ActiveX)
Windows 95
Вытесняющая многозадачность
Потоки ( Thread )
32-разрядная поддержка. Улучшенное управление виртуальной памятью
Windows NT
Способность выполнять приложения, написанные для других платформ (MS DOS, POSIX,
WINDOWS 3.1, OS/2…)
Переносимость на другие платформы
Многопроцессорность
Улучшенная защищенность
Организация распределенности по правилам «клиент-сервер»
Улучшенная защищенность
DCOM – технологии
Новая файловая система
Windows XP
Улучшенная защищенность
Управление рабочим столом
64-разрядная поддержка
Многоязычная поддержка
Удаленное управление рабочим столом
Пакеты разработки программ
Windows SDK (Software Development Kit)
Набор книг с описанием функций, макросов, сообщений
Редакторы ресурсов
Оперативная справка
Библиотеки
Примеры программ
Windows API (Application Program Interface)
Более 2000 функций, макросов, констант
user32.dll – управление окнами, сообщениями, курсорами,
таймерами
gdi32.dll – интерфейс графических устройств, рисование
элементов пользовательского инерфейса
kernel32.dll – управление памятью, распределение ресурсов
Дополнительные модули – стандартные диалоги,
дополнительные элементы управления, …
Ресурсы приложения
Шаблоны диалогов
Шаблоны панелей инструментов
Курсоры
Иконки
Шаблоны меню
Строковые таблицы
Картинки ( bitmap )
Акселераторы
Доступ к ресурсам осуществляется через численные идентификаторы или
строковое имя ресурса
Событийное программирование
Инициализация
Цикл сообщений
Получение сообщения из очереди
WM_QUIT?
Есть обработчик?
Окончание
Стандартная обработка Вызов обработчика
Цикл обработки сообщений
while ( GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);// трансляция ввода с клавиатуры в WM_CHAR
DispatchMessage(&msg);// в оконную процедуру
}
GetMessage Function
GetMessage получает сообщения из очереди сообщений для потока. Функция
отфильтровывает сообщения для обработки.
BOOL GetMessage(
LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);
Параметры
lpMsg
[out] Указатель на структуру MSG с информацией о сообщении из очереди.
hWnd
[in] От какого окна обрабатываются сообщения. Окно принадлежит данному потоку. 0 – от
любых окон данного потока.
wMsgFilterMin
[in] Задает фильтр сообщений. WM_KEYFIRST – от клавиатуры, WM_MOUSEFIRST – от
мыши.
Windows XP: WM_INPUT- только сообщения WM_INPUT.
Если wMsgFilterMin и wMsgFilterMax - 0, GetMessage возвращает все сообщения, то есть
нет фильтрации.
wMsgFilterMax
[in] Задает фильтр сообщений. WM_KEYLAST – от клавиатуры, WM_MOUSELAST - от мыши.
Return Value
Если сообщение – не WM_QUIT, то возвращается не ноль.
Если сообщение - WM_QUIT, возвращается ноль.
Если есть ошибка, то возвращается -1. Например, окно неверное или lpMsg неверный
указатель. Для расшифровки ошибки вызывается функция GetLastError.
typedef struct {
HWND hwnd;
UINT message;
WPARAM wParam
LPARAM lParam;
DWORD time;
POINT pt;} MSG, *PMSG;
hwnd
Окно, от которого пришло сообщение.
message
Идентификатор сообщения.
wParam
Дополнительная информация, зависит от типа сообщения.
lParam
Дополнительная информация, зависит от типа сообщения.
time
Время сообщения.
pt
Координаты курсора для сообщения.
Минимальное приложение для
Windows /*
первая функция приложения - инициализирует приложение и
выполняет цикл обработки сообщений
/* имя приложения */ */
#define APPNAME "MINAPIWIN" int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
#include <windows.h> /* описание функций Win32® API */ int nCmdShow)
#include "resource.h" /* определение идентификаторов */ {
MSG msg;
/* глобальные переменные */ HANDLE hAccelTable;
HINSTANCE hInst; /* идентификатор приложения */
if (!hPrevInstance)
HWND hwndEdit; /* идентификатор окна */ {
char szAppName[] = APPNAME; /* имя приложения */ /* инициализируем данные окна и регистрируем его */
/* заголовок главного окна */ if (!InitApplication(hInstance))
char szTitle[] = APPNAME": Минимальное приложение-пример"; return (FALSE);
}
CHAR szFileName[_MAX_PATH]; /* инициализируем приложение */
CHAR szFileTitle[_MAX_PATH]; if (!InitInstance(hInstance, nCmdShow))
return (FALSE);
/* определение используемых функций */
ATOM APIWinRegisterClass(CONST WNDCLASS *); hAccelTable = LoadAccelerators (hInstance, szAppName);
BOOL InitApplication(HINSTANCE); /* Цикл обработки сообщений */
BOOL InitInstance(HINSTANCE, int); while (GetMessage(&msg, NULL, 0, 0))
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
{
if (!TranslateAccelerator (msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (msg.wParam);
}
/* функция инициализации данных окна и его регистрируции*/ /* функция создания главного окна*/
BOOL InitApplication(HINSTANCE hInstance) BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{ {
WNDCLASS wc; HWND hWnd;
HWND hwnd; hInst = hInstance;
/* в Win32 API параметр hPrevInstance всегда равен NULL, hWnd = CreateWindow(szAppName, szTitle,
поэтому для нахождения ранее запущенного приложения WS_OVERLAPPEDWINDOW,
используем функция поиска окна (если не хотим CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
повторного запуска приложения */ NULL, NULL, hInstance, NULL);
hwnd = FindWindow (szAppName, NULL); if (!hWnd)
if (hwnd) return (FALSE);
{ ShowWindow(hWnd, nCmdShow);
/* нашли копию приложения - восстановим его на экране и UpdateWindow(hWnd);
активизируем его */ return (TRUE);
if (IsIconic(hwnd)) }
ShowWindow(hwnd, SW_RESTORE); /* функция главного окна
SetForegroundWindow (hwnd); обрабатывает следующие сообщения:
/* данная копия должна быть завершена */ WM_DESTROY - команда на завершение приложения */
return (FALSE); LRESULT CALLBACK WndProc(
} HWND hWnd,
wc.style = CS_HREDRAW | CS_VREDRAW; UINT message,
wc.lpfnWndProc = (WNDPROC)WndProc; WPARAM wParam,
wc.cbClsExtra = 0; LPARAM lParam)
wc.cbWndExtra = 0; {
wc.hInstance = hInstance; switch (message)
wc.hIcon = LoadIcon (hInstance, szAppName); {
wc.hCursor = LoadCursor(NULL, IDC_ARROW); case WM_DESTROY:
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); PostQuitMessage(0);
wc.lpszMenuName = szAppName; break;
wc.lpszClassName = szAppName; default:
return (DefWindowProc(hWnd, message, wParam, lParam));
return RegisterClass(&wc); }
} return (0);
}
Простейшее приложение для Windows
#include "windows.h"
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
MessageBox(0,"Привет, Мир!","Первая программа для Windows", MB_OK|MB_ICONEXCLAMATION);
MessageBeep(MB_ICONEXCLAMATION);
}
Приложение с диалогом
Создали ресурс
Добавили код
#include "windows.h"
#include "resource.h"
BOOL CALLBACK DlgProc(HWND hwnddlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
{
WPARAM wId = wParam;
switch(wId)
{
case IDOK:
case IDCANCEL:
EndDialog(hwnddlg,0);
return TRUE;
}
}
}
return FALSE;
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
MessageBox(0,"Привет, Мир!","Первая программа для Windows",MB_OK|MB_ICONEXCLAMATION);
MessageBeep(MB_MB_ICONEXCLAMATION);
DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),0,(DLGPROC)DlgProc);
}
Модальные и немодальные диалоги
#include "windows.h"
#include "resource.h"
BOOL CALLBACK DlgProc(HWND hwnddlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
{
WPARAM wId = wParam;
switch(wId)
{
case IDOK:
case IDCANCEL:
EndDialog(hwnddlg,0);
return TRUE;
}
}
}
return FALSE;
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
MessageBox(0,"Привет, Мир!","Первая программа для Windows",MB_OK|MB_ICONEXCLAMATION);
MessageBeep(MB_ICONEXCLAMATION);
DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),0,(DLGPROC)DlgProc);
HWND hhh = CreateDialog(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),0,(DLGPROC)DlgProc);
ShowWindow(hhh, SW_SHOW);
hhh = CreateDialog(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),0,(DLGPROC)DlgProc);
ShowWindow(hhh, SW_SHOW);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0 ))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Графический интерфейс
пользователя
Раньше программы писали
непосредственно в видеопамять или
принтер
Windows добавляет прмежуточный слой –
GDI (Graphics Device Interface)
Программа использует функции GDI со
ссылками на device context, а Windows
отображает все на физические устройства
через свои драйверы с разделением
дисплея между разными программами
Ресурсно-базируемое
программирование
При программировании под Windows часть
информации сохраняется в специальных
форматах в ресурсных файлах.
Эти файлы добавляются в exe-файл при
компоновке
Ресурсные файлы включают иконки,
битмапы, меню, панели инструментов,
курсоры, диалоги и т. д.
Для создания подобных элементов
используются редакторы ресурсов ( обычно
wysiwyg )
DLL – динамически-загружаемые
библиотеки
Эти библиотеки используются всеми
приложениями, что экономит память и
дисковое пространство
Можно использовать статичести
прикомпонованные библиотеки
Можно создавать свои DLL
Что такое MFC
K MFC следует подходить как к инструменту, который,
принимая на себя большую часть черновой работы,
требует от нас не просто знакомства с ним, но и
глубокого изучения. Только знание всех нюансов
построения и возможностей этой библиотеки позволит
нам быстро и легко создавать программы любой
степени сложности. В противном случае никогда не
будет уверенности, что созданное приложение при
любых условиях работает правильно — слишком много
скрыто от программиста. Функции вызываются не
только из недр Windows, но и из недр библиотеки. Ни о
каком последовательном вызове функций речь не идет.
Данные готовятся неизвестно где и неизвестно кем и
когда обрабатываются. Так что какая уж тут уверенность.
MFC - это набор классов, охватывающих большую часть
функциональных возможностей операционных систем Microsoft
Windows, а также предоставляющих разработчику значительное
количество не только очень мощных дополнительных классов, но
и целые механизмы, которые, не нарушая идеологию
операционной системы, существенно ее расширяют и ... упрощают.
Перед создателями библиотеки стояла задача создания
объектно-ориентированного интерфейса для Windows,
удовлетворяющего следующим основным целям
проектирования программных продуктов:
сокращение усилий по программированию приложений для
Windows;
скорость выполнения программ, написанных с
использованием библиотеки, должна быть сопоставима с
программами, написанными на языке С с использованием
Win32 API;
минимальный размер вспомогательного кода;
способность напрямую вызывать любую С-функцию Win32
API;
легкость использования Win32 API в C++ должна быть
такая же, как и при использовании традиционного С.
Создание MFC-приложения
Visual Studio для С++
Текстовый редактор
Редакторы ресурсов
Компилятор (cpp -> obj )
Компилятор ресурсов (rc ->res)
Компоновщик (obj + res -> exe)
Отладчик
AppWizard
ClassWizard
Просмотрщик кода
Помощь
Диагностика (Spy, PVIEW)
Контроль кода (Visual SourceSafe )
Галерея (ActiveX компоненты)
MFC
ATL (Microsoft Active Template Library)
Как программировать под
Windows
Программировать на С с
использованием Win32
Разработать свою библиотеку классов
на С++ с использованием Win32
Использовать MFC
Использовать другие библиотеки
классов ( OWL )
Что необходимо знать для
изучения MFC
MFC - это достаточно сложная библиотека, интенсивно использующая
возможности языка С++, а также в некоторых случаях и расширяющая язык.
Поэтому Вы должны хорошо разбираться в языке С++, в частности, не
должны вызывать затруднений наследование и создание производных
классов, полиморфизм (нужно также понимать его ограничения в С++),
виртуальные методы, перегрузка операторов, обработка исключений и
другие характерные для С++ понятия.
Если Вы не так свободно ориентируетесь в С++, то настоятельно
рекомендуется перед изучением MFC укрепить свои знания по С++,
например, с помощью книги Стенли Б. Липпмана "С++ для начинающих", или
одной из множества других книг, подобных этой.
Необходимо иметь опыт работы с одной из современных версий Windows, а
также представлять себе ее внутреннее устройство и принципы работы.
Необходим хотя бы минимальный опыт работы со средой Microsoft Visual C+
+. Предполагается, что Вы, по крайней мере, умеете создавать проекты,
добавлять к ним файлы, менять настройки и собирать проекты. Однако,
библиотека MFC построена так, что она повторяет структуру подсистем и
объектов Windows API. Это сделано ради эффективности. Поэтому, если Вы
уже программировали на С/С++ с использованием только "чистого" Windows
API, то это существенно облегчит процесс изучения MFC.
Опыт работы с системами RAD тоже будет полезен.
Иерархия классов MFC
CObject – базовый класс
Информация о типе времени выполнения
Если указатель или ссылка ссылается на объект, производный от
класса CObject, то в этом случае предусмотрен механизм
определения реального типа объекта с помощью макроса
RUNTIME_CLASS(). Хотя в С++ имеется механизм RTTI, механизм,
реализованный в MFC, намного более эффективен по
производительности.
Диагностика
Каждый класс, производный от CObject, может по запросу проверить
свое внутреннее состояние и выдать диагностическую информацию.
Это интенсивно используется в MFC при отладке.
Сериализация
Сериализация - это механизм, позволяющий преобразовать текущее
состояние объекта в последовательный поток байтов, который
обычно затем записывается на диск, и восстановить состояние
объекта из последовательного потока, обычно при чтении с диска.
Это позволяет сохранять текущее состояние приложения на диске,
и восстанавливать его при последующем запуске.
Основные классы
Некоторые классы порождаются непосредственно от CObject. Наиболее
широко используемыми среди них являются CCmdTarget, CFile, CDC,
CGDIObject и CMenu.
Класс ССmdTarget предназначен для обработки сообщений.
Класс СFile предназначен для работы с файлами.
Класс CDC обеспечивает поддержку контекстов устройств. В этот класс включены
практически все функции графики GDI. CGDIObject является базовым классом для
различных GDI-объектов, таких как перья, кисти, шрифты и другие.
Класс СMenu предназначен для манипуляций с меню.
От класса CCmdTarget порождается очень важный класс CWnd. Он является
базовым для создания всех типов окон, включая масштабируемые ("обычные") и
диалоговые, а также различные элементы управления.
Наиболее широко используемым производным классом является CFrameWnd. Как
Вы увидите в дальнейшем, в большинстве программ главное окно создается с
помощью именно этого класса.
От класса CCmdTarget, через класс CWinThread, порождается, наверное,
единственный из наиболее важных классов, обращение к которому в MFC-
программах происходит напрямую: CWinApp. Это один из фундаментальных
классов, поскольку предназначен для создания самого приложения. В
каждой программе имеется один и только один объект этого класса. Как
только он будет создан, приложение начнет выполняться.
Функции-члены в MFC
Первый параметр, ClassName, определяет имя класса окна для оконной подсистемы Windows.
Обычно его не нужно явно задавать, так как MFC выполняет всю необходимую черновую
работу.
Параметр Style задает стиль окна. По умолчанию создается стандартное перекрываемое окно.
Можно задать свой стиль, объединив с помощью операции "или" несколько констант
В дальнейшем мы не будем так подробно расписывать здесь все возможные значения констант,
потому что всегда можно обратиться к справке Visual C++ и получить подробную информацию.
Начальное положение и размер окна определяются параметром XYSize. Это структура, которая
определяет экранные координаты левого верхнего и правого нижнего угла прямоугольника, в котором
будет отображено окно.
Основные типы данных (как в API)
BOOL Булевское значение Функция обратного вызова или CallBack-
BSTR 32-битный указатель на символ функция вызывается операционной
системой по указателю, переданному ей
BYTE 8-битное целое без знака
ранее приложением. Это весьма удобный
COLORREF 32-битное значение, используемое для задания цвета и часто используемый механизм
DWORD 32-битное целое без знака или адрес подключения к стандартным функциям
LONG 32-битное целое со знаком
специфических обработчиков.
LPARAM 32-битное значение, посылаемое в качестве параметра в оконную процедуру или функцию обратного вызова
LPCSTR 32-битный указатель на константную строку символов
LPSTR 32-битный указатель на строку символов
LPCTSTR 32-битный указатель на константную строку символов, которая переносима в Unicode и DBCS
LPTSTR 32-битный указатель на строку символов, которая переносима в Unicode и DBCS
LPVOID 32-битный указатель на неопределенный тип данных
LRESULT 32-битное значение, возвращаемое из оконной процедуры или функции обратного вызова
UINT 32-битное целое без знака для Win32 и 16-битное — для Windows 3.x
WNDPROC 32-битный указатель на оконную процедуру
WORD 16-битное целое без знака
WPARAM Значение, посылаемое в качестве параметра в оконную процедуру или функцию обратного вызова; 32-битное
для Win32 и 16-битное для Windows 3.x
POSITION 32-битное целое без знака, используемое для обозначения позиции элемента в коллекции
LPCRECT 32-битный указатель на немодифицируемую структуру RECT
HINSTANCE 32-битное целое без знака для идентификации дескриптора экземпляра приложения
Получение информации о
приложении
Когда вы пишете приложение с использованием классов MFC, вы создаете единственный объект, производный от CWinApp. Для получения из
любого места программы информации об этом объекте и связанных с ним параметрах разработчики предоставили следующие функции.
CWinApp* AfxGetApp()
Возвращает указатель на единственный объект CWinApp приложения.
LPCNSRT AfxGetAppName()
Возвращает строку, заканчивающуюся нулем, содержащую имя приложения.
HINSTANCE AfxGetlnstanceHandle()
Возвращает дескриптор текущего приложения для исполняемого файла (.ЕХЕ); в случае, если функция вызвана из динамически подключаемой
библиотеки, связанной с USRDLL-версией MFC, то возвращается HINSTANCE этой библиотеки DLL.
CWnd* AfxGetMainWhd()
Возвращает значение переменной rn_pMainWnd объекта приложения, если оно не является сервером OLE, или указатель на активное главное окно
приложения — в противном случае.
HINSTANCE AfxGetResourceHandle()
Возвращает дескриптор загруженных по умолчанию ресурсов приложения.
void AfxSetResourceHandle(HINSTANCE hlnstResource)
Устанавливает дескриптор экземпляра приложения или модуля .ЕХЕ или .DLL, из которого будут загружены ресурсы приложения.
LPCTSTR AFXAPI AfxRegisterWndClass( UINT nClassStyle, HCURSOR hCursor =0, HBRUSH hbrBackground = 0, HICON hlcon = 0)
Возвращает строку, заканчивающуюся нулем, которая содержит имя зарегистрированного класса. В качестве параметров в эту функцию
передаются: nClassStyle — стиль или комбинация стилей класса окна Windows, которые будут рассмотрены при описании регистрации класса
окна, hCursor— дескриптор ресурса курсора, hbrBackground— дескриптор ресурса кисти, определяющей цвет фона, hlcon — дескриптор
ресурса-пиктограммы.
BOOL AFXAPI AfxRegisterClass(WNDCLASS* IpWndClass)
Возвращает значение TRUE при успешной регистрации класса окна и FALSE при ошибке. В качестве параметра в функцию передается указатель на
структуру WNDCLASS, которая должна содержать информацию, необходимую для успешной регистрации. При использовании этой функции
для регистрации класса окна в модуле DLL следует иметь в виду, что имя зарегистрированного класса автоматически удаляется из системы
при выгрузке библиотеки из памяти.
HINSTANCE AFXAPI AfxLoadLibrary(LPCTSTR IpszModuleName)
Загружает в память модуль (.DLL или .ЕХЕ файл), имя которого передается в качестве параметра IpszModuleName. Если загрузка прошла успешно,
то возвращается дескриптор модуля и увеличивается счетчик ссылок для этой библиотеки; в противном случае возвращается NULL.
BOOL AFXAPI AfxFreeLibrary(HINSTANCE hlnstLib)
Уменьшает счетчик ссылок для загруженного модуля DLL, определяемого параметром hlnstLib. Когда счетчик ссылок становится равным нулю,
модуль выгружается из адресного пространства текущего процесса.
int AfxMessageBox(
LPCTSTR IpszText, При использовании в блоке сообщений более одной кнопки можно
UINT nType = MB_OK, также установить кнопку по умолчанию:
UINT nIDHelp =0) MB_DEFBUTTONl — по умолчанию первая кнопка
И MB_DEFBUTTON2 — по умолчанию вторая кнопка
int AfxMessageBox ( MB_DEFBUTTON3 — по умолчанию третья кнопка
UINT nIDPrompt,
UINT nType = MB_OK,
UINT nIDHelp = (UINT) -1)
Выводит текст в окно сообщений. Первая форма этой функции выводит в окно сообщений строку IpszText и использует
идентификатор nIDHelp для перехода к соответствующей теме справки при нажатии клавиши. Вторая форма функции
использует для определения текста идентификатор строки ресурса, задаваемый параметром nIDPrompt. Если в качестве
nIDHelp используется значение по умолчанию, равное -1, то nIDPrompt задает тему справки.
Обе функции возвращают одно из следующих значений:
IDABORT — нажата кнопка Abort
IDCANCEL — нажата кнопка Cancel или нажата клавиша
IDIGNORE — нажата кнопка Ignore
IDNO — нажата кнопка No
IDOK — нажата кнопка ОК
IDRETRY — нажата кнопка Retry
IDYES — нажата кнопка Yes
О — окно сообщений не может быть создано.
Параметр пТуре определяет тип окна сообщений и может принимать одно из следующих значений:
MB_ABORTRETRYIGNORE — содержит три кнопки Abort, Retry и Ignore (Стоп, Повтор и Пропустить)
MBOK — содержит только кнопку ОК
MB_OKCANCEL — содержит две кнопки ОК и Cancel (OK и Отмена)
MB_RETRYCANCEL — содержит две кнопки Retry и Cancel (Повтор и Отмена)
MB_YESNO — содержит две кнопки Yes и No (Да и Нет)
MB_YESNOCANCEL — содержит три кнопки Yes, No и Cancel (Да, Нет и Отмена)
Кроме того, можно использовать следующие константы для определения степени модальности окна сообщений:
MB_APPLMODAL — модальность на уровне пользователя
MB_SYSTEMMODAL — модальность на уровне системы
MB_TASKMODAL — модальность на уровне процесса
MB_ICONEXCLAMATION, MB_ICONSTOP, MB_ICONERROR…
Создание проекта на MFC
Простое приложение с главным окном и
без поддержки архитектуры «Вид-
Документ»
Соглашения об именах
библиотеки MFC
В качестве префикса, обозначающего имя класса, библиотека MFC
использует заглавную букву С от слова "class" (класс), за которым идет имя,
характеризующее его назначение. Например, CWinApp — класс,
определяющий приложение, CWnd — базовый класс всех оконных объектов,
CDialog — класс окон диалога и т. д. Мы также будем придерживаться этого
соглашения в приводимых примерах.
Для имен методов классов используется три способа.
При первом способе имя объединяет глагол и существительное, например,
Loadlcon (Загрузить пиктограмму) или DrawText (Нарисовать текст).
При втором имя метода состоит только из существительного, например, DialogBox
(Блок диалога).
Для функций, предназначенных для преобразования одного типа в другой,
обычными являются такие имена, как XtoY(из X в Y).
Для членов классов библиотеки MFC принят следующий способ назначения
имен: обязательный префикс m_ (от class member — член класса), затем
идет префикс, характеризующий тип данных, и завершается все
содержательным именем переменной, например, m_pMainWnd, где р —
префикс, описывающий указатель (для переменных не членов класса
префикс m_ не используется, чтобы можно было отличить обычные
переменные от элементов любых классов, а не только классов библиотеки
MFC).
Включаемые файлы
#include “stdafx.h”
Этот включаемый файл служит для подключения к
программе необходимых ей библиотечных файлов.
Когда вы будете писать большие приложения, вам
обязательно потребуется использование заранее
откомпилированных заголовочных файлов, что
поможет существенно сократить требуемое время
компиляции. Прекомпилированные заголовки
удобны, если у вас есть несколько заголовков,
которые должны быть включены во все или в
большинство ваших исходных файлов. Однако их
использование полезно только в том случае, если
сами они не меняются между компиляциями.
Обработка сообщений
Windows взаимодействует с приложением,
посылая ему сообщения. Поэтому обработка
сообщений является ядром всех приложений. В
традиционных приложениях Windows (написанных
с использованием только API) каждое сообщение
передается в качестве аргументов оконной
функции. Там обычно с помощью большого
оператора switch определяется тип сообщения,
извлекается информация, и производятся нужные
действия. Это громоздкая и чреватая ошибками
процедура. С помощью MFC все делается намного
проще.
Обработка сообщений в MFC
В MFC включен набор предопределенных функций-
обработчиков сообщений, которые можно использовать в
программе. Если программа содержит такую функцию, то она
будет вызываться всякий раз, когда поступает связанное с
ней сообщение. При наличии дополнительной информации в
сообщении она передается в качестве аргументов функции.
Для организации обработки сообщений нужно выполнить
следующие действия:
В карту сообщений программы должна быть включена команда
соответствующего сообщения.
Прототип функции-обработчика должен быть включен в
описание класса, ответственного за обработку данного
сообщения.
В программу должна быть включена реализация функции-
обработчика.
Включение макрокоманд в карту
сообщений
Чтобы программа могла ответить на сообщение, в карту
сообщений должна быть включена соответствующая
макрокоманда. Названия макрокоманд соответствуют
именам стандартных сообщений Windows, но дополнительно
имеют префикс ON_ и заканчиваются парой круглых скобок.
Из этого правила есть исключение: сообщению
WM_COMMAND соответствует макрокоманда
ON_COMMAND(). Причина в том, что это сообщение
обрабатывается особым образом.
Чтобы включить макрокоманду в очередь сообщений, нужно
просто поместить ее между командами
BEGIN_MESSAGE_MAP() и END_MESSAGE_MAP().
Например, если необходимо обработать в программе
сообщение WM_CHAR, то очередь должна выглядеть так:
BEGIN_MESSAGE_MAP(CMainWin, CFrameWnd) ON_WM_CHAR()
END_MESSAGE_MAP()
В очереди может находиться более одной макрокоманды. Сообщение
WM_CHAR генерируется при нажатии алфавитно-цифровой клавиши
на клавиатуре.
Пример программы
} }
Запустив программу, обратите внимание, что она всегда
восстанавливает содержимое своего окна.
Так должны вести себя все корректные приложения Windows. Также
посмотрите в исходном тексте, как программа затирает в окне уже
выведенную раньше строку перед выводом новой строки.
Это делается с помощью вывода достаточно длинной строки из
пробелов; строка выводится с белым фоном, поэтому предыдущая
строка стирается.
По умолчанию вывод в окно осуществляется системным шрифтом,
ширина символов у которого различна. Поэтому, например, вывод
символа "i" сразу поверх "W" не сотрет предыдущий символ
Сообщение WM_TIMER
В Windows существуют специальные объекты, называемые таймерами. Программа (точнее, окно)
может запросить один или несколько таких объектов. После этого каждый таймер через регулярные
заранее указанные промежутки времени будет посылать сообщение WM_TIMER.
Они будут помещаться в очередь сообщений окна. Таким образом, в функции-обработчике этого
сообщения можно выполнять некоторые действия через регулярные промежутки времени. Если
создано несколько таймеров, то их можно различать по номерам, присвоенным им при запросе.
Для запроса таймера у системы используется следующая функция:
UINT CWnd::SetTimer(UINT Id, UINT Interval, void (CALLBACK EXPORT *TFunc)(HWND, UINT,
UINT, DWORD));
Третьим параметром пользуются очень редко, и обычно он равен 0. Мы не будем его использовать.
Параметр Id задает уникальный идентификационный номер таймера. По этим номерам обычно
различаются несколько созданных таймеров. Параметр Interval задает интервал между двумя
посылками сообщений (интервал таймера) в миллисекундах. Разрешающая способность таймеров
55 мс, поэтому интервалы измеряются с такой точностью. Если даже задать значение интервала
равным 1, то все равно будет использовано значение 55. Если задать 0, то таймер приостановит
свою работу.
Сообщения таймера обрабатываются функцией:
afx_msg void OnTimer(UINT Id);
Все таймеры вызывают один и тот же обработчик. Узнать, какой таймер послал сообщение, можно с
помощью параметра Id, в котором передается номер таймера.
Сообщение WM_DESTROY
Это сообщение посылается окну, когда последнее должно быть
удалено. Если его получает главное окно приложения, то это означает
завершение приложения.
В этом случае обычно приложение должно выполнить действия по
выгрузке.
Обработчик имеет прототип:
afx_msg void OnDestroy();
В нашем случае, мы должны удалить запрошенные таймеры. Все
запрошенные ресурсы перед завершением программы необходимо
освобождать.
Для таймеров это делается с помощью функции:
BOOL CWnd::KillTimer(int Id);
Функция освобождает таймер с идентификатором Id.
class CMainFrame: public CFrameWnd { BOOL CApp::InitInstance()
public: {
m_pMainWnd = new CMainFrame;
CMainFrame();
m_pMainWnd->ShowWindow(SW_RESTORE);
afx_msg void OnPaint(); m_pMainWnd->UpdateWindow();
// Обработчик сообщения WM_DESTROY
afx_msg void OnDestroy(); // Установка таймера с идентификатором 1 и
// Обработчик сообщения WM_TIMER // интервалом 500 мс
afx_msg void OnTimer(UINT ID);
m_pMainWnd->SetTimer(1, 500, 0);
char str[50];
return TRUE;
DECLARE_MESSAGE_MAP() }
};
CMainFrame::CMainFrame()
{
// Определение прямоугольника, в котором будет
// размещено окно
RECT rect;
rect.left = rect.top = 10;
rect.right = 200;
rect.bottom = 60;
// Создание окна в определенном экранном
// прямоугольнике
this->Create(0, "CLOCK", При создании окна мы явно задали координаты
WS_OVERLAPPEDWINDOW, rect); прямоугольника, в котором оно должно быть
strcpy(str, ""); отображено, с помощью структуры RECT. Таким
}
образом, всегда можно задать начальные размеры и
положение окна на экране.
afx_msg void CMainFrame::OnPaint()
{
CPaintDC dc(this);
// Выводим в окно строку текущего времени
dc.TextOut(1, 1, " ", 3);
dc.TextOut(1, 1, str);
}
Цикл
Очередь сообщений обработки
Системная
приложения 3 сообщений
Асинхронное
очередь сообщение
Очередь сообщений
приложения 1
Синхронное
сообщение
Стандартная
SendMessage оконная процедура
Категории сообщений
Сообщения Windows
WM_..., кроме WM_COMMAND Обрабаты-
ваются в
окнах
Извещения элементов управления CWnd
// Dialog Data
enum { IDD = IDD_DIALOG_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); //
DDX/DDV support
// Implementation
protected:
HICON m_hIcon;
#else
#define DECLARE_MESSAGE_MAP() \
private: \
static const AFX_MSGMAP_ENTRY _messageEntries[]; \
protected: \
static const AFX_MSGMAP messageMap; \
virtual const AFX_MSGMAP* GetMessageMap() const; \
#endif
BEGIN_MESSAGE_MAP(CDialogDlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
В файле cpp
#ifdef _AFXDLL
#define BEGIN_MESSAGE_MAP(theClass, baseClass) \
const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() \
{ return &theClass::messageMap; } \
const AFX_MSGMAP* theClass::GetMessageMap() const \
{ return &theClass::messageMap; } \
AFX_COMDAT const AFX_MSGMAP theClass::messageMap = \
{ &baseClass::GetThisMessageMap, &theClass::_messageEntries[0] }; \
AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = \
{\
#else
#define BEGIN_MESSAGE_MAP(theClass, baseClass) \
const AFX_MSGMAP* theClass::GetMessageMap() const \
{ return &theClass::messageMap; } \
AFX_COMDAT const AFX_MSGMAP theClass::messageMap = \
{ &baseClass::messageMap, &theClass::_messageEntries[0] }; \
AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = \
{\
#endif
#define END_MESSAGE_MAP() \
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \
}; \
AFX_MSGMAP_ENTRY
struct AFX_MSGMAP_ENTRY
{
UINT nMessage; // windows message
UINT nCode; // control code or WM_NOTIFY code
UINT nID; // control ID (or 0 for windows messages)
UINT nLastID; // used for entries specifying a range of
control id's
UINT_PTR nSig;
// signature type (action) or pointer to message #
AFX_PMSG pfn; // routine to call (or special value)
};
Компоненты карты сообщений
Сообщения Windows
Макрос имеет вид для каждого
сообщения:
ON_WM_xxx
ON_WM_LBUTTONUP
Для каждого макроса определен код в
файле afxmsg.h
#define ON_WM_LBUTTONUP() \
{ WM_LBUTTONUP, 0, 0, 0, AfxSig_vwp, \
(AFX_PMSG)(AFX_PMSGW) \
(static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, CPoint) >
(OnLButtonUp)) },
// Dialog Data
enum { IDD = IDD_DIALOG_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
HICON m_hIcon;
сpp
Нотификационные сообщения
// for general controls
#define ON_CONTROL(wNotifyCode, id, memberFxn) \
{ WM_COMMAND, (WORD)wNotifyCode, (WORD)id,
(WORD)id, AfxSigCmd_v, \
(static_cast< AFX_PMSG > (memberFxn)) },
AfxSigCmd_v, // void ()
class CDialogDlg : public CDialog
{
// Construction
public:
CDialogDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
enum { IDD = IDD_DIALOG_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
HICON m_hIcon;
void CDialogDlg::OnEnChangeEdit1()
{
// TODO: If this is a RICHEDIT control, the control will not
// send this notification unless you override the CDialog::OnInitDialog()
// function and call CRichEditCtrl().SetEventMask()
// with the ENM_CHANGE flag ORed into the mask.
// Dialog Data
enum { IDD = IDD_DIALOG_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
HICON m_hIcon;
AfxSigCmd_v, // void ()
#define ON_UPDATE_COMMAND_UI(id, memberFxn) \
{ WM_COMMAND, CN_UPDATE_COMMAND_UI, (WORD)id,
(WORD)id, AfxSigCmdUI, \
(AFX_PMSG) \
(static_cast< void (AFX_MSG_CALL CCmdTarget::*)
(CCmdUI*) > \
(memberFxn)) },
BEGIN_MESSAGE_MAP(CmessApp, CWinApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
// Standard file based document commands
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
// Standard print setup command
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
ON_COMMAND(ID_32771, On32771)
ON_UPDATE_COMMAND_UI(ID_32771, OnUpdate32771)
END_MESSAGE_MAP()
Обработка команд в диапазоне
#define ON_COMMAND_RANGE(id, idLast, memberFxn) \
{ WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)idLast, AfxSigCmd_RANGE, \
(AFX_PMSG) \
(static_cast< void (AFX_MSG_CALL CCmdTarget::*)(UINT) > \
(memberFxn)) },
// ON_COMMAND_RANGE(id, idLast, OnBar) is the same as
// ON_CONTROL_RANGE(0, id, idLast, OnBar)
BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
ON_MESSAGE(WM_MYMESSAGE, OnMyMessage)
END_MESSAGE_MAP()
LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam)
{
Remarks
If you send a message in the range below WM_USER to the asynchronous message functions (PostMessage,
SendNotifyMessage, and SendMessageCallback), its message parameters cannot include pointers. Otherwise, the operation will
fail. The functions will return before the receiving thread has had a chance to process the message and the sender will free the
memory before it is used.
Applications that need to communicate using HWND_BROADCAST should use the RegisterWindowMessage function to obtain a
unique message for inter-application communication.
The system only does marshalling for system messages (those in the range 0 to WM_USER). To send other messages (those
above WM_USER) to another process, you must do custom marshalling.
CWnd::SendNotifyMessage
Sends the specified message to the window.
BOOL SendNotifyMessage( UINT message, WPARAM wParam, LPARAM lParam );
Parameters
message
Specifies the message to be sent.
wParam
Specifies additional message-dependent information.
lParam
Specifies additional message-dependent information.
Return Value
Nonzero if the function is successful; otherwise 0.
Remarks
If the window was created by the calling thread, SendNotifyMessage calls the window
procedure for the window and does not return until the window procedure has
processed the message. If the window was created by a different thread,
SendNotifyMessage passes the message to the window procedure and returns
immediately; it does not wait for the window procedure to finish processing the
message.