red_brick BITMAP rbrick.bmp
1 BITMAP firm.bmp
Считается, что лучше использовать уникальные номера ресурсов, а не имена, так как это обеспечивает более быстрый поиск ресурса в приложении и требует меньше памяти для описания ресурсов приложения.
Для загрузки битмапа из ресурсов приложения используются функции:
HBITMAP LoadBitmap (hInstance, lpszName);
HANDLE LoadImage (hInstance, lpszName, uType, cxDesired, cyDesired, fuLoad); 1
где hInstance — хендл копии приложения, содержащего данный битмап, а lpszName — имя ресурса битмапа. Имя ресурса может быть либо текстом — тогда lpszName это обычная строка, оканчивающаяся символом ‘\0’, либо номером — тогда вместо lpszName может стоять или «#number», или MAKEINTRESOURCE (number). Например, для загрузки битмапов «red_brick» и «1» можно воспользоваться такими вызовами функций:
HBITMAP hbmpRedBrick = LoadBitmap (hInstance, "red_brick");
HBITMAP hbmp1a = LoadBitmap (hInstance, "#1");
HBITMAP hbmp1b = LoadBitmap (hInstance, MAKEINTRESOURCE (1));
Причем последний вариант является самым быстрым и компактным.
Функция LoadImage осуществляет загрузку битмапов, пиктограмм и курсоров. Теоретически она позволяет загружать требуемый ресурс из файла (для этого в fuLoad надо установить флаг LR_LOADFROMFILE и указать hInstance равным NULL). Однако такая операция поддерживается только в случае Windows–95, WindowsNT 4.0 и более поздних. Предыдущие реализации Win32 API не поддерживают загрузку изображений из файлов.
Вы можете использовать стандартные битмапы, предоставляемые Windows. Их символические имена начинаются на OBM_... . Для того, что бы вы могли воспользоваться этими идентификаторами, необходимо перед директивой #include <windows.h> определить символ OEMRESOURCE, то есть:
#define OEMRESOURCE
#include <windows.h>
В таблице приведены изображения стандартных битмапов и их идентификаторы, в соответствии с их реализацией в Windows 3.x (Windows API) и Windows NT 3.x (Win32 API); в более поздних версиях (как, например, Windows–95, Windows NT 4.0) внешний вид стандартных битмапов несколько изменен. В таблице заполнены не все клетки просто из соображений построчной группировки схожих битмапов.
OBM_UPARROW | OBM_UPARROWI | OBM_UPARROWD | OBM_OLD_UPARROW | ||||
OBM_DNARROW | OBM_DNARROWI | OBM_DNARROWD | OBM_OLD_DNARROW | ||||
OBM_RGARROW | OBM_RGARROWI | OBM_RGARROWD | OBM_OLD_RGARROW | ||||
OBM_LFARROW | OBM_LFARROWI | OBM_LFARROWD | OBM_OLD_LFARROW | ||||
OBM_REDUCE | OBM_REDUCED | OBM_OLD_REDUCE | |||||
OBM_ZOOM | OBM_ZOOMD | OBM_OLD_ZOOM | |||||
OBM_RESTORE | OBM_RESTORED | OBM_OLD_RESTORE | |||||
OBM_CLOSE | OBM_OLD_CLOSE | ||||||
OBM_MNARROW | OBM_COMBO | OBM_SIZE | OBM_BTSIZE | ||||
OBM_CHECK | OBM_BTNCORNERS | OBM_CHECKBOX |
Работа с зависимым от устройства битмапом
Небольшое замечание: так как битмап является объектом GDI, то вы обязаны удалить его, как только он станет ненужным. Это относится ко всем битмапам, как созданным с помощью функций CreateBitmap, CreateBitmapIndirect, CreateCompatibleBitmap, CreateDiscardableBitmap, так и к загруженным с помощью функции LoadBitmap. Освобождение неиспользуемых битмапов особенно важно, так как это едва–ли не самые большие объекты GDI, занимающие значительные ресурсы.
В GDI практически не содержится функций, использующих зависимые от устройства битмапы непосредственно. Исключение, разве что, функции для создания кисти по образцу, для задания графического образа пункта меню или для передачи изображения в независимый от устройства битмап (подробнее см. в соответствующих разделах):
HBRUSH hbrBrush = CreatePatternBrush (hBmp);
DeleteBitmap (hBmp); // 2
После того, как мы создали кисть, битмап можно удалять, так как его образ скопирован в кисть и больше не используется. Если битмап больше, чем 8x8 пикселей, то для создания кисти будет использован его верхний–левый уголок, размером 8x8.
Все остальные операции по работе с битмапами осуществляются посредством специально создаваемого контекста устройства, ассоциированного с этим битмапом. Для этого был разработан специальный вид контекстов устройства — совместимый контекст (compatible device context, compatible DC, чаще называемый memory device context, memory DC). Такой разнобой в названиях контекста связан, с одной стороны, с названием функции, его создающей — CreateCompatibleDC — создающей контекст устройства, совместимого с другим, реально существующим устройством (см. раздел «Получение хендла контекста устройства»). А, с другой стороны, созданный таким образом контекст устройства не соответствует никакому физическому устройству, его область отображения — некоторое растровое изображение, хранимое в памяти. Отсюда второе название — memory DC.
Совместимость контекста не значит, что его цветовая организация совпадает с организацией реально существующего контекста, а только лишь то, что принципы выполнения операций над этим контекстом будут такими же, как для реального устройства — например, при выводе на совместимый контекст может применяться графический акселератор, если для контекста реального устройства, указанного в качестве прототипа при создании совместимого, такой акселератор используется (конечно, это зависит еще и от возможностей самого акселератора).
Только что созданный совместимый контекст устройства имеет монохромную область отображения размером 1 пиксель. Так как нарисовать что–нибудь осмысленное в такой области нереально, вы должны принять меры к тому, что бы область отображения этого контекста была ассоциирована с хранимым в памяти растровым изображением — зависимым от устройства битмапом. Это делается тривиально — битмап выбирается в совместимый контекст устройства с помощью обычной функции SelectObject. После этого область отображения совместимого контекста будет совпадать с указанным битмапом — как по размерам, так и по цветовой организации.
Внимание!GDI предполагает, что битмап может быть выбран только в совместимый контекст устройства. Если его выбрать в какой–либо контекст реально существующего устройства, то скорее всего такая попытка будет просто проигнорирована, хотя в зависимости от платформы и используемых драйверов устройств, реакция системы может быть и иной.
Общая схема при этом выглядит следующим способом:
HDC hCompatDC;
HBITMAP hBmp;
hCompatDC = CreateCompatibleDC (hDC);
// функция CreateCompatibleDC () создает совместимый
// контекст устройства, соответствующий одному монохромному пикселу
hBmp = LoadBitmap (hInstance, lpszName);
// для получения хендла битмапа мы могли воспользоваться любым
// способом - его загрузкой из ресурсов или созданием
SelectObject (hCompatDC, hBmp);
// теперь совместимый контекст устройства соответствует нашему битмапу.
// ... здесь мы можем выполнять любые операции по рисованию на нашем битмапе
// ... или передавать изображения между разными контекстами устройств.
DeleteDC (hCompatDC);
// после того, как мы выполнили все нужные операции над контекстом
// устройства, мы можем его удалить.
// ... При этом битмап как объект GDI остается и мы можем свободно
// ... применять его хендл. Например, для создания кисти, или для
// ... отображения пункта меню.
DeleteObject (hBmp);
// после того, как битмап стал нам не нужен, мы можем его уничтожить
Очень часто встречается частный случай этой схемы: при создании нового изображения битмап делается совместимым по цветовой организации с тем устройством, на котором он будет отображаться. В этом случае создание битмапа выглядит так: