Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

лекции / Shchupak_Yu._Win32_API_Razrabotka_prilozheniy_dlya_Windows

.pdf
Скачиваний:
0
Добавлен:
11.02.2026
Размер:
13.15 Mб
Скачать

Растровые образы

261

 

 

 

Также растровые образы применяются для создания кистей. Кисти являются шаблонами пикселов, которые Windows использует для закрашивания изобража емых на экране областей. Пример такого использования битового образа вы мо жете найти в листинге 12.1 (глава 12).

Растровые образы создаются при помощи графического редактора аналогич но созданию пиктограмм. На первом шаге в диалоговом окне Insert Resource вмес то типа ресурса Icon выбирается тип Bitmap. Вызванный графический редактор будет работать в режиме создания растрового ресурса. В отличие от пиктограмм, растровые образы не ограничены в размерах.

Когда вы назначаете ресурсу идентификатор (на третьем шаге), окно Bitmap Properties (рис. 5.14) позволяет установить любые размеры для рисунка, а также выбрать палитру, содержащую 16 или 256 цветов.

Иногда бывает удобнее создать рисунок во внешнем графическом редакторе, обладающем более широкими возможностями, и добавить его в состав ресурсов приложения, выбрав на первом шаге режим Импорт. Ранее уже рассматривался сценарий импорта существующей пиктограммы. Импорт растрового образа осу ществляется аналогично.

Рис. 5.14. Диалоговое окно Bitmap Properties

Для использования растра в программе необходимо определить дескриптор типа HBITMAP и присвоить ему значение, возвращаемое функцией LoadBitmap:

HBITMAP LoadBitmap(

HINSTANCE hInstance, // дескриптор экземпляра приложения LPCTSTR lpBitmapName // имя растрового ресурса

);

Второй параметр функции интерпретируется так же, как для функции LoadIcon. Растровые ресурсы хранятся в модулях Win32 в формате упакованного DIB растра. Функция LoadBitmap находит растровый ресурс, загружает его в память, получает дескриптор упакованного DIB растра, затем на его базе создает DDB растр, совместимый с текущим экранным режимом, и возвращает дескриптор DDB растра. Вывод растрового образа в окно осуществляется при помощи функции BitBlt или StretchBlt с использованием совместимого контекста в памяти. Подробно эта

технология рассматривалась в главе 3.

Продолжим разработку программы Russia. На этом этапе мы добавим к ней ресурс растрового образа.

Для подготовки изображения воспользуемся внешним графическим редакто ром MS Paint. Создайте с его помощью новый рисунок размером 400 × 280 пиксе лов, содержащий изображение российского государственного флага с наложени ем надписи «Russia today» (рис. 5.15).

262

Глава 5. Ресурсы Windows-приложения

 

 

Рис. 5.15. Создание файла RussiaToday.bmp с помощью MS Paint

Этот рисунок нужно сохранить в файле с именем RusFlag.bmp, выбрав 256 цвет ный формат. Поместите файл с рисунком в папку проекта Russia1.

Добавьте к нашему приложению ресурс растрового образа в режиме Импорт, связав его с файлом RusFlag.bmp и назначив идентификатор IDB_RUSFLAG.

Если после сохранения ресурса открыть файл Russia.rc в текстовом режиме, то можно найти строку с определением нового ресурса:

IDB_RUSFLAG

BITMAP DISCARDABLE

"RusFlag.bmp"

Теперь займемся кодом программы. Для создания третьей редакции проекта нужно сделать несколько дополнительных вставок.

Добавьте в теле оконной процедуры определения переменных

static

HBITMAP hBmpRusFlag;

//

дескриптор

растра

HDC hMemDC;

// контекст устройства в памяти

static

BITMAP bm;

//

параметры

растра

В блоке обработки сообщения WM_CREATE добавьте инструкции

hBmpRusFlag = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_RUSFLAG)); GetObject(hBmpRusFlag, sizeof(bm), (LPSTR)&bm);

