Изучение операционной системы Windows

Министерство образования и науки РФ

Федеральное агентство по образованию

Государственное образовательное учреждение высшего профессионального образования

«Ижевский государственный технический университет»

Факультет «Информатика и вычислительная техника»

Кафедра «Вычислительная техника»

 

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

«Изучение операционной системы Windows»

по курсу «Операционные системы»

для студентов специальности 23.01.00

«Вычислительные машины, комплексы, системы и сети»

 

Ижевск, 2011

Оглавление

 

Введение. 3

Цель работы.. 4

1 Процессы, задания и потоки. 5

1.1 Процессы. 5

1.2 Задания. 9

1.3 Потоки. 10

2. Управление памятью в операционных системах. 12

2.1 Память и отображения, виртуальное адресное пространство. 12

2.2 Виртуальное адресное пространство. 14

2.3 Распределение памяти статическими и динамическими разделами. 15

2.4 Разделы с фиксированными границами. 16

2.5 Разделы с подвижными границами. 18

2.6 Сегментная, страничная и сегментно-страничная организация памяти. 20

3 Динамически подключаемые библиотеки. 21

4 Обработка исключений. 29

4.1 Обработчики завершения. 29

4.2 Примеры использования обработчиков завершения. 30

5 Операции с окнами. 34

5.1 Оконные сообщения. 34

5.2 Очередь сообщений потока. 35

5.3 Посылка асинхронных сообщений в очередь потока. 35

5.4 Посылка синхронных сообщений окну. 36

6 Invoke. 43

Приложение 1. Справочник API-функций и сообщений Windows. 44

Приложение 2. Темы курсовой работы. 52

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

 


Введение

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

В первую очередь необходимо ответить на следующий вопрос: зачем нужен язык ассемблера? Самый простой и убедительный ответ на поставленный вопрос такой - затем, что это язык процессора и, следовательно, он будет нужен до тех пор, пока будут существовать процессоры. Более пространный ответ на данный вопрос содержал бы в себе рассуждение о том, что ассемблер может понадобиться для оптимизации кода программ, написания драйверов, трансляторов, программирования некоторых внешних устройств и т.д. Программирование на ассемблере дает ощущение власти над компьютером, а жажда власти - один из сильнейших инстинктов человека[2].

Что касается операционной системы Windows, то здесь, как ни странно это прозвучит для уха некоторых программистов, программировать на ассемблере гораздо легче, чем в операционной системе MS DOS. Программировать на ассемблере в Windows ничуть не сложнее чем на Си, и при этом получается компактный, эффективный и быстрый код. Работая с языками высокого уровня, мы теряем определенные алгоритмические навыки. И процесс заходит все дальше. Только ради повышения своего профессионального уровня стоит заниматься программированием на ассемблере[1].


Цель работы

 

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

Помимо разработки выбранной темы выполнение курсовой работы требует самостоятельного изучения 32-битного программирования на ассемблере.

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

Список тем для курсовой работы представлен в приложении 2.


1 Процессы, задания и потоки.

 

1.1 Процессы.

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

· объекта ядра, через который операционная система управляет процессом. Там же хранится статистическая информация о процессе;

· адресного пространства, в котором содержится код и данные всех EXE- и DLL модулей. Именно в нем находятся области памяти, динамически распределяемой для стеков потоков и других нужд.

Рис. 1.1. Операционная система выделяет потокам кванты времени по принципу карусели

Процессы инертны. Чтобы процесс что-нибудь выполнил, в нем нужно создать поток. Именно потоки отвечают за исполнение кода, содержащегося в адресном пространстве процесса. В принципе, один процесс может владеть несколькими потоками, и тогда они "одновременно" исполняют код в адресном пространстве процесса.

Для этого каждый поток должен располагать собственным набором регистров процессора и собственным стеком. В каждом процессе есть минимум один поток. Если бы у процесса не было ни одного потока, ему нечего было бы делать на этом свете, и система автоматически уничтожила бы его вместе с выделенным ему адресным пространством.

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

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

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

· 1-й параметр - указывает на имя запускаемой программы. Имя может содержать полный путь к программе.

