лекции / Shchupak_Yu._Win32_API_Razrabotka_prilozheniy_dlya_Windows
.pdfРастры |
201 |
|
|
|
|
DIB секцией (DIB section) называется DIB растр, который позволяет произво дить непосредственное чтение и запись как со стороны приложения, так и со сторо ны GDI. Массив пикселов DIB секции хранится либо в виртуальной памяти при ложения, либо в файле, отображаемом на память, который в среде разработчиков операционной системы Windows называется секцией. Этим, видимо, объясняется происхождение термина «DIB секция».
DIB секция, как и аппаратно зависимый растр, является объектом GDI. Пос ле ее создания GDI возвращает дескриптор DIB секции, относящийся к типу HBITMAP. Завершив работу с DIB секцией, приложение должно вызвать функцию DeleteObject, чтобы освободить связанные с нею ресурсы.
Создание DIB-секции
Для создания DIB секции используется функция CreateDIBSection:
HBITMAP CreateDIBSection(
HDC hdc, |
// дескриптор контекста устройства |
|
CONST BITMAPINFO* pbmi, // |
адрес заголовка информационного блока |
|
UINT iUsage, |
// тип данных в цветовой таблице |
|
VOID** ppvBits, |
// |
адрес массива пикселов |
HANDLE hSection, // дескриптор объекта файла, отображаемого на память DWORD dwOffset // смещение массива пикселов внутри отображаемого файла
);
Основные характеристики создаваемого растра задаются в структуре типа BITMAPINFO, адрес которой передается второму параметру функции. В этой струк туре необходимо указать ширину, высоту, цветовую глубину и тип сжатия. DIB секции поддерживают только тип BI_RGB, то есть только несжатые растры. Также задаются битовые маски, если они нужны, и цветовая таблица, если она исполь зуется.
Параметр iUsage определяет тип данных, содержащихся в массиве bmiColors, ко торый является членом структуры BITMAPINFO. Если параметр iUsage имеет значе ние DIB_PAL_COLORS, то цветовая таблица bmiColors содержит индексы логической палитры. Значение DIB_RGB_COLORS указывает, что цветовая таблица содержит зна чения в формате RGB.
Параметр ppvBits содержит адрес переменной указателя, в который GDI зано сит адрес массива пикселов DIB секции.
Параметр hSection может быть равен NULL. В этом случае GDI выделяет память под массив пикселов из виртуальной памяти приложения, а параметр dwOffsetигно рируется. Если параметр hSection не равен NULL, то он должен быть дескриптором объекта файла, отображаемого на память, который был создан вызовом функции
CreateFileMapping с флагами PAGE_READWRITE или PAGE_WRITECOPY. В этом случае раз мещение массива пикселов осуществляется в указанном файле со смещением, оп ределяемым параметром dwOffset.
Прямой доступ к пикселам со стороны приложения
Прямой доступ к пикселам со стороны приложения реализуется точно так же, как и при работе с DIB растром (см. класс KDib в листинге 3.5).
Применительно к DIB секциям аналогичный доступ реализован в классе KDibSection, определение которого будет дано в главе 12, когда он будет приме няться для решения проблемы рисования в реальном времени (см. листинг 12.4).
202 |
Глава 3. GDI. Палитры, растры, метафайлы |
|
|
Отображение DIB-секции
Для вывода DIB секции на поверхность графического устройства можно исполь зовать два подхода:
вывод как DIB растра при помощи функции StretchDIBits или SetDIBitsToDevice;
вывод как растрового объекта GDI, заданного дескриптором hBitmap, с исполь зованием совместимого контекста устройства и функции BitBlt или StretchBlt.
Пример использования DIB секций приведен в приложении ArincReceiver (гла ва 12, листинг 12.4).
Тернарные растровые операции
Последний параметр, dwRop, в функциях BitBlt, PatBlt и StretchBlt задает растровую операцию, которая указывает для GDI, как должны комбинироваться биты ис ходного изображения с битами изображения приемника и с битами шаблона те кущей кисти. Результат операции определяет новое состояние изображения при емника. Поскольку число операндов равно трем, то операция относится к классу тернарных операций.
В Win32 API существует 256 ROP кодов (raster operation codes). Растровые операции кодируются 32 разрядными двойными словами DWORD. В старшем слове хранится один из 256 однобайтных кодов растровой операции, а младшее слово содержит кодировку формулы, по которой растровая операция реализуется драй вером графического устройства.
Разработчики Microsoft присвоили символические имена только пятнад цати тернарным растровым операциям из 256. Видимо, это как раз те операции, которые использует операционная система. Указанные операции приведены в табл. 3.9, при этом использована следующая система обозначений: P — шаблон кисти (pattern), S — источник (source), D — приемник (destination).
Таблица 3.9. Тернарные растровые операции
Pattern: |
1 1 1 1 0 0 0 0 |
Формула |
ROP-êîä |
Èìÿ |
Source: |
1 1 0 0 1 1 0 0 |
|
|
|
Destination: |
1 0 1 0 1 0 1 0 |
|
|
|
|
|
|
|
|
Результат: |
0 0 0 0 0 0 0 0 |
D = 0 |
0x00000042 |
BLACKNESS |
|
0 0 0 1 0 0 0 1 |
D = ~(S | D) |
0x001100A6 |
NOTSRCERASE |
|
0 0 1 1 0 0 1 1 |
D = ~S |
0x00330008 |
NOTSRCCOPY |
|
0 1 0 0 0 1 0 0 |
D = S & ~D |
0x00440328 |
SRCERASE |
|
0 1 0 1 0 1 0 1 |
D = ~D |
0x00550009 |
DSTINVERT |
|
0 1 0 1 1 0 1 0 |
D = P ^ D |
0x005A0049 |
PATINVERT |
|
0 1 1 0 0 1 1 0 |
D = S ^ D |
0x00660046 |
SRCINVERT |
|
1 0 0 0 1 0 0 0 |
D = S & D |
0x008800C6 |
SRCAND |
|
1 0 1 1 1 0 1 1 |
D = ~S | D |
0x00BB0226 |
MERGEPAINT |
|
1 1 0 0 0 0 0 0 |
D = P & S |
0x00C000CA |
MERGECOPY |
|
1 1 0 0 1 1 0 0 |
D = S |
0x00CC0020 |
SRCCOPY |
|
1 1 1 0 1 1 1 0 |
D = S | D |
0x00EE0086 |
SRCPAINT |
|
1 1 1 1 0 0 0 0 |
D = P |
0x00F00021 |
PATCOPY |
|
1 1 1 1 1 0 1 1 |
D = P | ~S | D |
0x00FB0A09 |
PATPAINT |
|
1 1 1 1 1 1 1 1 |
D = 1 |
0x00FF0062 |
WHITENESS |
|
|
|
|
|
Растры |
203 |
|
|
|
|
Полную таблицу тернарных растровых операций можно найти в MSDN (Platform SDK Windows GDI Ternary Raster Operations).
Следует обратить внимание на восьмиразрядные двоичные коды, являющие ся результатом каждой операции. Двузначное шестнадцатеричное число, соответ ствующее этим битам, есть старшее слово ROP кода.
При внимательном взгляде на табл. 3.9 можно заметить, что не все растровые операции зависят от всех трех операндов. Поэтому можно рассматривать отдель ные подгруппы этих операций.
Инициализирующие растровые операции
Операции BLACKNESS и WHITENESS не зависят ни от шаблона кисти, ни от источника, ни от приемника. Они обычно используются для инициализации или возврата гра фической поверхности в исходное состояние. Черный (Black) и белый (White) цвета отличаются от других тем, что все разряды для них установлены либо в 0, либо в 1. Благодаря этому для любого произвольного цвета C справедливы следую щие утверждения:
Black AND C = Black
Black OR C = C
Black XOR C = C
White AND C = C
White OR C = White
White XOR C = NOT C
Указанные свойства могут использоваться для достижения различных эффек тов при выводе растров.
Операции, зависящие только от источника
К таким операциям относятся SRCCOPY и NOTSRCCOPY.
Операция SRCCOPY уже использовалась ранее в примерах. Она просто копирует пикселы источника в приемник. Обычно эта операция применяется для отображе ния растра в исходном цвете.
Операция NOTSRCCOPY копирует в приемник цвет, противоположный цвету ис точника.
Операция, зависящая только от приемника
Операция DSTINVERT меняет цвет пиксела приемника на противоположный.
Операции, не зависящие от источника
В табл. 3.9 к таким операциям относятся PATINVERTи PATCOPY. Всего существует 16 ра стровых операций, не зависящих от источника, но не все они имеют символические имена. В GDI предусмотрена специальная функция для выполнения растровых опе раций, не зависящих от источника:
BOOL PatBlt(HDC hdc, int nXLeft, int nYLeft, int nWidth, int nHeight,
DWORD dwRop);
Функция PatBlt комбинирует текущую кисть с прямоугольным регионом прием ника. Вы можете использовать любые коды ROP из полной таблицы операций1, в ко торых не задействован источник, а не только те, которые приведены в табл. 3.9.
1 См. выше ссылку на MSDN.
204 |
Глава 3. GDI. Палитры, растры, метафайлы |
|
|
Операции, не зависящие от шаблона кисти
К таким операциям относятся NOTSRCERASE, SRCERASE, SRCINVERT, SRCAND, MERGEPAINT
и SRCPAINT. Следует отметить, что операции SRCINVERT и SRCAND используются систе мой Windows для отображения пиктограмм и курсоров мыши.
Рассмотрим, например, механизм отображения пиктограмм, которым пользу ется Windows. Ресурсы предопределенных пиктограмм хранятся в динамически загружаемой библиотеке Shell32.dll1. Доступ к библиотеке можно получить, за грузив ее в приложение при помощи функции LoadLibrary, которая возвращает дес криптор экземпляра модуля (hShell32), содержащего соответствующие растровые изображения. Затем, используя индекс пиктограммы, можно загрузить любую пик тограмму из модуля hShell32. Для этого достаточно вызвать функцию LoadImage. Например, если передать функции LoadImage индекс 12, то будет загружена пиктог рамма, обозначающая привод CD ROM.
Функция LoadImage в случае успешного завершения возвращает дескриптор пиктограммы hIcon. Затем при помощи вызова
GetIconInfo(hIcon, &iconInfo);
можно получить информацию о загруженной пиктограмме, сохранив ее в пере менной iconInfo типа ICONINFO. Для нас в этой структуре интересны два поля:
HBITMAP hbmMask;
HBITMAP hbmColor;
Первое из этих полей содержит дескриптор растра, представляющего собой маску пиктограммы, второе поле — дескриптор растра, представляющего собой изображение пиктограммы. На рис. 3.9 показаны маска и изображение для пик тограммы «привод CD ROM».
Рис. 3.9. Пара растров для вывода пиктограммы «привод CD-ROM»
Оба растра имеют размеры 48 × 48. Но для чего нужны эти два растра? Дело в том, что при выводе пиктограммы в виде прямоугольной области некоторые пик селы этой области должны изменяться, а некоторые должны остаться прежними. Изменяемая область называется непрозрачной, и в маске ей соответствует черный цвет. Остальные пикселы образуют прозрачную область — в маске ей соответству ет белый цвет.
Приложение, код которого приведен в листинге 3.8, демонстрирует, как можно отобразить пиктограмму с учетом ее прозрачной области.
Листинг 3.8. Проект DrawIconWithRop
//////////////////////////////////////////////////////////////////////
// DrawIconWithRop.cpp #include <windows.h>
1 Вопросы создания и применения пользовательских пиктограмм рассматриваются в главе 5.
Растры |
205 |
|
|
|
|
#include "KWnd.h"
#define ICON_ID 12
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //==================================================================== int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
KWnd mainWnd("Draw icon with ROP", hInstance, nCmdShow, WndProc); while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
//==================================================================== LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HDC hDC; PAINTSTRUCT ps;
static HINSTANCE hShell32; ICONINFO iconInfo;
BITMAP bmp; HICON hIcon; HDC hMemDC;
int x = 20, y = 20;
switch (uMsg)
{
case WM_CREATE:
hShell32 = LoadLibrary("Shell32.dll");
SetClassLong(hWnd, GCL_HBRBACKGROUND, (LONG)CreateSolidBrush (RGB(180,140,200)));
break;
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps); hMemDC = CreateCompatibleDC(hDC);
hIcon = (HICON)LoadImage(hShell32, MAKEINTRESOURCE(ICON_ID), IMAGE_ICON, 48, 48, LR_DEFAULTCOLOR);
if (!hIcon) {
MessageBox(hWnd, "Ошибка загрузки пиктограммы", "Error", MB_OK); break;
}
GetIconInfo(hIcon, &iconInfo); GetObject(iconInfo.hbmMask, sizeof(bmp), &bmp);
// Маска
SelectObject(hMemDC, iconInfo.hbmMask);
BitBlt(hDC, x, y, bmp.bmWidth, bmp.bmHeight, hMemDC, 0, 0, SRCCOPY); // Изображение
продолжение
206 |
Глава 3. GDI. Палитры, растры, метафайлы |
|
|
Листинг 3.8 (продолжение) |
|
SelectObject(hMemDC, |
iconInfo.hbmColor); |
BitBlt(hDC, x+60, y, bmp.bmWidth, bmp.bmHeight, hMemDC, 0, 0,
SRCCOPY);
//Вывод пиктограммы наложением маски и рисунка SelectObject(hMemDC, iconInfo.hbmMask);
BitBlt(hDC, x+120, y, bmp.bmWidth, bmp.bmHeight, hMemDC, 0, 0, SRCAND);
SelectObject(hMemDC, iconInfo.hbmColor);
BitBlt(hDC, x+120, y, bmp.bmWidth, bmp.bmHeight, hMemDC, 0, 0, SRCINVERT);
//Вывод пиктограммы функцией DrawIcon
DrawIcon(hDC, x+188, y, hIcon); DeleteObject(hMemDC); DestroyIcon(hIcon); EndPaint(hWnd, &ps);
break;
case WM_DESTROY: PostQuitMessage(0); break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
//////////////////////////////////////////////////////////////////////
Для отображения пиктограммы сначала при помощи функции BitBlt с растровой операцией SRCAND выводится маска. При этом непрозрачная область устанавлива ется в черный цвет, а прозрачная остается без изменения. Затем в этой же позиции выводится цветной растр изображения, для чего используется вызов BitBlt с рас тровой операцией SRCINVERT.
Результат работы программы показан на рис. 3.10. В клиентскую область прило жения последовательно выводятся: маска (а), цветной растр (б), пиктограмма (в), образованная наложением цветного растра на маску, и пиктограмма (г), нарисован ная функцией DrawIcon, которая масштабирует значок по его стандартным разме рам 32 × 32 пиксела.
Рис. 3.10. Вывод программы DrawIconWithRop
Метафайлы
Метафайл — это протокол обращений к функциям GDI, сохраненный в двоич ном формате. Метафайлы имеют такое же значение для векторной графики, как и битовые образы для растровой графики. Метафайл состоит из набора записей,
Метафайлы |
207 |
|
|
|
|
соответствующих вызовам графических функций, таких как создание и выбор
вконтекст устройства пера или кисти, рисование линий, фигур, вывод текста, и иных операций.
При воспроизведении метафайлов достигается такой же результат, как и при непосредственном использовании функций GDI. Разница между их воспроизве дением и непосредственным вызовом функций состоит в том, что метафайлы мо гут храниться в памяти или в файлах на диске, загружаться и воспроизводиться приложением столько раз, сколько это нужно.
Метафайлы используются для передачи изображений между программами через буфер обмена, а также для сохранения изображений в виде файлов на дис ке. Для их хранения требуется значительно меньше места, чем для хранения рас тровых изображений. В то же время для отображения метафайлов требуется обыч но больше времени, чем для вывода растровых изображений.
Поскольку метафайл описывает изображение в терминах команд графическо го вывода, то изображение может быть масштабировано при воспроизведении без потери разрешения. Для битовых образов масштабирование всегда связано с по терей качества изображения.
Первоначальный 16 битный формат метафайлов WMF1 появился в Windows 2.0. Однако этот формат был аппаратно зависимым и не содержал информацию о раз мерах изображения, поэтому его использование было связано со многими про блемами. В Win32 появился новый 32 битный формат EMF (Enhanced Metafile Format). Расширенные метафайлы содержат дополнительную информацию о раз мерах изображения и цветовой палитре, что обеспечивает их аппаратную незави симость. Кроме того, они поддерживают все 32 битные функции рисования. Win32 API позволяет использовать файлы форматов WMF и EMF.
Поскольку в новых приложениях рекомендуется использовать формат EMF, то
вдальнейшем будут рассматриваться только расширенные метафайлы.
Создание метафайла
Расширенный метафайл является таким же объектом GDI, как, например, объект кисти или объект DIB секции. Объект расширенного метафайла однозначно оп ределяется своим дескриптором типа HENHMETAFILE. Создание метафайла и запись в него команд GDI связаны с использованием метафайлового контекста устройства, который рассматривался во второй главе.
Метафайловый контекст устройства создается функцией CreateEnhMetaFile:
HDC CreateEnhMetaFile(HDC hdcRef, LPCTSTR lpFilename, CONST RECT* lpRect, LPCTSTR lpDescription);
Первый параметр, hdcRef, указывает на эталонный контекст устройства, данные которого будут использованы при записи EMF. Если этот параметр имеет значение NULL, то GDI принимает в качестве эталона текущий экран.
Во втором параметре, lpFilename, может передаваться имя файла на диске или значение NULL. Если передается NULL, то метафайл создается в памяти. Если переда ется имя файла, то после удаления объекта метафайла функцией DeleteEnhMetaFile файловый вариант сохраняется на диске.
1 WMF — Windows Metafile Format.
208 |
Глава 3. GDI. Палитры, растры, метафайлы |
|
|
Третий параметр, lpRect, определяет позицию и размеры сохраняемого изобра жения в единицах 0,01 мм. Если параметр имеет значение NULL, то GDI вычисляет ограничивающий прямоугольник по всем командам вывода.
Последний параметр, lpDescription, содержит необязательное текстовое описа ние, сохраняемое в метафайле. Обычно описание содержит имя приложения и имя документа, разделенные нулевым символом. Это описание должно завер шаться двумя нулевыми символами.
Функция CreateEnhMetaFile возвращает дескриптор метафайлового контекста устройства. Этот дескриптор передается затем всем графическим функциям GDI для записи «протокола рисования» в метафайл.
Когда рисование завершено, необходимо вызвать функцию CloseEnhMetaFile, ко торая закрывает метафайловый контекст и возвращает дескриптор расширенного метафайла. Этот дескриптор может быть использован для воспроизведения мета файла.
Как говорилось выше, если имя файла было задано при вызове функции CreateEnhMetaFile, то сохранение файла на диске происходит после вызова функции DeleteEnhMetaFile, которая удаляет объект метафайла из памяти приложения.
Технология создания метафайла иллюстрируется приложением, код которого приведен в листинге 3.9. В программе CreateMetaFileимитируется типичная ситуация для графических редакторов, работающих с векторной графикой, когда рисование в клиентской области окна дублируется рисованием в метафайле, который затем сохраняется на диске.
Листинг 3.9. Проект CreateMetaFile
//////////////////////////////////////////////////////////////////////
// CreateMetaFile.cpp
#include <windows.h> #include "KWnd.h"
#define FILE_NAME "Pict1.emf"
void DrawSomething(HDC);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //==================================================================== int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
KWnd mainWnd("CreateMetaFile", hInstance, nCmdShow, WndProc); while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
//==================================================================== LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HDC hDC; PAINTSTRUCT ps; RECT rect;
Метафайлы |
209 |
|
|
|
|
|
static |
HDC hdcEMF; |
HENHMETAFILE hemf;
switch (uMsg)
{
case WM_CREATE:
hdcEMF = CreateEnhMetaFile(NULL, FILE_NAME, NULL, "CreateMetaFile\0Pict1\0");
break;
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
DrawSomething(hDC);
DrawSomething(hdcEMF);
EndPaint(hWnd, &ps); break;
case WM_DESTROY:
hemf = CloseEnhMetaFile(hdcEMF); DeleteEnhMetaFile(hemf); PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
//////////////////////////////////////////////////////////////////////
void DrawSomething(HDC hdc) {
RECT r;
HPEN hPen, hOldPen;
HBRUSH hBrush, hOldBrush;
SetRect(&r, 20, 20, 220, 220);
hPen = CreatePen(PS_SOLID, 10, RGB(255, 160, 140)); hOldPen = (HPEN)SelectObject(hdc, hPen);
hBrush = CreateSolidBrush(RGB(140, 160, 255)); hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); Rectangle(hdc, r.left, r.top, r.right, r.bottom);
hPen = CreatePen(PS_SOLID, 3, RGB(0, 255, 0)); SelectObject(hdc, hPen);
hBrush = CreateSolidBrush(RGB(100, 100, 100)); SelectObject(hdc, hBrush);
InflateRect(&r, -40, -40);
Ellipse(hdc, r.left, r.top, r.right, r.bottom); SetTextColor(hdc, RGB(255, 255, 255)); SetBkMode(hdc, TRANSPARENT);
DrawText(hdc, "YES !", -1, &r, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
DeleteObject(SelectObject(hdc, hOldPen)); DeleteObject(SelectObject(hdc, hOldBrush));
}
//////////////////////////////////////////////////////////////////////
210 |
Глава 3. GDI. Палитры, растры, метафайлы |
|
|
Метафайловый контекст устройства создается в блоке обработки сообщения WM_CREATE. Его дескриптор hdcEMF объявлен со спецификатором static, так как ис пользование объекта метафайла происходит позже, при обработке других сообще ний.
В приложении определена функция DrawSomething, которая рисует некоторое изображение в контексте устройства hdc, передаваемом ей в качестве параметра. Изображение может быть произвольным, но в данном случае отображается квад рат размером 200 × 200 пикселов, внутри квадрата рисуется круг, а уже внутри круга выводится текст.
При обработке сообщения WM_PAINT функция DrawSomething вызывается дваж ды: сначала с контекстом дисплея, затем с метафайловым контекстом.
При обработке сообщения WM_DESTROY вызываются следующие функции:
hemf = CloseEnhMetaFile(hdcEMF); DeleteEnhMetaFile(hemf);
Именно благодаря им созданный метафайл сохраняется на диске. Откомпилируйте и запустите приложение. В окне программы должно появить
ся изображение, показанное на рис. 3.11. Если ваш дисплей работает в режиме True Color, то рамка, ограничивающая квадрат, будет нежно кремового цвета, внут ренняя область квадрата — светлого серо голубого цвета, окружность, ограничи вающая круг, — светло зеленого цвета, а сам круг — темно серого цвета.
Рис. 3.11. Вывод программы CreateMetaFile
Завершите работу с программой, щелкнув мышью на кнопке закрытия окна. Теперь посмотрите на содержимое папки с вашим проектом. В ней должен по явиться файл Pict1.emf. Это и есть созданный программой метафайл. Он может быть просмотрен с помощью любого графического редактора, поддерживающего формат EMF, например, при помощи приложения ACDSee.
Воспроизведение метафайла
Расширенный метафайл воспроизводится функцией PlayEnhMetaFile, которая име ет следующий прототип:
BOOL PlayEnhMetaFile(HDC hdc, HENHMETAFILE hemf, CONST RECT* lpRect);
Первый параметр, hdc, задает дескриптор приемного контекста устройства. Вто рой параметр содержит дескриптор расширенного метафайла. Третий параметр определяет ссылку на ограничивающий прямоугольник изображения в логичес ких координатах контекста hdc.