В блоке обработки сообщения WM_PAINT сразу после вызова функции BeginPaint разместите следующий фрагмент кода:

hMemDC = CreateCompatibleDC(hDC); SelectObject(hMemDC, hBmpRusFlag);

BitBlt(hDC, 0, 0, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0, SRCCOPY); DeleteDC(hMemDC);

После компиляции и запуска приложения его основное окно будет выглядеть, как показано на рис. 5.16.

1Вы можете взять готовый файл с рисунком, если загрузите исходный код данного проекта из фай лов к книге, доступных на сайте издательства «Питер» (www.piter.com).

Ресурсы, определяемые программистом

263

 

 

 

Рис. 5.16. Программа Russia. Курсор мыши находится у нижней границы окна

Перемещая курсор мыши в окне программы, понаблюдайте за изменением формы курсора и за качеством отображения картинки. Теперь проведите такой эксперимент. Замените второй аргумент (&rect) в вызове функции InvalidateRect значением NULL и перекомпилируйте программу. Посмотрите, как изменится ее поведение при перемещении курсора мыши.

Ресурсы, определяемые программистом

Ресурсы, определяемые программистом (user defined resource), позволяют вклю чать в выполняемый файл данные любого типа, после чего программа может лег ко получить к ним доступ во время своей работы. Эти ресурсы могут иметь любой формат: текстовый, двоичный или даже смешанный.

Предположим, что есть файл proghelp.txt, в котором содержится текст подска зок для пользователей приложения. Его можно включить в проект в качестве ре сурса, если добавить в файл описания ресурсов следующую строку:

HELPTEXT

TEXT

DISCARDABLE

proghelp.txt

Имя ресурса (HELPTEXT) и его тип (TEXT) в этом выражении могут быть лю быми. Для имени ресурса стоит использовать прописные буквы, так как компи лятор ресурсов в любом случае преобразует символы этого имени в символы вер хнего регистра.

В процессе инициализации программы, например при обработке сообщения WM_CREATE, можно получить дескриптор этого ресурса, а через него — доступ к данным в файле proghelp.txt.

Другой пример: вы можете включить в программу в виде ресурса мультиме дийный файл с записанным звуковым сопровождением. Пример такого исполь зования ресурсов, определенных программистом, приводится в разделе «Воспро изведение звуковых файлов».

К сожалению, редактор ресурсов Visual Studio не очень удобен для добавле ния ресурсов, определяемых программистом. Поэтому проще будет открыть файл

264 Глава 5. Ресурсы Windows-приложения

описания ресурсов в текстовом формате и добавить строку описания вашего ре сурса в следующем формате:

имя_ресурса тип_ресурса DISCARDABLE имя_файла

Рассмотрим технику доступа к ресурсам, которые определены программистом. Она немного сложнее, чем для ресурсов стандартных типов.

Доступ к данным в ресурсе

Для получения доступа к данным ресурса, определенного программистом, исполь зуются функции FindResource, LoadResource и LockResource.

Функция FindResource ищет ресурс указанного типа в соответствующем модуле. Она имеет следующий прототип:

HRSRC FindResource(HMODULE hModule, LPCTSTR lpName, LPCTSTR lpType);

Параметр hModule позволяет указывать дескриптор модуля выполняемого фай ла, который содержит указанный ресурс. Если hModule равен NULL, то Windows ищет ресурс в модуле, создавшем текущий процесс.

Параметр lpName содержит имя ресурса, представленное, как правило, строкой. Но если первым символом в строке является знак «#», то остальная часть представ ляет целое значение идентификатора ресурса. Параметр lpType задает тип ресурса.

При успешном выполнении функция возвращает дескриптор информационного блока указанного ресурса, а не дескриптор самого ресурса. Чтобы получить деск риптор ресурса, нужно передать дескриптор информационного блока функции LoadResource. В случае неудачи функция FindResource возвращает значение NULL.

