Device context windows что это
Чтобы дать возможность прикладным программам помещать вывод данных в память, а не отправлять их на реальное устройство (диск), используется специальный контекст устройства для операций с точечным рисунком, называемый контекст устройства в памяти (memory device context) . Контекст устройства (DC) в памяти дает возможность системе рассматривать часть памяти как виртуальное устройство. Это — массив битов в памяти, который приложение временно может использовать, чтобы сохранить данные о цвете для точечных рисунков, созданных на обычной поверхности для рисования . Поскольку точечный рисунок совместим с устройством, контекст устройства (DC) в памяти также иногда относится к совместимому контексту устройства (compatible device context) .
Контекст устройства (DC) в памяти сохраняет образы точечных рисунков для конкретного устройства. Приложение может создать контекст устройства в памяти при помощи вызова функции CreateCompatibleDC.
Исходный точечный рисунок в контексте устройства (DC) в памяти — просто символ — заместитель. Его размеры — цепь один пиксель за другим пикселем. Прежде, чем приложение может начать рисовать, оно должно выбрать точечный рисунок с соответствующей шириной и высотой в DC при помощи вызова функции SelectObject. Чтобы создать точечный рисунок соответствующих размеров, используйте функцию CreateBitmap, CreateBitmapIndirect или CreateCompatibleBitmap. После того, как точечный рисунок выбран в контексте устройства (DC) в памяти, система заменяет одноразрядный массив на массив, достаточно большой, чтобы сохранить информацию о цвете для заданного прямоугольника пикселей.
Когда приложение передает дескриптор, возвращенный CreateCompatibleDC одной из функций рисования, требуемый вывод данных не появляется на поверхности рисования устройства. Вместо этого, система сохраняет информацию о цвете для получающейся в результате линии, кривой, текста или региона (области) в массиве битов. Приложение может копировать образ, сохраненный в памяти обратно на поверхность рисования при помощи вызова функции BitBlt, идентифицируя контекст устройства (DC) в памяти, как исходный контекст устройства, а окно или контекст устройства (DC) экрана, как целевой контекст устройства.
При отображении на экране аппратно-независимого (DIB) или аппратно-зависимого точечного рисунка (DDB), созданного из DIB палитрой устройства , Вы можете улучшить быстродействие, в котором образ рисуется, выстраивая логическую палитру, которая соответствует макету системной палитры. Чтобы сделать это, вызовите функцию GetDeviceCaps со значением NUMRESERVED , чтобы получить число зарезервированных цветов в системе. Затем вызовите функцию GetSystemPaletteEntries и заполните первые и последние NUMRESERVED /2 записи логической палитры соответствующими цветами системы. Например, если NUMRESERVED — 20, Вы должны заполнить первые и последние 10 записей логической палитры системными цветами. Затем заполнить оставшиеся 256- NUMRESERVED цвета логической палитры (в нашем примере, оставшиеся 236 цветов) цветами из DIB и установить флажок PC_NOCOLLAPSE на каждом из этих цветов.
Для получения дополнительной информации о цвете и палитрах, см. главу Цвета. Для получения дополнительной информации о точечных рисунках и операциях с точечным рисунком, см. главу Точечные рисунки.
GDI — Graphics Device Interface
Graphics device interface (GDI — графический интерфейс устройства) — это базовая система вывода двухмерной графики Windows. Под системой вывода графики мы будем понимать рисование геометрических фигур и вывод текста. Т.е. GDI отвечает за рисование картинок и вывод текста.
GDI написана на winAPI, т.е. это просто набор функций и структур на чистом C. Сначала мы познакомимся с GDI, а потом рассмотрим более сложные системы вывода двухмерной графики: GDI+ и Direct2D.
Device context — контекст устройства
Контекст устройства (Device context) — это то место, куда рисуется графика, плюс средства рисования графики. Мы можем получить контекст устройства окна и тогда можем рисовать что-то в этом окне. Можно получить контекст устройства принтера и рисовать фигуры на печатаемой странице. Контекст устройства позволяет использовать кисти (brushes), перья (pens), картинки (bitmaps) для вывода графики.
Получение контекста устройства окна
Для получения контекста устройства окна используется описатель окна (HWND). Контекст устройства представлен в программе переменной типа HDC — переопределённый указатель на void. Для получения контекста устройства окна используется функция getDC:
!1?HDC hDC = GetDC(hWnd);?1!
После этого можно использовать переменную hDC для рисования в окне hWnd. После завершения рисования, нужно «отпустить» контекст устройства с помощью функции ReleaseDC. Давайте посмотрим на код, который рисует прямоугольник и выводит текстовую строку в окне:
!1?WNDCLASS wc; wc.style = CS_OWNDC; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(6); wc.lpszMenuName = 0; wc.lpszClassName = L»class»; RegisterClass(&wc); HWND hWnd = CreateWindow(L»class», L»GDI», WS_OVERLAPPEDWINDOW, 100, 100, 300, 300, NULL, NULL, hInstance, NULL); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); HDC hDC = GetDC(hWnd); // получение контекста устройства Rectangle(hDC, 50, 50, 200, 200); // рисование прямоугольника TextOut(hDC, 5, 5, L»Привет. «, 9); // вывод текста ReleaseDC(hWnd, hDC); // освобождение контекста устройства?1!
Функция Rectangle принимает следующие аргументы: контекст устройства, координаты левого верхнего угла, координаты правого нижнего угла.
Функция TextOut принимает аргументы: контекст устройства, координаты левого верхнего угла текста, текстовая строка, количество символов в текстовой строке.
Функция Release принимает аргументы: окно, контекст устройства.
В данном примере рисование происходит до основного цикла while. Т.е. рисование будет произведено только один раз. Если вы свернёте и развернёте окно, то нарисованное исчезнет. Просто нужно поместить рисование внутрь цикла while, как это сделано в прикреплённом проекте gdi_0.1, тогда окно будет перерисовываться при каждой итерации.
Вывод графики в нескольких окнах
Когда мы заполняем структуру WNDCLASS, чтобы зарегистрировать класс окна программы в Windows, мы заполняем поле style:
Данное поле задаёт стиль класса окон. Значение CS_OWNDC говорит, что для каждого окна данного класса будет создан свой контекст устройства.
Рассмотрим пример gdi_0.2. В данной программе создаётся два окна:
Заметьте, что второе окно нельзя растягивать, у него нет системного меню и кнопки закрытия. Просто при создании второго окна я не стал указывать стиль (передал ноль в третий аргумент):
!1?HWND hWnd2 = CreateWindow(L»class», L»GDI2″, 0, 300, 100, 200, 200, NULL, NULL, hInstance, NULL);?1!
У каждого окна этой программы свой контекст устройства:
!1?HWND hWnd1 = CreateWindow(L»class», L»GDI», WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, NULL, NULL, hInstance, NULL); HWND hWnd2 = CreateWindow(L»class», L»GDI2″, 0, 300, 100, 200, 200, NULL, NULL, hInstance, NULL); ShowWindow(hWnd1, nCmdShow); UpdateWindow(hWnd1); ShowWindow(hWnd2, nCmdShow); UpdateWindow(hWnd2); MSG msg; HDC hDC = GetDC(hWnd1); Rectangle(hDC, 50, 50, 100, 100); TextOut(hDC, 5, 5, L»Первое окно. «, 14); ReleaseDC(hWnd1, hDC); while (true) < if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) < if (msg.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg); >hDC = GetDC(hWnd2); Rectangle(hDC, 50, 50, 100, 100); TextOut(hDC, 5, 5, L»Второе окно. «, 14); ReleaseDC(hWnd2, hDC); >?1!
Рисование в первом окне происходит до основного цикла. Поэтому, если свернуть, а затем развернуть окно, то всё нарисованное исчезнет. Рисование во втором окне происходит при каждой итерации основного цикла.
Заключение
В данном уроке мы познакомились с GDI — базовой системой вывода двухмерной графики в Windows. В следующих уроках мы научимся работать с различными возможностями GDI: перьями и кистями.
В основном мы будем рисовать графику в главном цикле — такой вывод графики больше подходит для игр. Но это нехарактерно для программ Windows. Чуть позже мы познакомимся со стандартным способом использования GDI в Windows программах.
Контекст устройства отображения
В многозадачной операционной системе семейства Windows отсутствует возможность прямого бесконтрольного вывода на экран (как это было во времена MSDOS), тут все подчинено некоему регламенту. С целью обеспечения возможности вывода на устройство (экран, принтер, память) одновременно от множества источников (приложений), в Windows был создан специализированный механизм под названием контекст устройства (device context, DC) и подмножество обеспечивающих его работу функций. Указанные функции определяют размер клиентской области, шрифт, цвета и другие GDI-атрибуты и возвращают (предоставляют) приложению так называемый дескриптор контекста устройства (Device Context Descriptor). Поскольку контекст устройства является одним из основополагающих понятий в понимании механизмов вывода информации на устройство, я постараюсь дать некоторое количество определений для погружения в тему:
- Контекст устройства — логическое устройство вывода, посредством которого осуществляется вывод информации на устройство вывода (дисплей, принтер, память).
- Контекст устройства — структура данных, описывающая устройство отображения информации.
В операционной системе Windows существует несколько типов контекстов устройства, а именно:
- Контекст устройства отображения (display);
- Контекст устройства печати (printer);
- Контекст устройства памяти (memory, CompatibleDC);
- Контекст информационного устройства (information);
- если приложение создает/получает собственный контекст для отрисовки в собственном окне, такой контекст называется контекстом устройства отображения.
- если приложению необходимо выполнить операцию ввода-вывода на аппаратное устройство (экран, принтер, память), такой контекст называется контекстом устройства печати, контекстом устройства памяти или контекстом информационного устройства.
Нас же в рамках данной статьи интересует контекст устройства отображения:
Существует несколько типов контекста отображения:
- Контекст отображения класса окна (class display context);
- Общий контекст отображения (common display context);
- Личный контекст отображения (private display context);
- Контекст отображения окна (window display context);
- Родительский контекст отображения (parent display context);
Соответственно, методы получения (освобождения) контекста отображения различны для контекстов описанных типов.
В процессе изучения функционала GDI становится очевидным, что во многих функциях вывода графических примитивов в Windows одним из входных параметров является указатель на контекст устройства отображения.
Дескриптор (описатель) контекста отображения, возвращаемый функциями API, это своеобразный указатель, предоставляемый системой пользовательскому уровню приложения, посредством которого приложение получает доступ к устройству вывода (например, экран).
Каждое приложение в случае необходимости экранного вывода получает в свое распоряжение собственный контекст и осуществляет посредством него вывод изображения. Поэтому, более интуитивно дескриптор контекста устройства отображения воспринимается в качестве указателя на некую системную структуру в памяти ядра, через которую система выводит данные на физическое устройство отображения.
Структура контекста устройства
Надо учитывать, что контекст устройства является структурой, состоящей, в свою очередь, из описателей объектов графических примитивов (характеристик), используемых при работе с контекстом:
Атрибут контекста | Значение по умолчанию | Функция для изменения | Функция для получения |
---|---|---|---|
Режим отображения (Mapping mode) | MM_TEXT | SetMapMode | GetMapMode |
Начало координат окна (Window origin) | (0,0) | SetWindowOrgEx | GetWindowOrgEx |
Начало координат области вывода (Viewport Origin) | (0,0) | SetViewportOrgEx | GetViewportOrgEx |
Протяженность окна (Window extent) | (1,1) | SetWindowExtEx | GetWindowExtEx |
Протяженность области вывода (Viewport extent) | (1,1) | SetViewportExtEx , SetMapMode | GetViewportExtEx |
Перо (Pen) | BLACK_PEN | SelectObject | SelectObject |
Кисть (Brush) | WHITE_BRUSH | SelectObject | SelectObject |
Шрифт (Font) | SYSTEM_FONT | SelectObject | SelectObject |
Битовый образ (Bitmap) | NOT | SelectObject | SelectObject |
Текущая позиция пера (Current pen position) | (0,0) | MoveToEx , LineTo , PolylineTo , PolyBezierTo | GetCurrentPositionEx |
Режим фона (Background mode) | OPAQUE | SetBkMode | GetBkMode |
Цвет фона (Background color) | Обычно Белый (по Панели управления) | SetBkColor | GetBkColor |
Цвет текста (TextColor) | Обычно Черный (по Панели управления) | SetTextColor | GetTextColor |
Режим рисования (Drawing mode) | R2_COPYPEN | SetROP2 | GetROP2 |
Режим растяжения (Stretching mode) | BLACKONWHITE | SetStrethBltMode | GetStrethBltMode |
Режим закрашивания многоугольников (Polygon filling mode) | ALTERNATE | SetPolyFillMode | GetPolyFillMode |
Межсимвольный интервал (Intercharacter spacing) | 0 | SetTextCharacterExtra | GetTextCharacterExtra |
Начало координат кисти (Brush origin) | (0,0) | SetBrushOrgEx | GetBrushOrgEx |
Область отсечения (Clipping region) | Not . Окно (рабочая область) с обновляемым регионом обрезается. | SelectObject , SelectClipRgn | GetClipBox |
Обычно данная структура содержит значения по умолчанию, определенные разработчиками из Microsoft.
Вы имеете возможность менять указанные атрибуты по собственному желанию уже после того, как получили дескриптор контекста устройства отображения. Но не надо забывать, что когда пользовательскому приложению требуется изменить какой-либо элемент структуры контекста устройства, оно должно производить эти действия исключительно через предназначенные для этого функции WinAPI, поскольку напрямую элементы структуры контекста устройства для изменения не доступны. Все описанные выше инструменты (и их параметры) доступны для выбора и переназначения, поскольку функции GDI используют только выбранные в контекст устройства параметры и инструменты рисования.
Помимо связывания функций вывода WinAPI с конкретным устройством, контекст устройства решает проблему чрезмерной нагрузки на систему при интенсивном вызове GDI-функций. Ведь если разобраться, то становится очевидным, что параметры в контексте устройства присутствуют для снижения нагрузки на подсистемы ядра от необходимости постоянной передачи одних и тех же атрибутов при каждом вызове GDI-функций.
Любой контекст устройства должен ассоциироваться с каким-либо аппаратным устройством (видеоадаптер, принтер, память). Например, для случая вывода текста в окно приложения, контекст устройства отображения для пользовательского приложения ассоциируется с областью окна приложения (не со всем экраном) и видеоадаптером/монитором. Сопряжение логического изображения с определенным видеоадаптером осуществляется уже на уровне ядра операционной системы на основе установленных в системе драйверов видеоадаптера. Контекст устройства дополнительно решает еще и задачу абстракции (независимости) от конкретной аппаратной архитектуры, позволяющей приложению записывать данные в аппаратное устройство, абсолютно не заботясь о том, правильно или неправильно будет представлена информация на огромном количестве существующих или перспективных аппаратных устройств, имеющих свою специфику. Таким образом обеспечивается идентичность изображения на всех конфигурациях, на которых работает операционная система Windows.