· 2-й параметр - его значение зависит от того, является первый параметр NULL (0) или нет. Если первый параметр указывает на строку, то данный параметр трактуется как командная строка запуска (без имени программы). Если первый параметр равен NULL, то данный параметр рассматривается как командная строка, первый элемент которой представляет собой имя программы. Если путь к программе не указан, то функция CreateProcess осуществляет поиск программы по определенному алгоритму:

1. Поиск в каталоге, откуда была запущена программа.

2. Поиск в текущем каталоге.

3. Поиск в системном каталоге (можно получить через GetSystemDirectory). Обычно системным каталогом является C:WINDOWSSYSTEM.

4. Поиск в каталоге Windows (можно получить через GetWindowsDirectory). Обычно этим каталогом является C:WINDOWS.

5. Поиск в каталогах, перечисленных в параметре PATH окружения.

· 3-й и 4-й параметры. Используются для задания атрибутов доступа порождаемого процесса. Обычно полагают равным 0.

· 5-й параметр. Если этот параметр 0, то порождаемый процесс не наследует дескрипторы порождающего процесса, в противном случае порождаемый процесс наследует дескрипторы.

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

· 7-й параметр. Является указателем на буфер, содержащий параметры среды. Если параметр равен 0, то порождаемый процесс наследует параметры среды порождающего процесса.

· 8-й параметр. Задает текущее устройство и каталог для порождаемого процесса. Если параметр равен NULL, порождаемый процесс наследует текущее устройство и каталог порождающего процесса.

· 9-й параметр. Представляет указатель на структуру, которая содержит информацию об окне создаваемого процесса. Ниже будут рассмотрены поля этой структуры.

· 10-й параметр. Указывает на структуру, заполняемую при выполнении запуск приложения. Вот эта структура:

PROCINF STRUC

hProcess DD ? ; дескриптор созданного процесса.

hThread DD ? ; дескриптор главного потока нового процесса.

Idproc DD ? ; идентификатор созданного процесса.

idThr DD ? ; идентификатор главного потока нового процесса.

PROCINF ENDS

Основное отличие дескриптора от идентификатора заключается в том, что дескриптор уникален лишь в пределах данного процесса, идентификатор же является глобальной величиной. Посредством идентификатора может быть найдена база данных текущего процесса. У читателя, я думаю, сразу возникнет вопрос: а чем дескриптор приложения, который мы получаем при помощи функции GetModuleHandle, от только что упомянутых величин? Дескриптор приложения, или дескриптор модуля есть величина локальная, т.е. действующая в пределах данного процесса и, как правило, равная адресу загрузки модуля в виртуальное адресное пространство. Дескриптор модуля имеется у любого модуля, загруженного в память, в том числе и у подчиненных DLL-библиотек.

Рассмотрим теперь структуру, на которую указывает 9-й параметр функции CreateProcess. Вот эта структура:

 

STARTUP STRUC

cb DD 0

lpReserved DD 0

lpDesktop DD 0

lpTitle DD 0

dwX DD 0

dwY DD 0

dwXSize DD 0

dwYSize DD 0

dwXCountChars DD 0

dwYCountChars DD 0

dwFillAttribute DD 0

dwFlags DD 0

wShowWindow DW 0

cbReserved2 DW 0

lpReserved2 DD 0

hStdInput DD 0

hStdOutput DD 0

hStdError DD 0

STARTUP ENDS

 

Итак, разберем смысл полей этой структуры.

cb - размер данной структуры в байтах. Заполняется обязательно.

lpReserved - резерв, должно быть равно нулю.

lpDesktop - имя рабочего стола (и рабочей станции). Имеет смысл только для Windows NT.

lpTitle - название окна для консольных приложений, создающих свое окно. Для остальных приложений должно быть равно 0.

dwX - координата X левого верхнего угла окна.

dwY - координата Y левого верхнего угла окна.

dwXSize - размер окна по X.

dwYSize - размер окна по Y.

dwXCountChars - размер буфера консоли по X.

dwYCountChars - размер буфера консоли по Y.

dwFillAttribute - начальный цвет текста. Имеет значение только для консольных приложений.

dwFlags - флаг значения полей. Вот значение этого флага.

 