Функция LoadResource загружает ресурс, найденный функцией FindResource, в глобальную область памяти. Прототип этой функции выглядит следующим образом:

HGLOBAL LoadResource(HMODULE hModule, HRSRC hResInfo);

Параметру hResInfo должен передаваться дескриптор информационного бло ка, возвращенный функцией FindResource.

Хотя адрес, возвращаемый функцией LoadResource, в принципе, можно исполь зовать для доступа к данным ресурса, MSDN рекомендует получать указатель на эти данные, вызывая функцию LockResource:

LPVOID LockResource(HGLOBAL hResData);

Функция осуществляет блокировку указанного ресурса в памяти. Параметр hResData — это дескриптор ресурса, который должен быть заблокирован. В каче стве параметра необходимо передать адрес, возвращенный функцией LoadResource.

В случае успешного выполнения функция LockResource возвращает указатель на первый байт данных ресурса, в случае неудачи — значение NULL.

После использования данных ресурса его разблокировка не требуется, так как система автоматически удаляет ресурс из памяти при закрытии приложения.

Если вернуться к примеру с файлом proghelp.txt, который был добавлен к при ложению в виде определенного программистом ресурса, то доступ к данным этого ресурса можно получить при помощи следующего фрагмента кода:

HGLOBAL hResource = LoadResource(hInstance, FindResource(hInstance, "HELPTEXT", "TEXT"));

char* pHelpText = (char*) LockResource(hResource);

Воспроизведение звуковых файлов

265

 

 

 

Другой пример использования ресурсов, определенных программистом, будет рассмотрен в следующем разделе.

Воспроизведение звуковых файлов

Добавление звука к приложению может сделать его более эффективным для пользо вателя, а в каких то случаях и более привлекательным. Например, можно исполь зовать специальные звуки или воспроизведение аудиоклипов, чтобы привлечь вни мание пользователя при обнаружении ошибок или при завершении длительной операции. Другие очевидные сферы применения музыкальных и звуковых эффек тов — это обучающие программы, а также приложения, предназначенные для пре зентаций или рекламы.

Win32 API поддерживает работу только со звуковыми файлами, записанными в формате WAVE (waveform audio file fomat). Файлы этого формата имеют расши рение .wav. Они содержат оцифрованные с некоторой частотой 8 или 16 битовые звуковые данные. Хотя при записи WAVE формата информация сжимается как аппаратными, так и программными средствами, она содержит все необходимые данные о реальном звуковом потоке. А потому файлы с расширением .wav, к сожа лению, довольно громоздки и занимают сотни килобайтов на каждую минуту записи.

Для воспроизведения звуковых файлов вызывается функция PlaySound, кото рая имеет следующий прототип:

BOOL PlaySound(

 

LPCSTR pszSound,

// строка, специфицирующая воспроизводимый звук

HMODULE hmod,

// дескриптор экземпляра приложения

DWORD fdwSound

// флаги воспроизведения

);

 

Первый параметр функции задает либо имя файла на диске, либо строку име ни звукового ресурса. Если при вызове PlaySound первый параметр равен NULL, это вызывает прекращение воспроизведения любого «играемого» файла.

Второй параметр используется только при воспроизведении звука из звуково го ресурса. Если же функция вызвана для воспроизведения звука из файла, то второй параметр устанавливается в NULL.

Третий параметр управляет загрузкой и воспроизведением звука. В табл. 5.2 приведены наиболее часто используемые значения этого параметра.

Таблица 5.2. Значения параметра fdwSound

Ôëàã

Описание

 

 

SND_FILENAME

Параметр pszSound представляет собой имя файла

SND_RESOURCE

Параметр pszSound представляет собой идентификатор ресурса

SND_SYNC

Синхронное воспроизведение звука. Возврат из функции PlaySound

 

происходит только по завершении воспроизведения звука

SND_ASYNC

