1. bitmap (битовая карта, изображение), отображаемый в окне
2. перо для прорисовки линий
3. кисть
4. палитра
5. шрифт
и т. д. Программа никогда напрямую не обращается к контексту устройства (кстати, эта структура не документирована Microsoft), она обращается к нему опосредствованно, через определенные функции. После того, как все действия произведены, и необходимость в использовании устройства отпала, программа должна освободить контекст устройства, чтобы не занимать память. Есть еще одна причина, из-за которой необходимо освобождать контекст устройства. В системе может существовать одновременно только ограниченное число контекстов устройств. Если контекст устройства не будет освобождаться после операций вывода, то через несколько перерисовок окна система может зависнуть.
Когда программа требует контекст устройства, она получает его уже заполненным значениями по умолчанию. Объект в составе контекста называется текущим объектом. Само слово – текущий – говорит о том, что контекст устройства можно изменить. Программа может создать новый объект, скажем, bitmap или шрифт, и сделать его текущим. Замещенный объект автоматически из памяти не удаляется и его необходимо позже удалить отдельно. Само собой разумеется, что программа может получить характеристики текущего устройства. А вот изменить эти характеристики, увы, можно только через замену объекта (впрочем, это и так понятно).
В Windows поддерживаются следующие типы контекстов устройств:
1. контекст дисплея (обеспечивает работу с дисплеем)
2. контекст принтера (обеспечивает работу с принтером)
3. контекст в памяти (моделирует в памяти устройство вывода)
4. информационный контекст (служит для получения данных от устройства)
Windows поддерживает три типа контекста дисплея - контекст класса, приватный контекст и общий контекст. Первые два типа используются в приложениях, которые выводят на экран большое количество информации. Ярким примером такого рода приложений являются настольные издательские приложения, графические пакеты и т.д.
Приложения, которые не очень интенсивно работают с экраном, используют общий контекст. Контекст класса является устаревшим и поддерживается только для обеспечения совместимости с предыдущими версиями Windows. Microsoft не рекомендует использовать его при разработке новых приложении и рекомендует использовать только приватный контекст.
Контексты устройств хранятся в кэше, управляемом системой. Хэндл общего контекста программа получает с помощью функций GetDC, GetDCEx или BeginPaint. После того, как программа отработает с дисплеем, она должна освободить контекст, вызвав функцию ReleaseDCили EndPaint (в случаи, если контекст получался с помощью BeginPaint). После того, как контекст дисплея освобожден, все изменения, внесенные в него программой, теряются и при повторном получении контекста все действия по изменению контекста необходимо повторять заново.
Приватный контекст отличается от общего тем, что сохраняет изменения даже после того, как прикладная программа освободила его. Приватный контекст не хранится в кэше, поэтому прикладная программа может не освобождать его. Естественно, что в этом случае за счет использования большого объема памяти достигается более высокая скорость работы с дисплеем.
Для работы с приватным контекстом необходимо при регистрации класса окна указать стиль CS_OWNDC. После этого программа может получать хэндл контекста устройства точно так же, как и в случае общего контекста. Система удаляет приватный контекст в том случае, когда удаляется окно.
При работе с контекстами необходимо запомнить, что хэндлы контекста устройства с помощью функции BeginPaint необходимо получать только в случае обработки сообщения WM_PAINT. Во всех остальных случаях необходимо использовать функции GetDC или GetDCEx.
Контекст в памяти используется для хранения изображений, которые затем будут скопированы на устройство вывода. Сам по себе контекст в памяти не создается. Он обязательно создан как совместимый с тем устройством или окном, на которое предполагается копировать информацию (вот он - совместимый контекст - переходник между программой и драйвером устройства!). Алгоритм работы с контекстом в памяти состоит из нескольких шагов:
1. Получения хэндла контекста устройства (hDC - handleofDeviceContext) для окна, в которое будет осуществляться вывод изображения
2. Получения хэндла bitmap'а, который будет отображаться в окне
3. Получения совместимого с hDC контекста в памяти (для хранения изображения) с помощью функции CreateCompatibleDC
4. Выбора изображения (hBitmap) как текущего для контекста в памяти (hCompalibleDC)
5. Копирования изображения контекста в памяти (hCompatibleDC) на контекст устройства (hDC)
6. Удаления совместимого контекста (hCompatibleDC)
7. Принятия мер для того, чтобы замещенный bitmap из контекста в памяти не остался в памяти
8. Освобождения контекста устройства (hDC)
Как и когда удалять замещенный bitmap, зависит от программиста и поставленной перед ним задачи.
Именно этот способ и используется в большинстве программ для копирования изображения.
Программа называется EasyPaint. Программа написана на языке программирования ассемблер в среде RadAsm и скомпилирована компилятором MASM32. Кроме того, при разработке использовались следующие программы:
1. Bred
2. ICAConverter
3. IrfanView
4. Microangelo
Программа предназначена для предоставления простой работы с изображениями в формате BMP/DIB, для чего были реализованы необходимые инструменты, а также загрузка и сохранение изображений.
После запуска программы создается основное окно программы, загружаются ресурсы и создаются элементы управления, а также в памяти создается совместимый контекст, на котором будет производится все рисование. После этого запускается цикл обработки сообщений, в котором происходит обработка поступающих сообщений:
1. Обработка клавиатуры
2. Обработка «горячих клавиш» главного меню
3. Обработка сообщений к диалоговому окну
4. А также всех остальных сообщений как оконной функцией, так и стандартным обработчиком
При обработке перерисовки содержимое совместимого контекста копируется на основной контекст - в окно. Все рисование осуществляется при обработке событий от мыши, а также при изменении размеров окна.
При завершении работы программы совместимый контекст удаляется из памяти.
После запуска вначале происходит инициализация общих элементов управления (CommonControls), затем вызывается процедура WinMain (procWinMain.inc), являющаяся основной частью программы, своеобразным каркасом, на который навешаны остальные функции.
В этой процедуре вначале регистрируется класс окна и создается экземпляр, причем в качестве иконки и курсора выступают загруженные ресурсы. После этого окно центрируется на экране и в него добавляются элементы управления Панель управления и Строка состояния, описанные в файлах ToolBarRealization.inc и StatusBarRealization.inc соответственно. Элементы управления создаются и настраиваются, после этого они полностью готовы к функционированию как составные части программы.
Затем в файле InitApp.incпроизводятся действия по инициализации программы:
· производится вызов процедуры CreateBackBuffer (DoubleBuff.inc), в которой создается совместимый контекст – для двойной буферизации вывода графики (задний буфер)
· вызов процедур SetPenParam и SetBrushColor (Draw.inc) настраивает свойства объектов карандаш и кисть совместного контекста: устанавливаются цвет и толщина
В конце инициализации программы загружается список акселераторов из ресурсов, делается видимым главное окно и запускается цикл обработки сообщений. После завершения данного цикла вызов процедуры DeleteBackBuffer освобождает ресурсы, выделенные на задний буфер.
Процедуры этого модуля предназначены для создания плавного вывода без мерцания и любых других визуальных артефактов.
Задний буфер создается в процедуре CreateBackBuffer, которая не только создает буфер, но и кроме того позволяет менять его размер и даже копировать в новый буфер старое содержимое.
Для освобождения ресурсов буфера предназначена процедура DeleteBackBuffer.
Для очистки буфера (он заполняется белым цветом) предназначена процедура Clear.
Процедура Flip позволяет скопировать содержимое буфера на контекст окна.
Т.к. при вызове процедуры Flip отображается только заранее видимая часть изображения, то необходимо эту видимую часть вычислять. Это и делает процедура Resize.
Кроме того, в файле содержатся процедуры LoadFromFile и SaveToFile, позволяющие загружать и сохранять изображения соответственно.
В данном файле содержатся процедуры SetPenParam, SetBrushColor и PutPixel. Две первые предоставляют удобное средство для изменения свойств карандаша и кисти заднего буфера, а процедура PutPixel предназначена для вывода точки с определенной толщиной (в зависимости от толщины она выводит или один пиксель, или окружность в заданной точке).