Системное программирование в среде Win32

Автор работы: Пользователь скрыл имя, 25 Марта 2014 в 14:49, лекция

Краткое описание

Конспект лекций содержит описание технологии системного программирования под Windows с использованием функций Win32 API. В первой части конспекта лекций рассмотрены особенности архитектуры ОС Windows, специфика интерфейса прикладного программирования Win32, структура приложений для Windows. Подробно рассмотрены API функции и основные структуры данных для работы с дисками, каталогами, файлами. Отдельная глава посвящена структурной обработке исключений SEH.

Прикрепленные файлы: 1 файл

Win32_лек_часть1.doc

— 811.00 Кб (Скачать документ)

Контекст устройства – это структура, определяющая набор графических объектов и связанных с ними атрибутов и графических режимов. В этот набор входят:

  • битовая карта (bitmap) - прямоугольный массив точек, формирующий  изображение в окне;
  • перо (pen) для прорисовки линий, параметры пера - толщина, цвет, стиль (сплошная, пунктирная и т.п.);
  • кисть (brush) – для задания заливки замкнутых контуров; параметры кисти: цвет и стиль;
  • логическая палитра (logical palette) – осуществляет интерфейс между приложением и цветным устройством вывода, таким как дисплей, создает список цветов, необходимых приложению;
  • шрифт (font) – задает параметры вывода текста (имя шрифта, размер символов, цвет и т.п.);
  • и т.д.

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

Программа не имеет прямого доступа к контексту устройств (как и большинству структур Win32 API), она обращается к нему опосредованно через определенные функции. После того как все действия произведены, программа должна освободить контекст устройства, чтобы не занимать память. Еще одна причина, по которой следует освобождать контекст устройств: в системе может существовать одновременно только ограниченное число контекстов устройств. Если контекст не будет освобождаться после операций вывода, то через несколько перерисовок окна система может зависнуть.

Когда программа требует контекст устройства, она получает его уже заполненным значениями по умолчанию. Объект в составе контекста называется текущим объектом. Само слово – текущий – говорит о том, что контекст устройства можно изменить. Программа может создать новый объект, например, bitmap или шрифт, и сделать его текущим. Замещенный объект автоматически из памяти не удаляется. Его необходимо позже удалить отдельно.

Типы контекстов устройств

Win32 определяет  четыре типа контекстов устройств:

  • контекст дисплея - обеспечивает операции рисования непосредственно на экране;
  • контекст принтера – обеспечивает операции рисования на принтере или плоттере;
  • контекст в памяти - используется для хранения изображений, которые будут скопированы на устройство вывода.
  • информационный контекст - служит для получения данных от устройства).

 

Контекст дисплея

Windows поддерживает  три типа контекста дисплея  – контекст класса, приватный (частный) контекст и общий контекст. Первые два типа используются в приложениях, которые выполняют многочисленные операции рисования (например, издательские системы, программы автоматизированного проектирования). Контекст класса является устаревшим, поддерживается только для совместимости с предыдущими версиями Windows. В новых разработках следует использовать частные контексты.

Общие контексты используются в приложениях, которые лишь время от времени выполняют операции рисования. Общий контекст хранится в кэше. Получить его хэндл можно с помощью функций GetDC(), GetDCEx()  или BeginPaint(). Windows инициализирует общие контексты устройства значениями по умолчанию, которые можно менять по мере необходимости с помощью специальных функций. Количество общих контекстов в системе ограничено и, следовательно, после завершения операции вывода необходимо освободить контекст, вызвав функцию ReleaseDC()  или EndPaint(). После того, как контекст дисплея освобожден, все изменения, внесенные в него программой, теряются и при повторном получении контекста все действия по изменению контекста необходимо повторить заново.

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

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

При работе с контекстами необходимо помнить, что хэндлы с помощью функции BeginPaint() можно получать только в случае обработки сообщения WM_PAINT.

Контекст принтера

Win32 API обеспечивает  один и тот же тип контекста  устройства как для принтера, который может быть матричным, струйным или лазерным, так и  для графопостроителя (плоттера). При  необходимости вывода на принтер программа должна создать контекст устройства с помощью функции CreateDC(). Аргументы этой функции определяют имя драйвера устройства, тип устройства и инициализационные данные устройства. После распечатки прикладная программа должна удалить контекст принтера с помощью функции DeleteDC(). Простое освобождение контекста при помощи функции ReleaseDC()   недостаточно и недопустимо!