Асинхронное воспроизведение звука. Возврат из функции PlaySound

 

происходит немедленно после начала воспроизведения звука. Для

 

прекращения асинхронного воспроизведения вызывается функция

 

PlaySound, параметр pszSound которой равен NULL

 

продолжение

266

Глава 5. Ресурсы Windows-приложения

 

Таблица 5.2. (продолжение)

 

 

Ôëàã

Описание

 

 

SND_LOOP

Звук воспроизводится циклически до тех пор, пока не будет вызвана

 

функция PlaySound, параметр pszSound которой равен NULL. Вместе

 

с этим флагом должен быть определен флаг SND_ASYNC

SND_NODEFAULT

Звук по умолчанию не используется. Если указанный звук не найден,

 

PlaySound завершает работу, не воспроизводя при этом звук по умолчанию

SND_PURGE

Если параметр pszSound не равен NULL, то прекращается воспроизведение

 

всех экземпляров указанного звука. Если параметр имеет значение NULL,

 

то прекращается воспроизведение всех звуков вызывающего приложения

SND_NOWAIT

Если драйвер занят, то функция немедленно возвращает управление без

 

воспроизведения звука

 

 

Функция PlaySound содержится в мультимедийной библиотеке Windows. Что бы ее имя и расположение стали известны компоновщику Visual Studio, необхо димо подключить к проекту мультимедийную библиотеку winmm.lib1.

Таким образом, наиболее простой способ озвучить ваше приложение — это выз вать функцию PlaySound в режиме воспроизведения из файла. Конечно, при этом звуковой файл .wav должен находиться в одной папке с исполняемым exe файлом программы. Это не очень удачное решение, если предполагается передавать про грамму сторонним пользователям. Не все специалисты обладают достаточной под готовкой для корректного общения с компьютером. Например, чрезмерно усерд ный пользователь может освобождать пространство на диске, и вдруг — вот сюрприз! — нет больше звукового файла … Именно поэтому как растровые, так

извуковые образы, используемые в программе, рекомендуется хранить в exe файле приложения в виде ресурсов.

Функция PlaySound предоставляет такую возможность — режим воспроизве дения звука из ресурса. Ее использование довольно просто и в этом случае, так как не требует предварительного вызова функций FindResource, LoadResource

иLockResource. Все действия по загрузке и получению доступа к данным ресурса выполняются автоматически самой функцией PlaySound.

Использование функции PlaySound продемонстрируем на примере дальнейшей разработки программы Russia. Мы обещали добавить к программе воспроизведе ние государственного гимна России, и теперь выполним это обещание. В послед ней версии программы, названной RussiaToday, также будут удалены ресурсы кур соров, определенных программистом, и вывод на экран текущей позиции курсора мыши. Эта тема уже пройдена, поэтому код программы можно сделать более про зрачным.

Втексте файла RussiaToday.rc необходимо добавить строку описания звукового ресурса

MY_SOUND

WAVE

DISCARDABLE

"RusHymn.wav"

Необходимо также поместить в папку проекта звуковой файл RusHymn.wav с гимном России2.

1Для Visual Studio 6.0 надо выполнить команду меню Project Settings и найти на вкладке Link тексто вое поле Object/library modules.

2Гимн России можно скачать из Интернета и преобразовать его к формату WAVE либо воспользо ваться файлом RusHymn.wav в составе данного проекта. Исходные тексты к примерам этой книги доступны на сайте издательства «Питер»: www.piter.com.

Воспроизведение звуковых файлов

267

 

 

 

Исходный код основного файла программы приведен в листинге 5.4.

Листинг 5.4. Проект RussiaToday

//////////////////////////////////////////////////////////////////////

// RussiaToday.cpp #include <windows.h> #include <stdio.h> #include "KWnd.h" #include "resource.h"

char szSoundName[] = "MY_SOUND"; // имя звукового ресурса

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //====================================================================

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)

