
- •Содержание
- •Глава 1 README.TXT
- •Вызов, брошенный программистам
- •Основные правила
- •Краткая история Windows
- •Краткая история этой книги
- •Начнем
- •Глава 2 Hello, Windows 95
- •Отличительная особенность Windows
- •Графический интерфейс пользователя
- •Концепции и обоснование GUI
- •Содержимое интерфейса пользователя
- •Преимущество многозадачности
- •Управление памятью
- •Независимость графического интерфейса от оборудования
- •Соглашения операционной системы Windows
- •Вызовы функций
- •Объектно-ориентированное программирование
- •Архитектура, управляемая событиями
- •Оконная процедура
- •Ваша первая программа для Windows
- •Что в этой программе неправильно?
- •Файлы HELLOWIN
- •Make-файл
- •Вызовы функций Windows
- •Идентификаторы, написанные прописными буквами
- •Новые типы данных
- •Описатели
- •Венгерская нотация
- •Точка входа программы
- •Регистрация класса окна
- •Создание окна
- •Отображение окна
- •Цикл обработки сообщений
- •Оконная процедура
- •Обработка сообщений
- •Воспроизведение звукового файла
- •Сообщение WM_PAINT
- •Сообщение WM_DESTROY
- •Сложности программирования для Windows
- •Не вызывай меня, я вызову тебя
- •Синхронные и асинхронные сообщения
- •Думайте о ближнем
- •Кривая обучения
- •Глава 3 Рисование текста
- •Рисование и обновление
- •Сообщение WM_PAINT
- •Действительные и недействительные прямоугольники
- •Введение в графический интерфейс устройства (GDI)
- •Контекст устройства
- •Структура информации о рисовании
- •Получение описателя контекста устройства. Второй метод
- •Функция TextOut. Подробности
- •Системный шрифт
- •Размер символа
- •Метрические параметры текста. Подробности
- •Форматирование текста
- •Соединим все вместе
- •Не хватает места!
- •Размер рабочей области
- •Полосы прокрутки
- •Диапазон и положение полос прокрутки
- •Сообщения полос прокрутки
- •Прокрутка в программе SYSMETS
- •Структурирование вашей программы для рисования
- •Создание улучшенной прокрутки
- •Мне не нравится пользоваться мышью
- •Глава 4 Главное о графике
- •Концепция GDI
- •Структура GDI
- •Типы функций
- •Примитивы GDI
- •Другие аспекты
- •Контекст устройства
- •Получение описателя контекста устройства
- •Программа DEVCAPS1
- •Размер устройства
- •О цветах
- •Атрибуты контекста устройства
- •Сохранение контекста устройства
- •Рисование отрезков
- •Ограничивающий прямоугольник
- •Сплайны Безье
- •Использование стандартных перьев
- •Создание, выбор и удаление перьев
- •Закрашивание пустот
- •Режимы рисования
- •Рисование закрашенных областей
- •Функция Polygon и режим закрашивания многоугольника
- •Закрашивание внутренней области
- •Режим отображения
- •Координаты устройства (физические координаты) и логические координаты
- •Системы координат устройства
- •Область вывода и окно
- •Работа в режиме MM_TEXT
- •Метрические режимы отображения
- •Ваши собственные режимы отображения
- •Программа WHATSIZE
- •Прямоугольники, регионы и отсечение
- •Работа с прямоугольниками
- •Случайные прямоугольники
- •Создание и рисование регионов
- •Отсечения: прямоугольники и регионы
- •Программа CLOVER
- •Пути
- •Создание и воспроизведение путей
- •Расширенные перья
- •Bits and Blts
- •Цвета и битовые образы
- •Файл DIB
- •Упакованный формат хранения DIB
- •Отображение DIB
- •Преобразование DIB в объекты "битовые образы"
- •Битовый образ — объект GDI
- •Создание битовых образов в программе
- •Формат монохромного битового образа
- •Формат цветного битового образа
- •Контекст памяти
- •Мощная функция BitBlt
- •Перенос битов с помощью функции BitBlt
- •Функция DrawBitmap
- •Использование других ROP кодов
- •Дополнительные сведения о контексте памяти
- •Растяжение битовых образов с помощью функции StretchBlt
- •Кисти и битовые образы
- •Метафайлы
- •Простое использование метафайлов памяти
- •Сохранение метафайлов на диске
- •Расширенные метафайлы
- •Делаем это лучше
- •Базовая процедура
- •Заглянем внутрь
- •Вывод точных изображений
- •Текст и шрифты
- •Вывод простого текста
- •Атрибуты контекста устройства и текст
- •Использование стандартных шрифтов
- •Типы шрифтов
- •Шрифты TrueType
- •Система EZFONT
- •Внутренняя работа
- •Форматирование простого текста
- •Работа с абзацами
- •Глава 5 Клавиатура
- •Клавиатура. Основные понятия
- •Игнорирование клавиатуры
- •Фокус ввода
- •Аппаратные и символьные сообщения
- •Аппаратные сообщения
- •Системные и несистемные аппаратные сообщения клавиатуры
- •Переменная lParam
- •Виртуальные коды клавиш
- •Использование сообщений клавиатуры
- •Модернизация SYSMETS: добавление интерфейса клавиатуры
- •Логика обработки сообщений WM_KEYDOWN
- •Посылка асинхронных сообщений
- •Символьные сообщения
- •Сообщения WM_CHAR
- •Сообщения немых символов
- •Каретка (не курсор)
- •Функции работы с кареткой
- •Программа TYPER
- •Наборы символов Windows
- •Набор символов OEM
- •Набор символов ANSI
- •Наборы символов OEM, ANSI и шрифты
- •Международные интересы
- •Работа с набором символов
- •Связь с MS-DOS
- •Использование цифровой клавиатуры
- •Решение проблемы с использованием системы UNICODE в Windows NT
- •Глава 6 Мышь
- •Базовые знания о мыши
- •Несколько кратких определений
- •Сообщения мыши, связанные с рабочей областью окна
- •Простой пример обработки сообщений мыши
- •Обработка клавиш <Shift>
- •Сообщения мыши нерабочей области
- •Сообщение теста попадания
- •Сообщения порождают сообщения
- •Тестирование попадания в ваших программах
- •Гипотетический пример
- •Пример программы
- •Эмуляция мыши с помощью клавиатуры
- •Добавление интерфейса клавиатуры к программе CHECKER
- •Использование дочерних окон для тестирования попадания
- •Дочерние окна в программе CHECKER
- •Захват мыши
- •Рисование прямоугольника
- •Решение проблемы — захват
- •Программа BLOKOUT2
- •Глава 7 Таймер
- •Основы использования таймера
- •Система и таймер
- •Таймерные сообщения не являются асинхронными
- •Использование таймера: три способа
- •Первый способ
- •Второй способ
- •Третий способ
- •Использование таймера для часов
- •Позиционирование и изменение размеров всплывающего окна
- •Получение даты и времени
- •Обеспечение международной поддержки
- •Создание аналоговых часов
- •Стандартное время Windows
- •Анимация
- •Класс кнопок
- •Создание дочерних окон
- •Сообщения дочерних окон родительскому окну
- •Сообщения родительского окна дочерним окнам
- •Нажимаемые кнопки
- •Флажки
- •Переключатели
- •Окна группы
- •Изменение текста кнопки
- •Видимые и доступные кнопки
- •Кнопки и фокус ввода
- •Дочерние окна управления и цвета
- •Системные цвета
- •Цвета кнопок
- •Сообщение WM_CTLCOLORBTN
- •Кнопки, определяемые пользователем
- •Класс статических дочерних окон
- •Класс полос прокрутки
- •Программа COLORS1
- •Интерфейс клавиатуры, поддерживаемый автоматически
- •Введение новой оконной процедуры
- •Закрашивание фона
- •Окрашивание полос прокрутки и статического текста
- •Класс редактирования
- •Стили класса редактирования
- •Коды уведомления управляющих окон редактирования
- •Использование управляющих окон редактирования
- •Сообщения управляющему окну редактирования
- •Класс окна списка
- •Стили окна списка
- •Добавление строк в окно списка
- •Выбор и извлечение элементов списка
- •Получение сообщений от окон списка
- •Простое приложение, использующее окно списка
- •Список файлов
- •Утилита Head для Windows
- •Компиляция ресурсов
- •Значки и курсоры
- •Редактор изображений
- •Получение описателя значков
- •Использование значков в вашей программе
- •Использование альтернативных курсоров
- •Битовые образы: картинки в пикселях
- •Использование битовых образов и кистей
- •Символьные строки
- •Использование ресурсов-символьных строк
- •Меню
- •Структура меню
- •Шаблон меню
- •Ссылки на меню в вашей программе
- •Меню и сообщения
- •Образец программы
- •Этикет при организации меню
- •Сложный способ определения меню
- •Третий подход к определению меню
- •Независимые всплывающие меню
- •Использование системного меню
- •Изменение меню
- •Другие команды меню
- •Использование в меню битовых образов
- •Два способа создания битовых образов для меню
- •Контекст памяти
- •Создание битового образа, содержащего текст
- •Масштабирование битовых образов
- •Соберем все вместе
- •Добавление интерфейса клавиатуры
- •Быстрые клавиши
- •Зачем нужны быстрые клавиши?
- •Некоторые правила назначения быстрых клавиш
- •Таблица быстрых клавиш
- •Преобразование нажатий клавиш клавиатуры
- •Получение сообщений быстрых клавиш
- •Программа POPPAD, имеющая меню и быстрые клавиши
- •Разрешение пунктов меню
- •Обработка опций меню
- •Глава 11 Окна диалога
- •Модальные окна диалога
- •Создание окна диалога About
- •Шаблон окна диалога
- •Диалоговая процедура
- •Вызов окна диалога
- •Дополнительная информация о стиле окна диалога
- •Дополнительная информация об определении дочерних окон элементов управления
- •Более сложное окно диалога
- •Работа с дочерними элементами управления окна диалога
- •Кнопки OK и Cancel
- •Позиции табуляции и группы
- •Рисование в окне диалога
- •Использование с окном диалога других функций
- •Определение собственных окон управления
- •Окна сообщений
- •Информация во всплывающих окнах
- •Немодальные окна диалога
- •Различия между модальными и немодальными окнами диалога
- •Новая программа COLORS
- •Программа HEXCALC: обычное окно или окно диалога?
- •Творческое использование идентификаторов дочерних окон элементов управления
- •Диалоговые окна общего пользования
- •Модернизированная программа POPPAD
- •Изменение шрифта
- •Поиск и замена
- •Программа для Windows, содержащая всего один вызов функции
- •Основы элементов управления общего пользования
- •Инициализация библиотеки
- •Создание элементов управления общего пользования
- •Стили элементов управления общего пользования
- •Уведомляющие сообщения от элементов управления общего пользования
- •Элементы управления главного окна
- •Панели инструментов
- •Создание панели инструментов
- •Строка состояния
- •Программа GADGETS
- •Наборы страниц свойств
- •Создание набора страниц свойств
- •Процедуры диалогового окна страницы свойств
- •Программа PROPERTY