Контекст в памяти

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

Последовательность работы с контекстом в памяти.

  1. Получение хэндла контекста устройства для окна, в которое будет осуществляться вывод изображения (hDC).
  2. Получение хэндла bitmap’а, который будет отображаться в окне.
  3. Получение совместимого с hDC контекста в памяти (для хранения изображения) с помощью функции CreateCompatibleDC().
  4. Выбор изображения (hBitmap) как текущего для контекста в памяти (hCompatibleDC).
  5. Копирование изображения контекста в памяти (hCompatibleDC) на контекст устройства (hDC).
  6. Удаление совместимого контекста (hCompatibleDC).
  7. Принятие мер для того, чтобы замещенный bitmap из контекста в памяти не остался в памяти.
  8. Освобождение контекста устройства (hDC).

Информационный контекст

Информационный контекст фактически не является контекстом устройства и служит только для получения информации о действительном контексте устройства. К примеру, для того чтобы получить характеристики принтера, программа создает информационный контекст, используя функцию CreateIC(), а затем из него выбирает требующиеся характеристики. Для чего нужен информационный контекст? Почему нельзя те же самые данные получить из действительного контекста устройства? Дело в том, что этот тип контекста создается и работает намного быстрее, а также занимает меньше памяти по сравнению с действительным контекстом. Завершив работу с информационным контекстом, его следует удалить с помощью функции DeleteDC().

 

2. Структура приложений для Windows

Большинство приложений Windows обеспечивают взаимодействие с пользователем при помощи набора элементов управления, размещенных в одном или нескольких окнах.

Практически любое классическое Windows-приложение должно иметь хотя бы одно окно. Каждое окно должно выполнять следующие функции:

  • отображать себя на экране;
  • взаимодействовать с другими окнами и операционной системой;
  • управлять размещенными на нем элементами управления;
  • реагировать на разнообразные события (обрабатывать очередь сообщений).

 

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

2.1. Минимальная программа для Windows

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

Все это происходит, как правило, в функции WinMain(), которая является стандартной точкой входа  во все программы  Windows. (Функция  main() является точкой входа  DOS-овских  программ, а WinMain() – Windows-овых).

Для удобства функция окна отделена от WinMain() (к функции окна постоянно обращается система). Она может находиться либо в той же программе, что и WinMain(), либо вызываться  из какой-либо библиотеки. Тем самым можно создавать множество окон, использующих одну и ту же оконную функцию (использующих одни и те же методы), но имеющих разные характеристики (разные значения полей).

Каждое окно принадлежит какому-либо классу. Если к моменту создания окна операционной системе известен класс создаваемого окна (например, это определенный в системе или зарегистрированный текущим или другим приложением класс), то можно воспользоваться именем этого класса. Иначе нужно создать новый класс (описать функцию окна и набор используемых ресурсов) и зарегистрировать его. Потом можно создать само окно (объект класса).

В самом обобщенном виде программу для Windows можно записать следующим  образом:

 

WinMain ( список аргументов)

{Описание  класса окон с заданными характеристиками;

Создание экземпляра окна только что созданного класса;

Пока не произошло необходимое событие

  Опрашивать очередь сообщений и передавать сообщения

оконной функции (вызывать оконную функцию);

Возврат из программы;

}

WindowsFunction (список аргументов)  // оконная функция

{

Обработать полученное сообщение;

Возврат;

}

 

2.2. Функция WinMain() и ее аргументы

int WINAPI  WinMain  (HINSTANCE  hInstance,

HINSTANCE  hPrevInstance,

LPSTR  lpszCmdParam,  int nCmdShow)

 

Функция возвращает целое значение. Следующая характеристика – WINAPI- определяет порядок передачи параметров при вызове функции. В данном случае название говорит само за себя, т.е. применяются соглашения о передаче параметров, принятые в системах Windows NT и Windows 9х.

Рассмотрим следующие два параметра: hInstance, hPrevInstance. Так как Windows является многозадачной системой, то одна и та же программа может быть запущена несколько раз. Для того чтобы различать экземпляры программ, каждому экземпляру присваивается хэндл. Когда вызывается функция WinMain(), Windows через переменную hInstance сообщает программе хэндл экземпляра программы. В Windows 3.1 переменная hPrevInstance являлась хэндлом предыдущего экземпляра. Если запускался первый экземпляр программы, то hPrevInstance равнялась NULL. Этот факт можно было использовать для того, чтобы не разрешить системе запустить более одного экземпляра приложения. В Win32 hPrevInstance оставлен только для совместимости с предыдущими версиями Windows, он не несет никакой нагрузки и постоянно равен NULL. Так просто, как в более ранних версиях Windows, определить наличие ранее запущенного экземпляра приложения не удастся.