{

MSG msg;

KWnd mainWnd("Russia today", hInstance, nCmdShow, WndProc, NULL, 0, 0, 400, 300);

while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg);

}

return msg.wParam;

}

//==================================================================== LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

HINSTANCE hInst; HICON hIcon, hIconSm; HDC hDC;

PAINTSTRUCT ps;

static HBITMAP hBmpRusFlag; HDC hMemDC;

static BITMAP bm;

switch (uMsg)

{

case WM_CREATE:

hInst = GetModuleHandle(NULL);

hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_TRICOLOUR));

hIconSm = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_TRICOLOUR), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);

SetClassLong(hWnd, GCL_HICON, (LONG)hIcon); SetClassLong(hWnd, GCL_HICONSM, (LONG)hIconSm);

hBmpRusFlag = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_RUSFLAG)); GetObject(hBmpRusFlag, sizeof(bm), (LPSTR)&bm);

// Воспроизведение звука из ресурса

PlaySound (szSoundName, hInst, SND_RESOURCE | SND_ASYNC); break;

case WM_PAINT:

hDC = BeginPaint(hWnd, &ps); hMemDC = CreateCompatibleDC(hDC); SelectObject(hMemDC, hBmpRusFlag);

268

Глава 5. Ресурсы Windows-приложения

 

 

Листинг 5.4. (продолжение)

BitBlt(hDC, 0, 0, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0, SRCCOPY); DeleteDC(hMemDC);

EndPaint(hWnd, &ps); break;

case WM_DESTROY: PostQuitMessage(0); break;

default:

return DefWindowProc(hWnd, uMsg, wParam, lParam);

}

return 0;

}

//////////////////////////////////////////////////////////////////////

Откомпилировав и запустив программу RussiaToday на выполнение, вы увидите почти такое же окно, как на рис. 5.16, только без специализированных курсоров и без отладочного вывода текста, сообщающего о позиции курсора. Но теперь одно временно с появлением окна приложения на экране вы услышите торжественные звуки государственного гимна России!

Если у вас хорошая звуковая карта и качественные колонки, то, несомненно, вам захочется встать и… испытать чувство глубокого удовлетворения от пройден ной темы.

А теперь — бонус! Хотя Win32 API поддерживает только WAVE формат звуко вых файлов, все таки есть способ заставить зазвучать MP3 файлы! Для этого нуж но использовать следующий вызов функции ShellExecute:

ShellExecute(hWnd, "open", "MySound.mp3", NULL, NULL, SW_SHOW);

Выполнение функции ShellExecute с указанными параметрами приводит к вы зову программы, связанной по умолчанию с файлами с расширением .mp3. Ско рее всего, это будет приложение WinAmp, если оно установлено на компьютере, либо приложение Windows Media Player. В любом случае вызванное приложение обеспечит воспроизведение файла MySound.mp3.

Таблицы строк

Ресурс таблицы строк — это список строк, связанных с уникальными численны ми идентификаторами. В файле описания ресурсов таблица строк имеет пример но следующий вид:

STRINGTABLE DISCARDABLE

 

BEGIN

 

IDS_STRING1

"Открыть файл"

IDS_STRING2

"Закрыть файл"

IDS_STRING3

"Выход из программы"

 

END

 

Это так называемое многострочное описание ресурса. Многострочное описа ние используется также для ресурсов меню и диалоговых окон.

Необходимость или полезность использования ресурса таблицы строк для на чинающих Windows программистов не вполне очевидна. Казалось бы, использо

Таблицы строк

269

 

 

 

вание обычных символьных строк, объявленных в виде переменных или констант в исходном тексте программы, не приносит никаких проблем. Зачем еще допол нительные строковые ресурсы? Тем не менее, в двух ситуациях использование ресурса таблицы строк дает ощутимые преимущества:

при модификации программы с целью адаптации для иноязычного пользова теля;

при использовании строковых ресурсов для вывода текста в окнах подсказок (tooltip) или в строке состояния (status bar) приложения.

