- •Содержание
- •Глава 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
305
wndclass.hbrBackground = hBrush;
Главное отличие между битовыми образами и остальными ресурсами в их практической важности и может быть легко выражено так: битовые образы являются объектами GDI. Хороший стиль составления программ рекомендует, что битовые образы должны быть удалены из программы, если в них отпадает нужда, или если программа завершается. В программе RESOURC2 это происходит по завершении работы функции WinMain:
DeleteObject((HGDIOBJ) hBrush);
DeleteObject((HGDIOBJ) hBitmap);
Символьные строки
Наличие ресурса для символьных строк может вначале показаться странным. Тем более, что не было никаких проблем при использовании привычных символьных строк, определенных в качестве переменных непосредственно в теле исходного текста нашей программы.
Ресурсы-символьные строки предназначены главным образом для облегчения перевода вашей программы на другие языки. Как будет рассказано в следующих двух главах, меню и окна диалога также являются частью описания ресурсов. Если вместо непосредственного использования строк в исходном тексте вашей программы, вы используете ресурсы-символьные строки, то весь текст вашей программы, окажется в одном файле — файле описания ресурсов. Если текст в файле описания ресурсов переводится, то все, что вам нужно сделать для иноязычной версии вашей программы, это перекомпоновать программу и добавить переведенные ресурсы в файл с расширением .EXE. Этот способ намного безопасней, чем возня с исходными кодами вашей программы. (Конечно, можно определить все символьные строки в качестве макросов и хранить их в заголовочном файле. Такой способ также позволяет избежать изменения исходного кода программы при переводе на другие языки.)
Использование ресурсов-символьных строк
Ресурсы-символьные строки определяются в описании ресурсов с помощью ключевого слова STRINGTABLE:
STRINGTABLE
{
id1, "character string 1"
id2, "character string 2"
[определения остальных строк]
}
В описании ресурсов может содержаться только одна таблица строк. Максимальный размер каждой строки — 255 символов. В строке не может быть управляющих символов языка С, за исключением \t (табуляция). Однако, символьные строки могут содержать восьмеричные константы:
Табуляция (Tab) |
\011 |
Перевод строки (Linefeed) |
\012 |
Возврат каретки (Carriage return) |
\015 |
Эти управляющие символы распознаются функциями DrawText и MessageBox.
Вы можете использовать функцию LoadString для копирования строки из ресурса в буфер в сегменте данных вашей программы:
LoadString(hInstance, id, szBuffer, iMaxLength);
Параметр id соответствует идентификатору, который предшествует каждой строке в файле описания ресурсов; szBuffer — это указатель на символьный массив, в который заносится символьная строка; iMaxLength — это максимальное число передаваемых в szBuffer символов. Идентификаторы строк, которые предшествуют каждой строке, обычно являются идентификаторами макроопределений, которые задаются в заголовочном файле. Многие программисты, программирующие под Windows, для идентификаторов строк используют префикс IDS_. Иногда, при выводе на экран имени файла или другой информации, она должна быть помещена в строку. В этом случае вы помещаете в строку символы форматирования языка С и используете эту строку в качестве форматирующей в функциях sprintf или wsprintf.
Использование ресурсов-строк в функции MessageBox
Давайте рассмотрим пример программы, в которой для вывода на экран трех сообщений об ошибках в окне сообщений используются три символьные строки. В заголовочном файле, который мы назовем PROGRAM.H, для этих сообщений определяются три идентификатора:
#define IDS_FILENOTFOUND |
1 |
306
#define |
IDS_FILETOOBIG |
2 |
#define |
IDS_FILEREADONLY |
3 |
Файл описания ресурсов выглядит следующим образом:
#include "program.h" |
|
[описание других ресурсов] |
|
STRINGTABLE |
|
{ |
|
IDS_FILENOTFOUND, |
"File %s not found." |
IDS_FILETOOBIG, |
"File %s too large to edit." |
IDS_FILEREADONLY, |
"File %s is read-only." |
} |
|
Файл с исходным кодом на С также включает этот заголовочный файл и определяет функцию для вывода на экран окна сообщений. (Предполагается, что szAppName — это глобальная переменная, в которой содержится имя программы, а hInst — это глобальная переменная, в которой содержится описатель экземпляра вашей программы.)
#include "program.h"
[другие строки программы]
OkMessage(HWND hwnd, int iErrorNumber, char *szFileName)
{
char szFormat[40]; char szBuffer[60];
LoadString(hInst, iErrorNumber, szFormat, 40);
sprintf(szBuffer, szFormat, szFileName);
return MessageBox(hwnd, szBuffer, szAppName, MB_OK | MB_ICONEXCLAMATION);
}
Для вывода на экран окна сообщений с сообщением "File not found." программа вызывает функцию:
OkMessage(hwnd, IDS_FILENOTFOUND, szFileName);
Ресурсы, определяемые пользователем
Ресурсы, определяемые пользователем (user-defined resourse) удобны для включения самых разнообразных данных в ваш файл с расширением .EXE и получения доступа в программе к этим данным. Данные могут содержаться в любом выбранном вами формате — текстовом или бинарном. При загрузке данных в оперативную память возвращаемым значением функций Windows, которые используются для доступа к определяемым пользователем ресурсам, является указатель на данные. С этими данными вы можете делать все, что угодно. Вы вероятно решите, что этот способ хранения и доступа к разнообразным данным удобнее, чем альтернативный, при котором данные хранятся в других файлах и доступ к ним осуществляется через функции файлового ввода.
Например, предположим, что у вас есть файл PROGHELP.TXT, в котором содержится текст "подсказок" для вашей программы. Такой файл не должен быть в чистом виде ASCII-файлом: в нем также могут содержаться бинарные данные, например, указатели, которые могли бы помочь при ссылках на различные части этого файла. Следующим образом опишите ссылку на этот файл в вашем файле описания ресурсов:
helptext TEXT proghelp.txt
Имена helptext (имя ресурса) и TEXT (тип ресурса) в этом выражении могут быть любыми. Слово TEXT написано прописными буквами просто, чтобы сделать его похожим на слова ICON, CURSOR и BITMAP. То, что мы здесь делаем, является созданием ресурса вашего собственного типа, который называется TEXT.
В процессе инициализации программы (например, при обработке сообщения WM_CREATE), можно получить описатель этого ресурса:
hResource = LoadResource(hInstance, FindResource(hInstance, "TEXT", "helptext"));
Переменная hResource определяется как имеющая тип HGLOBAL. Несмотря на свое имя, функция LoadResource фактически не загружает сразу ресурс в оперативную память. Используемые вместе, так как это было показано, функции LoadResource и FindResource по существу эквивалентны функциям LoadIcon и LoadCursor. Фактически,
функции LoadIcon и LoadCursor используют функции LoadResource и FindResource.
307
Вместо имен и типов ресурсов можно использовать числа. Числа могут быть преобразованы в дальние указатели при вызове функции FindResource с использованием MAKEINTRESOURCE. Числа, используемые в качестве типа ресурса, должны быть больше 255. (Числа от 1 до 9 при вызове функции FindResource используются в Windows для существующих типов ресурсов.)
Когда вам необходимо получить доступ к тексту, вызывайте функцию LockResource:
pHelpText = LockResource(hResource);
Функция LockResource загружает ресурс в память (если он еще не был загружен), и возвращает указатель на него. После окончания работы с этим ресурсом, вы можете освободить оперативную память, вызвав функцию
FreeResource:
FreeResource(hResource);
Даже если вы не вызовите функцию FreeResource, после завершения работы программы оперативная память все равно будет освобождена.
Давайте рассмотрим пример программы, в которой используется три ресурса — значок, таблица строк и ресурс, определяемый пользователем. В программе POEPOEM, представленной на рис. 9.3, на экран, в рабочую область окна программы, выводится текст поэмы Эдгара Алана По "Annabel Lee". Ресурс, определяемый пользователем — это файл POEPOEM.ASC, в котором находится текст поэмы. Текстовый файл заканчивается символом обратной косой черты
(\).
POEPOEM.MAK
#-----------------------
# POEPOEM.MAK make file
#-----------------------
poepoem.exe : poepoem.obj poepoem.res
$(LINKER) $(GUIFLAGS) -OUT:poepoem.exe poepoem.obj poepoem.res $(GUILIBS)
poepoem.obj : poepoem.c poepoem.h $(CC) $(CFLAGS) poepoem.c
poepoem.res : poepoem.rc poepoem.ico poepoem.asc poepoem.h $(RC) $(RCVARS) poepoem.rc
POEPOEM.C
/*------------------------------------------------- |
|
POEPOEM.C -- |
Demonstrates User-Defined Resource |
|
(c) Charles Petzold, 1996 |
------------------------------------------------- |
*/ |
#include <windows.h> #include "poepoem.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
char |
szAppName[10]; |
char |
szCaption[35]; |
HINSTANCE |
hInst; |
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{ |
|
HWND |
hwnd; |
MSG |
msg; |
WNDCLASSEX |
wndclass; |
LoadString(hInstance, IDS_APPNAME, szAppName, sizeof(szAppName));
LoadString(hInstance, IDS_CAPTION, szCaption, sizeof(szCaption));
wndclass.cbSize |
= sizeof(wndclass); |
wndclass.style |
= CS_HREDRAW | CS_VREDRAW; |
wndclass.lpfnWndProc |
= WndProc; |
wndclass.cbClsExtra |
= 0; |
308
wndclass.cbWndExtra |
= 0; |
wndclass.hInstance |
= hInstance; |
wndclass.hIcon |
= LoadIcon(hInstance, szAppName); |
wndclass.hCursor |
= LoadCursor(NULL, IDC_ARROW); |
wndclass.hbrBackground |
=(HBRUSH) GetStockObject(WHITE_BRUSH); |
wndclass.lpszMenuName |
= NULL; |
wndclass.lpszClassName |
= szAppName; |
wndclass.hIconSm |
= LoadIcon(hInstance, szAppName); |
RegisterClassEx(&wndclass);
hInst = hInstance;
hwnd = CreateWindow(szAppName, szCaption, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, 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 char |
*pText; |
static HGLOBAL hResource; |
|
static HWND |
hScroll; |
static int |
iPosition, cxChar, cyChar, cyClient, iNumLines, xScroll; |
char |
szPoemRes[15]; |
HDC |
hdc; |
PAINTSTRUCT |
ps; |
RECT |
rect; |
TEXTMETRIC |
tm; |
switch(iMsg)
{
case WM_CREATE :
hdc = GetDC(hwnd); GetTextMetrics(hdc, &tm); cxChar = tm.tmAveCharWidth;
cyChar = tm.tmHeight + tm.tmExternalLeading; ReleaseDC(hwnd, hdc);
xScroll = GetSystemMetrics(SM_CXVSCROLL);
hScroll = CreateWindow("scrollbar", NULL, WS_CHILD | WS_VISIBLE | SBS_VERT, 0, 0, 0, 0,
hwnd,(HMENU) 1, hInst, NULL); LoadString(hInst, IDS_POEMRES, szPoemRes, sizeof(szPoemRes));
hResource = LoadResource(hInst,
FindResource(hInst, szPoemRes, "TEXT"));
pText =(char *) LockResource(hResource);
309
iNumLines = 0;
while(*pText != '\\' && *pText != '\0')
{
if(*pText == '\n') iNumLines ++;
pText = AnsiNext(pText);
}
*pText = '\0';
SetScrollRange(hScroll, SB_CTL, 0, iNumLines, FALSE);
SetScrollPos (hScroll, SB_CTL, 0, FALSE);
return 0;
case WM_SIZE :
MoveWindow(hScroll, LOWORD(lParam) - xScroll, 0,
xScroll, cyClient = HIWORD(lParam), TRUE);
SetFocus(hwnd); return 0;
case WM_SETFOCUS : SetFocus(hScroll); return 0;
case WM_VSCROLL : switch(wParam)
{
case SB_TOP : iPosition = 0; break;
case SB_BOTTOM :
iPosition = iNumLines; break;
case SB_LINEUP : iPosition -= 1; break;
case SB_LINEDOWN : iPosition += 1; break;
case SB_PAGEUP :
iPosition -= cyClient / cyChar; break;
case SB_PAGEDOWN :
iPosition += cyClient / cyChar; break;
case SB_THUMBPOSITION : iPosition = LOWORD(lParam); break;
}
iPosition = max(0, min(iPosition, iNumLines));
if(iPosition != GetScrollPos(hScroll, SB_CTL))
{
SetScrollPos(hScroll, SB_CTL, iPosition, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
}
return 0;
case WM_PAINT :
hdc = BeginPaint(hwnd, &ps);
pText =(char *) LockResource(hResource);
GetClientRect(hwnd, &rect);
310
rect.left += cxChar;
rect.top += cyChar *(1 - iPosition);
DrawText(hdc, pText, -1, &rect, DT_EXTERNALLEADING);
EndPaint(hwnd, &ps); return 0;
case WM_DESTROY : FreeResource(hResource); PostQuitMessage(0); return 0;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
POEPOEM.RC
/*----------------------------
POEPOEM.RC resource script
----------------------------*/
#include "poepoem.h"
poepoem |
ICON |
poepoem.ico |
AnnabelLee |
TEXT |
poepoem.asc |
STRINGTABLE
{
IDS_APPNAME, "poepoem"
IDS_CAPTION, """Annabel Lee"" by Edgar Allen Poe"
IDS_POEMRES, "AnnabelLee"
}
POEPOEM.ICO
POEPOEM.H
/*-----------------------
POEPOEM.H header file
-----------------------*/
#define IDS_APPNAME 0 #define IDS_CAPTION 1 #define IDS_POEMRES 2
POEPOEM.ASC
It was many and many a year ago, In a kingdom by the sea,
That a maiden there lived whom you may know
By the name of Annabel Lee;
And this maiden she lived with no other thought Than to love and be loved by me. I was a child and she was a child
In this kingdom by the sea,
But we loved with a love that was more than love -I and my Annabel Lee -- With a love that the winged seraphs of Heaven Coveted her and me.
And this was the reason that, long ago,
In this kingdom by the sea,
A wind blew out of a cloud, chilling
My beautiful Annabel Lee;
So that her highborn kinsmen came And bore her away from me, To shut her up in a sepulchre
In this kingdom by the sea.
311
The angels, not half so happy in Heaven,
Went envying her and me --
Yes! that was the reason(as all men know,
In this kingdom by the sea)
That the wind came out of the cloud by night, Chilling and killing my Annabel Lee. But our love it was stronger by far than the love Of those who were older than we --
Of many far wiser than we --
And neither the angels in Heaven above
Nor the demons down under the sea
Can ever dissever my soul from the soul Of the beautiful Annabel Lee:
For the moon never beams, without bringing me dreams Of the beautiful Annabel Lee; And the stars never rise, but I feel the bright eyes Of the beautiful Annabel Lee:
And so, all the night-tide, I lie down by the side Of my darling -- my darling -- my life and my bride, In her sepulchre there by the sea --
In her tomb by the sounding sea.
[May, 1849]
Рис. 9.3 Программа POEPOEM, содержащая значок и ресурс, определяемый пользователем
В файле описания ресурсов POEPOEM.RC ресурсу, определяемому пользователем, присваивается тип TEXT и имя
AnnabelLee:
AnnabelLee TEXT poepoem.asc
При обработке в WndProc сообщения WM_CREATE описатель ресурса получается с использованием функций LoadResource и FindResource. Захватывается ресурс с помощью функции LockResource, а небольшая подпрограмма заменяет символ обратной косой черты (\) в конце файла на 0. Это сделано для адаптации текста к функции DrawText, которая позже, при обработке сообщения WM_PAINT, будет отображать его на экране.
Обратите внимание на использование полосы прокрутки-элемента управления вместо полосы прокрутки окна: в полосе прокрутки-элемента управления автоматически поддерживается интерфейс клавиатуры, поэтому в программе POEPOEM не требуется обрабатывать сообщение WM_KEYDOWN.
В программе POEPOEM также используются три символьные строки, идентификаторы которых определяются в заголовочном файле POEPOEM.H. Строки IDS_APPNAME и IDS_CAPTION с помощью функции LoadString заносятся в глобальные статические переменные:
LoadString(hInstance, IDS_APPNAME, szAppName, sizeof(szAppName));
LoadString(hInstance, IDS_CAPTION, szCaption, sizeof(szCaption));
Теперь, когда мы задали все символьные строки программы POEPOEM как ресурсы, мы упростили переводчикам их задачу. Конечно, им все равно придется переводить текст поэмы "Annabel Lee", и есть подозрение, что это будет несколько более трудной задачей.