Следующий параметр – lpszCmdParam – представляет собой указатель на ту командную строку, которая набирается после имени запускаемой программы. При необходимости программа может проанализировать этот аргумент и выполнить те ли иные действия.

И последний параметр – nCmdShow – определяет, в каком виде создаваемое окно появится на экране. В Win32 API определяются 10 возможных значений этого параметра. Их идентификаторы начинаются с SW (от названия функции ShowWindow, которая использует эти значения). Наиболее часто используются значения SW_SHOWNORMAL (активизирует и отображает окно в первоначальных размерах), SW_SHOWMAXIMIZED (активизирует окно распахнутым на весь экран), SW_SHOWMINNOACTIVE (сворачивает окно) (другие значения см. табл. П.1).

 

2.3. Функция окна и ее аргументы

Функция окна описывает реакцию окна на поступающие сообщения. Она от обычных функций отличается следующим:

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

Еще одно отличие. В ООП методы изменения параметров состояния объектов (функции-члены) обычно описываются отдельно. Функция окна реализует единственный метод для изменения всех параметров состояния окна.

Имя функции окна – обычное имя, определяемое разработчиком. При регистрации класса окна (см. ниже пример 2.1) операционная система запоминает указатель на эту функцию.

  Заголовок функции окна определен  соглашениями Windows и имеет вид:

LRESULT  CALLBACK WndProc (

HWND hWnd, UINT  Message,

UINT  wParam, LONG lParam);

 

Тип возвращаемого функцией результата LRESULT – равноценен типу  signed long. (макрос, а вообще  - DWORD)

Модификатор CALLBACK говорит о том, что это - функция обратного вызова. Такие функции вызываются ядром системы, а не пользовательской функцией. Данная функция вызывается ядром при приходе сообщения (Windows Message)

Параметры этой функции следующие:

HWND hWnd;  - хэндл окна-адресата, а Message, wParam, lParam –описывают полученное сообщение.  Message – код сообщения. Другие параметры зависят от кода сообщения (для wParam). Например,  при поступлении сообщения WM_MOVE параметр lParam содержит экранные координаты левого верхнего угла рабочей области:

left=LOWORD(lParam); // Координата левого края рабочей  области

top=HIWORD(lParam);  // Координата верхнего края рабочей  области

При поступлении сообщения WM_SIZE параметр lParam несет информацию о ширине и высоте рабочей области:

cx=LOWORD(lParam); // ширина рабочей области

cy=HIWORD(lParam);  // высота рабочей области

 

Рассмотрим действие оконной функции.

Как обработать множество различных сообщений?

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

Дело в том, что в Windows  предусмотрена обработка всех сообщений по умолчанию. В программе должен присутствовать код обработки только тех сообщений, обработка которых по умолчанию не устраивает программу. Все остальные «протекают» сквозь функцию окна и передаются на обработку по умолчанию. Делается это простым обращением к функции DefWindowProc  (Default Window Procedure). Именно эта функция, спрятанная глубоко в недрах Windows, производит обработку подавляющего большинства сообщений, получаемых окном. На долю оконной процедуры остается «самая малость» – обработать сообщения, которые нуждаются в нестандартной  обработке.

Громадный switch

Фактически вся оконная процедура состоит из одного единственного оператора switch.

Рассмотрим основные виды сообщений, которые приходится обрабатывать практически каждой оконной функции.

Например,

WM_PAINT

До Windows при изменениях на экране для восстановления картинки создавался графический буфер. В Windows каждое окно «знает» о том, что оно должно проделать в тех случаях, когда условия отображения изменились (размер, положение на экране, восстановление после перекрытия). В этих случаях окну посылается сообщение WM_PAINT, говорящее о том, что окно должно само перерисоваться полностью или частично, обработав сообщение WM_PAINT. Т.е. экономится память (легче хранить небольшую процедуру, чем выделять память под графический буфер). При этом выполняется требование ООП – инкапсуляция. Полями объекта управляют методы того же (и только того же!) объекта. Т.о. каждое окно должно обрабатывать сообщение WM_PAINT, иначе оно не сможет восстановить изображение в своей рабочей области.

Информация о работе Системное программирование в среде Win32