Ресурс таблицы строк значительно облегчает перевод программы на другие языки. Если вместо непосредственного использования символьных строк в ис ходном тексте программы вынести их в файл описания ресурсов, а затем извле кать строки по их идентификаторам, то вся текстовая информация окажется со средоточенной в одном месте. Поэтому в случае разработки иноязычной версии сделанной ранее программы достаточно перевести текст в файле описания ресур сов и перекомпилировать программу.

Вторая сфера рекомендуемого использования ресурса таблицы строк связана с упрощением вывода подсказок в элементе управления Tooltip или в строке со стояния приложения. Эти вопросы будут рассмотрены в главе 8.

Для добавления к приложению ресурса символьных строк при помощи редак тора ресурсов выполните следующую последовательность действий:

1.В главном меню Visual Studio выполните команду меню Insert Resource. В по явившемся диалоговом окне Insert Resource укажите тип ресурса String Table и нажмите кнопку New. В результате будет отображено окно редактора табли цы строк, показанное на рис. 5.17.

Рис. 5.17. Окно редактора таблицы строк

2.Сделайте двойной щелчок мышью на первой пустой строке в таблице. Появится диалоговое окно String Properties, показанное на рис. 5.18.

Рис. 5.18. Диалоговое окно для ввода строки

Введите нужный идентификатор в текстовом поле ID и символьную строку в окне Caption. Закройте диалоговое окно.

270

Глава 5. Ресурсы Windows-приложения

 

 

3.Повторите действия, описанные в п. 2, для каждой строки, которую необходи мо внести в ресурс.

4.Сохраните ресурс с помощью команды меню File Save.

Всоставе ресурсов приложения может быть только одна таблица строк. Мак симальный размер каждой строки составляет 255 символов. В строке не может быть управляющих символов языка C, за исключением символа табуляции \t. Однако символьные строки могут содержать восьмеричные константы \011 (та буляция), \012 (перевод строки) и \015 (возврат каретки). Эти управляющие сим волы распознаются функциями DrawText и MessageBox.

Вы можете использовать функцию LoadString для копирования строки из ре сурса в символьный буфер szBuffer:

LoadString(hInstance, id, szBuffer, iMaxLength);

Параметр id соответствует идентификатору строки в файле описания ресурсов, а в параметре iMaxLength указывается максимальное число копируемых символов.

Давайте рассмотрим пример программы, в которой для вывода на экран трех сообщений о статусе некоторого файла используется ресурс таблицы строк.

Создайте проект с именем StringTable и добавьте к нему ресурс таблицы строк по описанной выше процедуре. Введите в таблицу три строки:

Идентификатор

Строка

 

 

IDS_FILENOTFOUND

Файл %s не найден

IDS_FILETOOBIG

Файл %s слишком велик для редактирования

IDS_FILEREADONLY

Файл %s доступен только для чтения

После сохранения этой информации в файле описания ресурсов StringTable.rc вы можете открыть его в текстовом режиме и увидеть следующее описание табли цы строк:

STRINGTABLE DISCARDABLE

 

BEGIN

 

IDS_FILENOTFOUND

"Файл %s не найден."

IDS_FILETOOBIG

"Файл %s слишком велик для редактирования."

IDS_FILEREADONLY

"Файл %s доступен только для чтения."

END

 

Теперь добавьте к проекту файлы KWnd.h, KWnd.cpp и StringTable.cpp. Файл StringTable.cpp должен содержать текст, приведенный в листинге 5.5.

Листинг 5.5. Проект StringTable

//////////////////////////////////////////////////////////////////////

// StringTable.cpp #include <windows.h> #include <stdio.h> #include "KWnd.h" #include "resource.h"

char szAppName[] = "StringTable";

int StatusFileMsg(HWND hwnd, int status, char* fileName); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

//==================================================================== int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpCmdLine, int nCmdShow)