Автор работы: Пользователь скрыл имя, 25 Марта 2014 в 14:49, лекция
Конспект лекций содержит описание технологии системного программирования под Windows с использованием функций Win32 API. В первой части конспекта лекций рассмотрены особенности архитектуры ОС Windows, специфика интерфейса прикладного программирования Win32, структура приложений для Windows. Подробно рассмотрены API функции и основные структуры данных для работы с дисками, каталогами, файлами. Отдельная глава посвящена структурной обработке исключений SEH.
Контекст устройства – это структура, определяющая набор графических объектов и связанных с ними атрибутов и графических режимов. В этот набор входят:
Если программе нужно осуществить обмен с внешним устройством, программа должна оповестить GDI о необходимости подготовить устройство для операции ввода/вывода. После того как устройство подготовлено, программа получает хэндл контекста устройства, т.е. хэндл структуры, содержащей набор характеристик этого устройства.
Программа не имеет прямого доступа к контексту устройств (как и большинству структур Win32 API), она обращается к нему опосредованно через определенные функции. После того как все действия произведены, программа должна освободить контекст устройства, чтобы не занимать память. Еще одна причина, по которой следует освобождать контекст устройств: в системе может существовать одновременно только ограниченное число контекстов устройств. Если контекст не будет освобождаться после операций вывода, то через несколько перерисовок окна система может зависнуть.
Когда программа требует контекст устройства, она получает его уже заполненным значениями по умолчанию. Объект в составе контекста называется текущим объектом. Само слово – текущий – говорит о том, что контекст устройства можно изменить. Программа может создать новый объект, например, bitmap или шрифт, и сделать его текущим. Замещенный объект автоматически из памяти не удаляется. Его необходимо позже удалить отдельно.
Win32 определяет
четыре типа контекстов
Windows поддерживает три типа контекста дисплея – контекст класса, приватный (частный) контекст и общий контекст. Первые два типа используются в приложениях, которые выполняют многочисленные операции рисования (например, издательские системы, программы автоматизированного проектирования). Контекст класса является устаревшим, поддерживается только для совместимости с предыдущими версиями Windows. В новых разработках следует использовать частные контексты.
Общие контексты используются в приложениях, которые лишь время от времени выполняют операции рисования. Общий контекст хранится в кэше. Получить его хэндл можно с помощью функций GetDC(), GetDCEx() или BeginPaint(). Windows инициализирует общие контексты устройства значениями по умолчанию, которые можно менять по мере необходимости с помощью специальных функций. Количество общих контекстов в системе ограничено и, следовательно, после завершения операции вывода необходимо освободить контекст, вызвав функцию ReleaseDC() или EndPaint(). После того, как контекст дисплея освобожден, все изменения, внесенные в него программой, теряются и при повторном получении контекста все действия по изменению контекста необходимо повторить заново.
Приватный контекст отличается тем, что сохраняет изменения даже после того, как прикладная программа освободила его. Приватный контекст не хранится в кэше, поэтому прикладная программа может не освобождать его. В этом случае за счет использования большого объема памяти достигается большая скорость работы с дисплеем.
Для того чтобы работать с приватным контекстом необходимо при регистрации класса окна указать стиль CS_OWNDC. После этого программа может получать хэндл контекста так же, как и в случае с общим контекстом. Система удаляет приватный контекст в том случае, когда удаляется окно.
При работе с контекстами необходимо помнить, что хэндлы с помощью функции BeginPaint() можно получать только в случае обработки сообщения WM_PAINT.
Win32 API обеспечивает один и тот же тип контекста устройства как для принтера, который может быть матричным, струйным или лазерным, так и для графопостроителя (плоттера). При необходимости вывода на принтер программа должна создать контекст устройства с помощью функции CreateDC(). Аргументы этой функции определяют имя драйвера устройства, тип устройства и инициализационные данные устройства. После распечатки прикладная программа должна удалить контекст принтера с помощью функции DeleteDC(). Простое освобождение контекста при помощи функции ReleaseDC() недостаточно и недопустимо!
Используется чаще всего. Этот контекст используется для хранения изображений, которые затем будут скопированы на устройство вывода. Контекст в памяти создается не сам по себе, а обязательно совместимый с тем устройством или окном, на которое предполагается копировать информацию. Он является промежуточным связующим звеном между программой и драйвером устройства.
Последовательность работы с контекстом в памяти.
Информационный контекст фактически не является контекстом устройства и служит только для получения информации о действительном контексте устройства. К примеру, для того чтобы получить характеристики принтера, программа создает информационный контекст, используя функцию CreateIC(), а затем из него выбирает требующиеся характеристики. Для чего нужен информационный контекст? Почему нельзя те же самые данные получить из действительного контекста устройства? Дело в том, что этот тип контекста создается и работает намного быстрее, а также занимает меньше памяти по сравнению с действительным контекстом. Завершив работу с информационным контекстом, его следует удалить с помощью функции DeleteDC().
Большинство приложений Windows обеспечивают взаимодействие с пользователем при помощи набора элементов управления, размещенных в одном или нескольких окнах.
Практически любое классическое Windows-приложение должно иметь хотя бы одно окно. Каждое окно должно выполнять следующие функции:
Для разработчика окно является совокупностью большого количества элементов, функционирующих под управлением приложения и операционной системы. С точки зрения языка программирования, окна – это объекты (переменные), над которыми выполняют действия. Объект принадлежит определенному классу (типу), который описывает множество данных (параметров состояния окна) и метод (функцию) изменения этих данных.
Итак, при запуске программы должны происходить, по меньшей мере, два события – должно быть создано окно и запущен цикл обработки сообщений, из которого с наступлением какого-то события должен быть осуществлен выход и работа программы должна завершиться.
Все это происходит, как правило, в функции WinMain(), которая является стандартной точкой входа во все программы Windows. (Функция main() является точкой входа DOS-овских программ, а WinMain() – Windows-овых).
Для удобства функция окна отделена от WinMain() (к функции окна постоянно обращается система). Она может находиться либо в той же программе, что и WinMain(), либо вызываться из какой-либо библиотеки. Тем самым можно создавать множество окон, использующих одну и ту же оконную функцию (использующих одни и те же методы), но имеющих разные характеристики (разные значения полей).
Каждое окно принадлежит какому-либо классу. Если к моменту создания окна операционной системе известен класс создаваемого окна (например, это определенный в системе или зарегистрированный текущим или другим приложением класс), то можно воспользоваться именем этого класса. Иначе нужно создать новый класс (описать функцию окна и набор используемых ресурсов) и зарегистрировать его. Потом можно создать само окно (объект класса).
В самом обобщенном виде программу для Windows можно записать следующим образом:
WinMain ( список аргументов)
{Описание
класса окон с заданными
Создание экземпляра окна только что созданного класса;
Пока не произошло необходимое событие
Опрашивать очередь сообщений и передавать сообщения
оконной функции (вызывать оконную функцию);
Возврат из программы;
}
WindowsFunction (список аргументов) // оконная функция
{
Обработать полученное сообщение;
Возврат;
}
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.1) операционная система запоминает указатель на эту функцию.
Заголовок функции окна
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.
Рассмотрим основные виды сообщений, которые приходится обрабатывать практически каждой оконной функции.
Например,
До Windows при изменениях на экране для восстановления картинки создавался графический буфер. В Windows каждое окно «знает» о том, что оно должно проделать в тех случаях, когда условия отображения изменились (размер, положение на экране, восстановление после перекрытия). В этих случаях окну посылается сообщение WM_PAINT, говорящее о том, что окно должно само перерисоваться полностью или частично, обработав сообщение WM_PAINT. Т.е. экономится память (легче хранить небольшую процедуру, чем выделять память под графический буфер). При этом выполняется требование ООП – инкапсуляция. Полями объекта управляют методы того же (и только того же!) объекта. Т.о. каждое окно должно обрабатывать сообщение WM_PAINT, иначе оно не сможет восстановить изображение в своей рабочей области.
Информация о работе Системное программирование в среде Win32