Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторный практикум «Основы разработки приложений Windows» книга 2.DOC
Скачиваний:
90
Добавлен:
10.05.2014
Размер:
827.9 Кб
Скачать

ФЕДЕРАЛЬНОЕ АГЕНСТВО ПО ОБРАЗОВАНИЮ

МОСКОВСКИЙ ИНЖЕНЕРНО-ФИЗИЧЕСКИЙ ИНСТИТУТ

(ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ)

К.Г. Финогенов

Лабораторный практикум «Основы разработки приложений Windows» Книга 2

Москва 2005

УДК 32.973.1

ББК 681.3

Ф59

Финогенов К.Г. Лабораторный практикум «Основы разработки приложений Windows». Книга2. Уч. пособие.

М.:МИФИ, 2005. 108 с.

Пособие предназначено для широкого круга читателей, приступающих к освоению программирования на языке С++ в операционной системе Windows. В первой части описано использование в прикладных программах таких средств системы Windows, как шрифты, таймеры, дочерние окна, растровые изображения и др. Уделено внимание специфическим возможностям 32-разрядных приложений – особенностям обслуживания файлов и организации параллельных вычислений.

Вторая часть пособия – описание лабораторного практикума по изучению основ разработки приложений Windows.

Предназначено для обучения студентов кафедры компьютерных медицинских систем факультета автоматики и электроники МИФИ по курсам “Информатика”, “Компьютерный практикум” и “Языки программирования и операционные системы”. Пособие может быть также полезно студентам, аспирантам и преподавателям, имеющим представление о языке С++ и желающим самостоятельно освоить принципы разработки прикладных программ, предназначенных для работы в системе Windows.

Рецензенты: С. М. Зайцев и В. В. Комаров

Рекомендовано редсоветом МИФИ в качестве учебного пособия

© Московский инженерно-физический институт (государственный университет), 2005

О г л а в л е н и е

Часть 1. Теоретические сведения4

1. Основы архитектуры защищенного режима4

Регистры процессора 4

Адресация памяти 9

2. Логические шрифты13

Создание логических шрифтов 13

Вывод на экран текстовых строк 17

3. Таймеры Windows19

Организация и обслуживание таймеров 19

Мультимедийные таймеры 22

Измерение интервалов времени22

Организация периодического процесса23

Задание однократного интервала времени25

4. Дочерние окна26

Создание и использование дочерних окон 26

Окна предопределенных классов в главном окне 33

5. Вывод растровых изображений35

Процедура вывода растрового изображения 35

Компоновка составных изображений 42

6. Обслуживание файлов в 32-разрядных приложениях Windows44

Базовые операции с файлами 45

Открытие и создание файла45

Запись и чтение файла47

Файлы, проецируемые в память 50

7. Процессы и потоки54

Создание дочернего процесса 54

Создание дочернего потока 55

Синхронизация потоков 61

Общие характеристики объектов Windows61

Синхронизация с помощью состояний потока63

Синхронизация с помощью событий65

Критические секции и защита данных68

8. Библиотеки динамической компоновки70

Часть 2. Лабораторный практикум73

Работы лабораторного практикума 73

Индивидуальные задания лабораторного практикума 88

Список литературы107

Часть 1 Теоретические сведения

1. Основы архитектурЫ защищенного режима Регистры процессора

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

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

Количество и назначение регистров процессора, как и механизм адресации памяти, зависит от типа процессора. Мы будем рассматривать 32-разрядные процессоры фирмы Intel(напримерPentium) и совместимые с ними процессоры других фирм.

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

Процессор содержит 8 регистров общего назначения (рис. 1.1), носящих мнемонические обозначения EAX, EBX, ECX и т. д. Все они имеют размер по четыре байта, т. е. могут хранить по одному целому числу типа intилиunsigned int.

Рис. 1.1. Регистры общего назначения

Для того чтобы программа могла работать с более короткими переменными (например, short– 2 байта илиchar– 1 байт), младшие половины регистров EAX, EBX, ECX и EDX имеют самостоятельные обозначения – AX, BX, CX и DX соответственно; при этом они, в свою очередь, еще разделены пополам с образованием регистров длиной всего 1 байт. Старшая половина (старший байт) регистра AX носит название AH (от high – старший), младший байт – AL (от low – младший). Аналогично построены имена остальных байтовых регистров.

Компилятор, преобразуя текст программы в машинные коды, активно использует регистры процессора для временного хранения операндов команд и результатов выполняемых операций. На рис. 1.2 показано, как может выглядеть простой фрагмент программы на языке С++ после компиляции. Видно, что компилятор выделил для хранения переменных xиyрегистры EAX и EDX, и в тот же регистр EDX поместил результат сложения. В дальнейшем по ходу программы этот результат может быть перенесен в память, а регистр EDX использован для выполнения других операций.

int x=0x12345678; mov EAX,12345678h

int y=0x11111111; mov EDX,11111111h

int z=x+y; add EDX,EAX

Рис. 1.2. Фрагмент программы и результат его компиляции

Особое значение имеют сегментные регистры процессора (рис. 1.3). Свое название они получили потому, что любая программа располагается в связных участках памяти, называемых сегментами.

Рис. 1.3. Сегментные регистры

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

Рис. 1.4. Сегменты программы и роль сегментных регистров

В сегментных регистрах хранится информация, позволяющая процессору определить, в каком месте памяти располагается тот или иной программный сегмент. Поскольку в программу обычно входят три сегмента, для обращения к ним используются три сегментных регистра. Регистр CS всегда служит для адресации сегмента команд, в регистре DS обычно хранится адрес сегмента данных, а регистр SS используется исключительно для работы со стеком. Остальные сегментные регистры используются по мере надобности для обращения, например, к системным полям памяти.

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

Смещение очередной команды, которую надлежит выполнять процессору, всегда находится в регистре-указателе команд EIP. Он не входит в состав регистров общего назначения (и, соответственно, не был показан на рис. 1.1), потому что не является программно адресуемым регистром, т. е. к нему нельзя напрямую обратиться из программы и изменить его значение. Содержимым регистра EIP управляет исключительно сам процессор: прочитав из памяти очередной байт команды, процессор увеличивает содержимое EIP на 1, чем и обеспечивается строго последовательное чтение байтов программы, находящейся в памяти. Поскольку при обращении к сегменту команд процессор использует сегментный регистр CS, содержимое пары регистров CSиEIP, которое обычно обозначается, как CS:EIP, в каждый момент времени характеризует то место, до которого дошла программа по ходу своего выполнения.

Текущее смещение в стеке всегда находится в регистре-указате­ле стека ESP. Поскольку адрес стека процессор определяет с помощью сегментного регистра SS, содержимое пары регистров SS:ESP характеризует то место стека, в котором находится последнее отправленное туда данное.

К сегменту данных процессор обращается обычно с помощью регистра DS; смещение же конкретной ячейки может находиться в этом случае в любом регистре общего назначения: EAX, EBX и других (за исключением, разумеется, ESP). Смещение может также входить непосредственно в код команды, т. е. храниться не в регистре, а в составе кода команды в памяти.

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

Другими флагами управляет сам процессор, устанавливая или сбрасывая их по результатам выполнения каждой команды. Если, например, в результате выполнения арифметической операции образовалось отрицательное число, устанавливается флаг знака SF; если получился нулевой результат, устанавливается флаг нуля ZF и т. д. Анализ флагов позволяет процессору выполнять операции сравнения и условных переходов. Содержимое регистра флагов отображается в отладчике, и программист имеет возможность определить состояние флагов в любой точке программы.