Макро-значение флага Значение константы Смысл значения
STARTF_USESHOWWINDOW 1h Разрешить поле dwShowWindow
STARTF_USESIZE 2h Разрешить dwXSize и dwYSize
STARTF_USEPOSITI0N 4h Разрешить dwX и dwY
STARTF_USECOUNTCHARS 8h Разрешить dwXCountChars и dwYCountChars
STARTF_USEFILLATTR1BUTE 10h Разрешить dwFillAttribute
STARTF_FORCEONFEEDBACK 40h Включить возврат курсора
STARTF_FORCEOFFFEEDBACK 80h Выключить возврат курсора
STARTF_USESTDHANDLES 100h Разрешить hStdInput

 

wShowWindow - определяет способ отображения окна.

cbReserved2 - резерв, должно быть равно 0.

hStdInput - дескриптор ввода (для консоли).

hStdOutput - дескриптор вывода (для консоли).

hStdError - дескриптор вывода сообщения об ошибке (для консоли).

 

 

1.2 Задания.

Группу процессов зачастую нужно рассматривать как единую сущность. Например, когда Вы командуете Microsoft Developer Studio собрать проект, он порождает процесс Ct.exe, а тот в свою очередь может создать другие процессы (скажем, для дополнительных проходов компилятора). Но, если Вы пожелаете прервать сборку, Developer Studio должен каким-то образом завершить C1.exe и все его дочерние процессы. Решение этой простой (и распространенной) проблемы в Windows было весьма затруднительно, поскольку она не отслеживает родственные связи между процессами. В частности, выполнение дочерних процессов продолжается даже после завершения родительского.

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

В Windows 2000 введен новый объект ядра — задание job. Он позволяет группировать процессы и помещать их в нечто вроде песочницы, которая определенным образом ограничивает их действия. Относитесь к этому объекту как к контейнеру процессов. Кстати, очень полезно создавать задание и с одним процессом — это позволяет налагать на процесс- ограничения, которые иначе указать нельзя.

Создание нового объекта ядра «задание» выполняется вызовом:

HANDLE CreateJobObject( PSECURITY_ATTRIBUTES psa, PCTSTR pszName);

Как и любая функция, создающая объекты ядра, CreateJobObject принимает в первом параметре информацию о защите и сообщает системе, должна ли она вернуть наследуемый описатель. Параметр pszName позволяет присвоить заданию имя, что бы к нему могли обращаться другие процессы через функцию OpenJobObject.

HANDLE OpenJobObject( DWORD dwDesiredAccess, BOOL bInheritHandle, PCTSTR pszName);

Закончив работу с объектом-заданием, закройте его описатель, вызвав, как всегда, CloseHandle. Именно так я и делаю в конце своей функции StartRestrictedProcess. Имейте в виду, что закрытие объекта-задания не приводит к автоматическому завершению всех его процессов. На самом деле этот объект просто помечается как подлежащий разрушению, и система уничтожает его только после завершения всех включенных в него процессов

Потоки.

В главе 4.1 сказано, что процесс фактически состоит из двух компонентов объекта ядра "процесс" и адресного пространства так вот, любой… · объекта ядра, через который операционная система управляет потоком. Там же… · стека потока, который содержит параметры всех функций и локальные переменные, необходимые потоку для выполнения…

Fuction1

DWORD Function1() { DWORD dwTemp; // 1 Что-то делаем здесь __try { // 2. Запрашиваем разрешение на доступ // к защищенным данным, а… _finally { // 3 Даем и другим попользоваться защищенными данными ReleaseSemaphore(g_hSem, 1, NULL); }

Funcion2

DWORD Funcion2() { DWORD dwTemp;

Function3

DWORD Function3() { DWORD dwTemp;

Литература

1. Голубь Н.Г. Искусство программирования на ассемблере. Лекции и упражнения. – СПб.: ООО “ДиаСофтЮп”, 2002.

2. Зубков С.В. Assembler для DOS, Windows и Unix. – М.: ДМКПресс, 2000 (2002,2003).

3. Пирогов В.Ю. Ассемблер для Windows. – М.: Издатель Молгачева С.В., 2002.

4. Юров В.И. Assembler, практикум. – СПб.: Питер, 2002.

5. Ирвин К. Язык ассемблера для процессоров Intel, - М.: Издат. Дом “Вильямс”, 2002.