328
Затем Windows выводит на экран всплывающее меню с пунктами File, Edit, Background и Help. Выбор любого из этих пунктов приводит к тому, что вложенное всплывающее окно меню появляется на экране правее выбранной опции. Функции этого меню те же, что и у обычного меню.
Использование системного меню
В родительских окнах, стиль которых содержит идентификатор WS_SYSMENU, имеется зона системного меню в левой части строки заголовка. При желании, можно модифицировать это меню. Например, к системному меню можно добавить собственные команды. Хотя это и не рекомендуется, модификация системного меню — это, как правило, быстрый, но некрасивый способ добавления меню к короткой программе, без определения его в файле описания ресурсов. Здесь имеется только одно ограничение: идентификатор, который вы используете для добавления команды к системному меню должен быть меньше, чем 0xF000. В противном случае он будет конфликтовать с идентификаторами, которые Windows использует для команд обычного системного меню. И запомните: при обработке сообщений WM_SYSCOMMAND для этих новых пунктов меню в вашей оконной процедуре, остальные сообщения WM_SYSCOMMAND вы должны передавать в DefWindowProc. Если вы этого не сделаете, то гарантировано запретите все обычные опции системного меню.
Программа POORMENU ("Poor Person's Menu"), представленная на рис. 10.4, добавляет к системному меню разделительную линию и три команды. Последняя из этих команд удаляет добавления.
POORMENU.MAK
#------------------------
# POORMENU.MAK make file
#------------------------
poormenu.exe : poormenu.obj
$(LINKER) $(GUIFLAGS) -OUT:poormenu.exe poormenu.obj $(GUILIBS) poormenu.obj : poormenu.c
$(CC) $(CFLAGS) poormenu.c
POORMENU.C
/*----------------------------------------- |
|
POORMENU.C -- |
The Poor Person's Menu |
|
(c) Charles Petzold, 1996 |
----------------------------------------- |
*/ |
#include <windows.h>
#define IDM_ABOUT 1 #define IDM_HELP 2 #define IDM_REMOVE 3
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static char szAppName[] = "PoorMenu";
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{ |
|
HMENU |
hMenu; |
HWND |
hwnd; |
MSG |
msg; |
WNDCLASSEX wndclass; |
|
wndclass.cbSize |
= sizeof(wndclass); |
wndclass.style |
= CS_HREDRAW | CS_VREDRAW; |
wndclass.lpfnWndProc |
= WndProc; |
wndclass.cbClsExtra |
= 0; |
wndclass.cbWndExtra |
= 0; |
wndclass.hInstance |
= hInstance; |
wndclass.hIcon |
= LoadIcon(NULL, IDI_APPLICATION); |
wndclass.hCursor |
= LoadCursor(NULL, IDC_ARROW); |
wndclass.hbrBackground |
=(HBRUSH) GetStockObject(WHITE_BRUSH); |
wndclass.lpszMenuName |
= NULL; |

329
wndclass.lpszClassName |
= |
szAppName; |
wndclass.hIconSm |
= |
LoadIcon(NULL, IDI_APPLICATION); |
RegisterClassEx(&wndclass);
hwnd = CreateWindow(szAppName, "The Poor-Person's Menu", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
hMenu = GetSystemMenu(hwnd, FALSE); |
|
|
AppendMenu(hMenu, MF_SEPARATOR, 0, |
NULL); |
|
AppendMenu(hMenu, MF_STRING, |
IDM_ABOUT, |
"About..."); |
AppendMenu(hMenu, MF_STRING, |
IDM_HELP, |
"Help..."); |
AppendMenu(hMenu, MF_STRING, |
IDM_REMOVE, |
"Remove Additions"); |
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
switch(iMsg)
{
case WM_SYSCOMMAND : switch(LOWORD(wParam))
{
case IDM_ABOUT :
MessageBox(hwnd, "A Poor-Person's Menu Program.",
szAppName, MB_OK | MB_ICONINFORMATION);
return 0;
case IDM_HELP :
MessageBox(hwnd, "Help not yet implemented!", szAppName, MB_OK | MB_ICONEXCLAMATION);
return 0;
case IDM_REMOVE : GetSystemMenu(hwnd, TRUE); return 0;
}
break;
case WM_DESTROY : PostQuitMessage(0); return 0;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
Рис. 10.4 Программа POORMENU
Три идентификатора меню определяются в самом начале программы POORMENU.С:
#define IDM_ABOUT |
1 |
#define IDM_HELP |
2 |
#define IDM_REMOVE |
3 |

330
После создания окна POORMENU получает описатель системного меню:
hMenu = GetSystemMenu(hwnd, FALSE);
При первом вызове функции GetSystemMenu необходимо установить второй параметр в FALSE для подготовки к модификации меню.
Меню изменяется четырьмя вызовами функции AppendMenu:
AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(hMenu, MF_STRING, IDM_ABOUT, "About...");
AppendMenu(hMenu, MF_STRING, IDM_HELP, "Help...");
AppendMenu(hMenu, MF_STRING, IDM_REMOVE, "Remove Additions");
Первый вызов функции AppendMenu добавляет разделитель. Выбор пункта меню Remove Additions заставляет программу POORMENU удалить эти добавления, что выполняется просто путем повторного вызова функции GetSystemMenu со вторым параметром, установленным в TRUE:
GetSystemMenu(hwnd, TRUE);
В стандартном системном меню имеются опции Restore, Move, Size, Minimize, Maximize, Close и Switch To. Они генерируют сообщения WM_SYSCOMMAND с параметром wParam, равным SC_RESTORE, SC_MOVE, SC_SIZE, SC_MINIMIZE, SC_MAXIMIZE, SC_CLOSE и SC_TASKLIST. Хотя в программах для Windows этого обычно не делается, вы сами можете обработать эти сообщения, а не передавать их в DefWindowProc. Вы также можете запретить или удалить из системного меню некоторые из этих стандартных опций, используя описанные ниже способы. В документацию Windows также включено несколько стандартных дополнений к системному меню. В них используются идентификаторы SC_NEXTWINDOW, SC_PREVWINDOW, SC_VSCROLL, SC_HSCROLL и SC_ARRANGE. Как вы, наверное, догадались, они предназначены для добавления этих команд к системному меню в некоторых приложениях.
Изменение меню
Мы уже видели, как функция AppendMenu может использоваться для определения меню в целом внутри программы и добавления пунктов к системному меню. До появления Windows 3.0 для выполнения этой работы использовалась функция ChangeMenu. Функция ChangeMenu была столь многогранной по своим задачам, что была одной из наиболее сложных функций в Windows. В Windows 95 эта функция по-прежнему имеется, но ее задачи распределены между пятью новыми функциями:
•AppendMenu — добавляет новый элемент в конец меню.
•DeleteMenu — удаляет существующий пункт меню и уничтожает его.
•InsertMenu — вставляет в меню новый пункт.
•ModifyMenu — изменяет существующий пункт меню.
•RemoveMenu — удаляет существующий пункт меню.
Отличие между функциями DeleteMenu и RemoveMenu весьма важно, если указанный пункт меню является всплывающим меню. Функция DeleteMenu уничтожает всплывающее меню, а функция RemoveMenu — нет.
Другие команды меню
Для работы с меню имеется еще несколько полезных функций.
Если изменяется пункт главного меню, изменения не произойдет, пока Windows не перерисует строку меню. Вызвав функцию DrawMenuBar, можно форсировать эту операцию:
DrawMenuBar(hwnd);
Обратите внимание, что параметром функции DrawMenuBar является описатель окна, а не описатель меню. Описатель всплывающего меню можно получить с помощью функции GetSubMenu:
hMenuPopup = GetSubMenu(hMenu, iPosition);
где iPosition — это индекс (отсчитываемый с 0) всплывающего меню внутри главного меню, которое задается параметром hMenu. Затем, полученный описатель всплывающего меню hMenuPopup можно использовать в других функциях, например, AppendMenu.
Текущее число пунктов главного или всплывающего меню можно получить с помощью функции
GetMenuItemCount:
iCount = GetMenuItemCount(hMenu);
Идентификатор меню для пункта всплывающего меню можно получить следующим образом:
id = GetMenuItemID(hMenuPopup, iPosition);

331
В программе MENUDEMO было показано, как установить или удалить метку пункта всплывающего меню с помощью функции CheckMenuItem:
CheckMenuItem(hMenu, id, iCheck);
В программе MENUDEMO hMenu был описателем главного меню, id — идентификатором меню, а значение параметра iCheck было равно либо MF_CHECKED, либо MF_UNCHECKED. Если hMenu является описателем всплывающего меню, то параметр id может стать не идентификатором меню, а индексом положения. Если пользоваться этим индексом удобнее, то в третьем параметре указывается флаг MF_BYPOSITION. Например:
CheckMenuItem(hMenu, iPosition, MF_CHECKED | MF_BYPOSITION);
Работа функции EnableMenuItem похожа на работу функции CheckMenuItem за исключением того, что третьим параметром может быть MF_ENABLED, MF_DISABLED или MF_GRAYED. Если используется функция EnableMenuItem для пункта главного меню, содержащего всплывающее меню, то в качестве третьего параметра следует использовать идентификатор MF_BYPOSITION, поскольку этот пункт меню не имеет идентификатора меню. Мы рассмотрим пример использования функции EnableMenuItem в программе POPPAD, представленной далее в этой главе. Функция HiliteMenuItem напоминает функции CheckMenuItem и EnableMenuItem, но использует идентификаторы MF_HILITE и MF_UNHILITE. Эта функция обеспечивает инверсное изображение, которое Windows использует, когда вы перемещаете указатель от одного из пунктов меню к другому. Обычным приложениям нет необходимости использовать функцию HiliteMenuItem.
Что еще нужно сделать с меню? Если вы забыли, какие символьные строки использовались в вашем меню, то освежить память можно следующим образом:
iByteCount = GetMenuString(hMenu, id, pString, iMaxCount, iFlag);
Параметр iFlag равен либо MF_BYCOMMAND (при этом id — это идентификатор меню), либо MF_BYPOSITION (при этом id — это индекс положения). Функция копирует iMaxCount байтов строки символов в pString и возвращает число скопированных байтов.
Может быть вы хотите узнать, каковы текущие флаги пункта меню:
iFlags = GetMenuState(hMenu, id, iFlag);
И снова, параметр iFlag равен либо MF_BYCOMMAND, либо MF_BYPOSITION. Возвращаемое значение функции iFlags — это комбинация всех текущих флагов. Вы можете определить текущие флаги, проверив iFlags с помощью идентификаторов MF_DISABLED, MF_GRAYED, MF_CHECKED, MF_MENUBREAK, MF_MENUBARBREAK и MF_SEPARATOR.
А может быть, вам уже слегка надоело меню. В таком случае, если меню вам больше не нужно, его можно удалить:
DestroyMenu(hMenu);
Эта функция делает недействительным описатель меню.
Нестандартный подход к меню
Теперь, давайте немного сойдем с проторенной дороги. Вместо создания в вашей программе всплывающих меню, попробуем создать нескольких главных меню и переключаться между ними с помощью вызова функции SetMenu. Программа NOPOPUPS, представленная на рис. 10.5, показывает, как это сделать. В этой программе, так же как в программе MENUDEMO, имеются пункты меню File и Edit, но вывод их на экран осуществляется по-другому, в виде главного меню.
NOPOPUPS.MAK
#------------------------
# NOPOPUPS.MAK make file
#------------------------
nopopups.exe : nopopups.obj nopopups.res
$(LINKER) $(GUIFLAGS) -OUT:nopopups.exe nopopups.obj \ nopopups.res $(GUILIBS)
nopopups.obj : nopopups.c nopopups.h $(CC) $(CFLAGS) nopopups.c
nopopups.res : nopopups.rc nopopups.h $(RC) $(RCVARS) nopopups.rc

332
NOPOPUPS.C
/*-------------------------------------------------
NOPOPUPS.C -- Demonstrates No-Popup Nested Menu
(c) Charles Petzold, 1996
-------------------------------------------------*/
#include <windows.h> #include "nopopups.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static char szAppName[] = "NoPopUps";
HWND |
hwnd; |
MSG |
msg; |
WNDCLASSEX |
wndclass; |
wndclass.cbSize |
= sizeof(wndclass); |
wndclass.style |
= CS_HREDRAW | CS_VREDRAW; |
wndclass.lpfnWndProc |
= WndProc; |
wndclass.cbClsExtra |
= 0; |
wndclass.cbWndExtra |
= 0; |
wndclass.hInstance |
= hInstance; |
wndclass.hIcon |
= LoadIcon(NULL, IDI_APPLICATION); |
wndclass.hCursor |
= LoadCursor(NULL, IDC_ARROW); |
wndclass.hbrBackground |
=(HBRUSH) GetStockObject(WHITE_BRUSH); |
wndclass.lpszMenuName |
= NULL; |
wndclass.lpszClassName |
= szAppName; |
wndclass.hIconSm |
= LoadIcon(NULL, IDI_APPLICATION); |
RegisterClassEx(&wndclass);
hwnd = CreateWindow(szAppName, "No-Popup Nested Menu Demonstration", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static HMENU hMenuMain, hMenuEdit, hMenuFile; HINSTANCE hInstance;
switch(iMsg)
{
case WM_CREATE :
hInstance =(HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE);
hMenuMain = LoadMenu(hInstance, "MenuMain");
hMenuFile = LoadMenu(hInstance, "MenuFile");

333
hMenuEdit = LoadMenu(hInstance, "MenuEdit");
SetMenu(hwnd, hMenuMain); return 0;
case WM_COMMAND : switch(LOWORD(wParam))
{
case IDM_MAIN :
SetMenu(hwnd, hMenuMain); return 0;
case IDM_FILE :
SetMenu(hwnd, hMenuFile); return 0;
case IDM_EDIT :
SetMenu(hwnd, hMenuEdit); return 0;
case IDM_NEW : case IDM_OPEN : case IDM_SAVE : case IDM_SAVEAS : case IDM_UNDO : case IDM_CUT : case IDM_COPY : case IDM_PASTE : case IDM_DEL :
MessageBeep(0); return 0;
}
break;
case WM_DESTROY : SetMenu(hwnd, hMenuMain); DestroyMenu(hMenuFile); DestroyMenu(hMenuEdit);
PostQuitMessage(0); return 0;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
NOPOPUPS.RC
/*-----------------------------
NOPOPUPS.RC resource script
----------------------------- |
|
*/ |
|
#include "nopopups.h" |
|
|
|
MenuMain MENU |
|
|
|
{ |
|
|
|
MENUITEM "MAIN:", |
|
0, |
INACTIVE |
MENUITEM "&File... |
", |
IDM_FILE |
|
MENUITEM "&Edit... |
", |
IDM_EDIT |
|
} |
|
|
|
MenuFile MENU |
|
|
|
{ |
|
|
|
MENUITEM "FILE:", |
|
0, |
INACTIVE |
MENUITEM "&New", |
|
IDM_NEW |
|
MENUITEM "&Open... |
", |
IDM_OPEN |
|
MENUITEM "&Save", |
|
IDM_SAVE |
|

334
MENUITEM |
"Save &As...", |
IDM_SAVEAS |
||
MENUITEM "(&Main)", |
IDM_MAIN |
|
||
} |
|
|
|
|
MenuEdit MENU |
|
|
|
|
{ |
|
|
|
|
MENUITEM "EDIT:", |
0, |
INACTIVE |
||
MENUITEM "&Undo", |
IDM_UNDO |
|
||
MENUITEM "Cu&t", |
IDM_CUT |
|
||
MENUITEM "&Copy", |
IDM_COPY |
|
||
MENUITEM "&Paste", |
IDM_PASTE |
|
||
MENUITEM "De&lete", |
IDM_DEL |
|
||
MENUITEM "(&Main)", |
IDM_MAIN |
|
||
} |
|
|
|
|
NOPOPUPS.H |
|
|
|
|
/*------------------------ |
|
|
||
NOPOPUPS.H header file |
|
|
||
------------------------*/ |
|
|
||
#define IDM_NEW |
1 |
|
|
|
#define IDM_OPEN |
2 |
|
|
|
#define IDM_SAVE |
3 |
|
|
|
#define IDM_SAVEAS |
4 |
|
|
|
#define IDM_UNDO |
5 |
|
|
|
#define IDM_CUT |
6 |
|
|
|
#define IDM_COPY |
7 |
|
|
|
#define IDM_PASTE |
8 |
|
|
|
#define IDM_DEL |
9 |
|
|
|
#define IDM_MAIN |
10 |
|
|
|
#define IDM_EDIT |
11 |
|
|
|
#define IDM_FILE |
12 |
|
|
Рис. 10.5 Программа NOPOPUPS
В файле описания ресурсов вместо одного имеется три меню. Когда оконная процедура обрабатывает сообщение WM_CREATE, Windows загружает в память ресурс каждого меню:
hMenuMain = LoadMenu(hInstance, "MenuMain");
hMenuFile = LoadMenu(hInstance, "MenuFile");
hMenuEdit = LoadMenu(hInstance, "MenuEdit");
В начале работы программа выводит на экран главное меню:
SetMenu(hwnd, hMenuMain);
В главном меню тремя символьными строками представлены три опции "MAIN:", "File..." и "Edit...". Однако, опция "MAIN:" запрещена, поэтому она не вызывает посылку оконной процедуре сообщения WM_COMMAND. Для идентификации себя в качестве подменю, меню File и Edit начинаются с "FILE:" и "EDIT:". Последним пунктом меню File и Edit является текстовая строка "(Main)"; эта опция обозначает возвращение в главное меню. Переключение между этими тремя меню достаточно простое:
case WM_COMMAND : switch(LOWORD(wParam))
{
case IDM_MAIN :
SetMenu(hwnd, hMenuMain); return 0;
case IDM_FILE :
SetMenu(hwnd, hMenuFile); return 0;
case IDM_EDIT :
SetMenu(hwnd, hMenuEdit); return 0;