Партнерка на США и Канаду по недвижимости, выплаты в крипто

  • 30% recurring commission
  • Выплаты в USDT
  • Вывод каждую неделю
  • Комиссия до 5 лет за каждого referral

Московский государственный университет путей сообщения (МИИТ)

___________________________________________________________

Кафедра “Автоматизированные системы управления”

В. А. ВАРФОЛОМЕЕВ

СИСТЕМНЫЕ ВЫЗОВЫ

Рекомендовано редакционно-издательским советом университета в качестве методических указаний к лабораторным работам по дисциплине "Операционные системы"

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

"Автоматизированные системы обработки информации и управления"

и "Информационные системы и технологии"

М О С К В А - 2006

УДК 681.3.066

В18

Варфоломеев вызовы. Методические указания к лабораторным работам по дисциплине "Операционные системы". — М.: МИИТ, 2006 — 27 с.

В методических указаниях представлены сведения об организации системных вызовов в операционных системах MS DOS и Windows, описаны средства и интерфейсы прикладного программирования, используемые при создании программ на Ассемблере и языках высокого уровня.

Ó Московский государственный

университет путей сообщения

(МИИТ), 2006

СОДЕРЖАНИЕ

1. ВВЕДЕНИЕ..................................................................................................... 3

2. ОРГАНИЗАЦИЯ СИСТЕМНЫХ ВЫЗОВОВ В ОС MS DOS..................... 4

2.1. Механизм программных прерываний MS DOS.................................... 4

2.2. Средства для работы с программными прерываниями в системе программирования Турбо Паскаль................................................................ 7

2.3. Рабочее задание...................................................................................... 10

НЕ нашли? Не то? Что вы ищете?

2.4. Контрольные вопросы............................................................................ 11

3. ОРГАНИЗАЦИЯ СИСТЕМНЫХ ВЫЗОВОВ В ОС WINDOWS.............. 14

3.1. Интерфейс прикладного программирования Win32 API................... 14

3.2. Типы данных, применяемые в Win32 API........................................... 14

3.3. Использование функций Win32 API при программировании на языке С/С++ 17

3.4. Использование функций Win32 API при программировании на Ассемблере 20

3.5. Рабочее задание...................................................................................... 22

3.6. Контрольные вопросы............................................................................ 26

ЛИТЕРАТУРА.................................................................................................. 26

ПРИЛОЖЕНИЕ. Настройка параметров проекта консольного приложения Win32 в среде Borland C++............................................................................................ 27

ЦЕЛЬ РАБОТЫ: практическое изучение механизма и средств организации системных вызовов в операционной системе MS DOS при разработке прикладного программного обеспечения на ассемблере и Турбо Паскале.

1. ВВЕДЕНИЕ

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

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

Реализация системных вызовов осуществляется в операционной системе с помощью специального механизма, получившего название интерфейс прикладного программирования (Application Programming Interface или API).

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

2. ОРГАНИЗАЦИЯ СИСТЕМНЫХ ВЫЗОВОВ В ОС MS DOS

2.1. Механизм программных прерываний MS DOS

В операционной системе MS DOS системные вызовы производятся с использованием так называемых «программных прерываний». Программными прерываниями называют готовые процедуры в составе базовой системы ввода-вывода (BIOS) и загружаемой части операционной системы (DOS), которые могут вызываться программистом с помощью специальной команды INT. Каждая из таких процедур-прерываний выполняет определенную функцию (или несколько функций) ОС и ей присвоен уникальный номер в виде целого числа в диапазоне 0-255. Программные прерывания с номерами 0-31 связаны с процедурами BIOS, а остальные входят в состав собственно DOS.

Например, прерываниеh) – поддерживает функции работы с видеотерминалом, прерываниеh) обслуживает вывод на принтер. Особое место в ряду программных прерываний DOS занимает прерываниеh), вызов которого называют "обращением к DOS". Это прерывание обеспечивает доступ к более чем 100 основным функциям операционной системы, включая управление файловой системой, управление памятью и выполнением программ и ряд других. Подробное описание всех прерываний и реализуемых ими функций приводится в документации и специальных справочниках.

Интерфейс прикладного программирования MS DOS устанавливает определенный механизм организации системных вызовов на основе программных прерываний и включает:

-  команду вызова программного прерывания INT;

-  команду возврата из программного прерывания IRET;

-  передачу входных и выходных параметров через регистры процессора.

Команда вызова программного прерывания имеет формат:

INT номер_прерывания

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

По типу команда INT представляет собой команду передачи управления с возвратом, действующую почти так же, как команда CALL, сохраняя в стеке пару регистров CS:IP в качестве адреса возврата. Однако в отличие от CALL команда INT сохраняет в стеке регистр флагов. Таким образом, при использовании команды INT программист должен предусмотреть наличие сегмента стека подходящего размера для записи в него значений сохраняемых регистров.

Команда возврата из программного прерывания IRET параметров не имеет и, выталкивая из стека сохраненные командой INT регистры, обеспечивает продолжение выполнения приложения в точке вызова прерывания.

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

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

Например, для вывода строковых данных на экран предназначена функция 9 прерывания 21h. В качестве входных данных при использовании этой функции необходимо указать адрес размещения в памяти выводимой строки, записав его в регистровую пару DS:DX. Выводимая строка обязательно должна завершаться символом ‘$’. Выходных данных у функции 9 нет.

.data

str db ‘Hello, darling!$’ ; выводимая строка

.code

mov ax,@data

mov ds, ax ;сформировали DS

mov ah,9 ;номер функции - в AH

mov dx, offset str ;смещение строки в текущем

;сегменте данных - в DX

int 21h ;вызов функции вывода на экран

. . .

Результатом вызова функции 9 прерывания 21h будет появление на экране выводимой строки.

Рассмотрим еще один пример. Для открытия существующего файла предназначена функция 3Dh прерывания 21h. В качестве входных данных необходимо записать режим доступа к файлу в регистр AL (1 – для чтения, 2 – для записи, 3 – для чтения и записи), а в регистровой паре DS:DX – указать адрес строки с полным именем открываемого файла в формате ASCIIZ (т. е. в конце строки необходимо записать символ с кодом 0). В качестве выходных данных прерывание формирует: флаг переноса CF (0 – функция выполнена успешно, 1 – ошибка) и регистр AX (если нет ошибки – содержит идентификатор (номер) файла, в противном случае возвращает код ошибки: 2 – файл не найден, 3 – путь не найден, 5 – доступ запрещен). В приведенном ниже тексте производится открытие файла C:\TMP\MYPROG. PAS в режиме чтения:

.data

fname db ‘C:\TMP\MYPROG. PAS!’,0 ;имя файла

mes1 db ‘Файл открыт!$’

mes2 db ‘Файл не найден$’

mes3 db ‘Путь не найден$’

mes4 db ‘Доступ запрещен$’

.code

mov ax,@data

mov ds, ax ;сформировали DS

mov ah,3dh ;номер функции - в AH

mov al,1 ;доступ для чтения

mov dx, offset fname ;адрес строки с именем файла–в DX

int 21h ;вызов функции открытия файла

jnc ok ;если CF=0 – файл открыт

;обработка ошибки

cmp ax,1 ;если ax<>1 – дальше (e2)

jne e2

mov ah,9 ;если ax=1

mov dx, offset mes2

int 21h ;вывод сообщения об ошибке(mes2)

jmp quit

e2: ... ;вывод других сообщений(mes3, mes4)

. . .

jmp quit

ok: mov ah,9

mov dx, offset mes1

int 21h ;вывод сообщения об успешном завершении

quit: …

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

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

Одним из таких средств является включенная в состав модуля DOS Турбо-Паскаль процедура Intr, предназначенная для обращения к программным прерываниям DOS и BIOS. Процедура имеет формат:

Intr(НомерПрерывания:byte;

VarРегистроваяПеременная:registers)

В качестве параметров процедуры используются номер вызываемого прерывания (целое число в диапазоне 0..255) и специальная регистровая переменная, имеющая стандартизированный тип registers:

type registers=record

case integer of

0: (AX, BX, CX, DX, BP, SI, DS, ES, Flags:word);

1: (AL, AH, BL, BH, CL, CH, DL, DH;byte);

end;

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

var regs: registers;

то оператор regs. DX:=0 обеспечивает обнуление содержимого регистра DX; а оператор regs. AH:=regs. AL содержимому старшего байта (AH) регистра AX присваивает значение младшего байта (AL) того же регистра.

Использование процедуры Intr и регистровой переменной предполагает включение в программу предложения: uses DOS.

Рассмотрим, как выглядит на Паскале программа, представленная на стр. 7.

program example;

uses DOS;

var R: reqisters;

Fname: string;

begin

Fname:=‘C:\TMP\MYPROG. PAS!’+Chr(0);

{Формирование входных данных}

R. AH:=$3D; {номер функции}

R. AL:=1; {тип доступа}

R. DS:=Seg(Fname); {адрес сегмента строки}

R. DX:=Ofs(Fname[1]);{смещение1-го символа строки}

{Вызов программного прерывания 21h}

Intr ($21,R);

{Анализ выходных данных и вывод сообщений}

{Учитываем, что флаг переноса размещается в младшем разряде регистра флагов!}

if (R. Flags and 1) = 0 then

writeln(‘Файл открыт!’);

else begin

write(‘Ошибка: ’);

case R. AX of

1: writeln(‘Файл не найден!’);

2: writeln(‘Путь не найден!’);

5: writeln(‘Доступ запрещен’);

else writeln(‘код’,R. AX);

end;

end;

end.

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

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

Seg(<имя переменной>)- возвращает значение сегментной части адреса переменной;

Ofs(<имя переменной>)- возвращает значение смещения для указанной переменной.

2. Передача строковых данных при выполнении системных вызовов из программ, написанных на Паскале, связана с решением проблемы различий внутреннего представления текстовых строк в Турбо Паскале и DOS.

В Турбо Паскале вместе со строковой переменной хранится ее фактический размер (количество символов), который записывается в первый байт переменной. Например, строковая переменная S:string='DOS' будет представлена в памяти следующими байтами: S[0]=03h (количество символов), S[1]='D', S[2]='0', S[3]='S':

03h

‘D’

‘O’

‘S’

В DOS используется формат, получивший название ASCIIZ, при котором размер строки не фиксируется. Вместо этого указывается ограничитель строки в виде байта с кодом 0, помещаемый за последним значимым символом (S[0]='D', S[1]='0', S[2]='S',S[3]=00h):

‘D’

‘O’

‘S’

00h

Поэтому при передаче указателя на строку, содержание которой используется в прерывании, следует дополнить строку нулевым байтом справа (S:=S+chr(0)) и сформировать DS:=Seg(S) и DX:=Ofs(S[1]).

Следует отметить, что программист, пишущий программы на Паскале (как и на других языках высокого уровня) как правило, имеет возможность использовать системные функции, не прибегая к системным вызовам. Эта возможность реализована в виде готовых процедур и функций, входящих в стандартные библиотеки (модули) Турбо Паскаля. Например, определить текущую системную дату можно не только с помощью функции 2Ah прерывания 21h, но и используя функцию Турбо Паскаля

GetDate(Var Year, Month, Day, DayofWeek:Word).

2.3. Рабочее задание

1. Для заданного варианта (см. табл. 1) написать и отладить две программы, обеспечивающие реализацию заданных системных вызовов функций программного прерывания 21h DOS. По указанию преподавателя одна из программ должна быть написана на ассемблере, другая на Паскале. Каждую из программ следует представить в виде EXE-файла и продемонстрировать их работу, запуская из командной строки. Не рекомендуется использовать в программах функции очистки экрана и ожидания нажатия на клавишу.

2. В программах на ассемблере входные данные задавать непосредственно в тексте программы, а выходные данные и сообщения выводить на экран с использованием функций 2 и/или 9 прерывания 21h. Разрешается использовать макросы и процедуры ввода-вывода из стандартной библиотеки ассемблера (IO. ASM, IO. PROC).

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

Например, если вы создали программу удаления файла mydel. exe (функция 41h), то имя удаляемого файла (например, badfile. txt) необходимо задавать следующим образом:

A:\>mydel. exe badfile. txt

B Турбо Паскале существует две функции для работы с командной строкой:

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

Функция ParamStr(i)- возвращает значение i-го параметра, представленное в строковом виде.

Для примера, приведенного выше, функция ParamCount возвратит значение 1, а функция ParamStr(1)- строку ‘badfile. txt’

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

3. Там, где это необходимо, производить анализ признака ошибки (флаг CF) и кода ошибки (регистр AL) используемой системной функции с выдачей соответствующих сообщений.

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

5. Отчет по лабораторной работе должен содержать: текст задания, блок схемы программ, распечатки текстов программ и результатов их работы.

2.4. Контрольные вопросы

1.  Раскройте смысл понятий "системный вызов" и “интерфейс прикладного программирования”.

2.  Дайте определение и приведите примеры программных прерываний в ОС MS DOS.

3.  Что такое функция программного прерывания? Как задается требуемая функция при вызове прерывания 21h?

4.  Как передаются входные и выходные параметры при реализации системных вызовов в MS DOS?

5.  Объясните средства, используемые при вызове программных прерываний в среде Турбо Паскаль.

6.  Каковы особенности представления строковых данных в прерываниях MS DOS и что такое ASCIIZ-строка?

7.  Как формируются и передаются указатели на строковые переменные при организации системных вызовов в программах на Ассемблере и Турбо Паскале?

8.  Как вы думаете, почему команда INT производит сохранение регистра флагов?

9.  При вызове некоторых системных функций признаком ошибки выполнения служит устанавливаемое значение флага переноса CF=1. Как проверить значение флага переноса в программах на Ассемблере и Турбо Паскале?

Таблица 1. Описание функций прерывания 21h DOS (варианты заданий)

Номер функ-ции

Назначение функции

Входные данные

Выходные данные

1

2Аh

Определить текущую дату

Номер функции (АН)

Год (СХ), месяц (DH), день(DL), день недели (AL: 0-вс, 1-пн и т. д.)

39h

Создать каталог

Номер функции (АН), указатель на ASCIIZ строку с именем каталога (DS:DX)

Признак ошибки (СF=1); код ошибки (AL): 3-путь не найден, 5-ошибка доступа

2

2Вh

Установить текущую дату

Номер функции (АН), год (СХ): 1980..2099, месяц (DH),день(DL)

Код завершения (AL): 0- дата установлена, FFh - введена несуществующая дата

47h

Определить текущий каталог

Номер функции (АН), номер диска (DL): 0 - текущий, 1-А и т. д., указатель на область получения результата (DS:SI)

Признак ошибки (СF=1); код ошибки (AL): 0Fh - указан несуществующий диск

3

2Сh

Определить текущее время

Номер функции (АН)

Часы (СН), минуты (CL), секунды (DН), сотые доли секунды (DL)

3Bh

Задать текущий каталог

Номер функции (AН), указатель на ASCIIZ строку с именем каталога (DS:DX)

Признак ошибки (СF=1); код ошибки (AL): 3 –путь не найден

4

2Dh

Задать текущее время

Номер функции (АН), часы (СН), минуты (CL), секунды (DН), сотые доли секунды (DL)

Код завершения (AL): 0- время установлено, FFh - введено несуществующее время

3Ah

Удалить каталог

Номер функции (AН), указатель на ASCIIZ строку с именем каталога (DS:DX)

Признак ошибки (СF=1); код ошибки (AL): 3-путь не найден, 5-ошибка доступа, 10- попытка удалить текущий каталог

5

0Еh

Задать текущий диск

Номер функции (АН), номер диска (DL): 0 - А, 1-В и т. д.

Количество дисковых устройств в системе (AL)

41h

Удалить файл

Номер функции (AН), указатель на ASCIIZ строку с именем файла (DS:DX)

Признак ошибки (СF=1); код ошибки (AL): 2- файл не найден, 3-путь не найден, 5-доступ запрещен

6

19h

Определить текущий диск

Номер функции (АН)

Номер диска (AL): 0-А, 1-В, 2-С и т. д.

4Еh

Поиск файла

Номер функции (AН), атрибут файла (СХ, принять =0), указатель на ASCIIZ строку с именем файла (DS:DX)

Признак ошибки (СF=1); код ошибки (AL): 2 – файл не найден, 3- путь не найден, 12- неправильный режим доступа

7

30h

Получить номер версии DOS

Номер функции (АН)

Старшая (AL) и младшая (АН) цифры номера версии

56h

Переименовать файл

Номер функции (AН), указатель на ASCIIZ строку со старым именем файла (DS:DX), указатель на ASCIIZ строку с новым именем файла (ЕS:DI)

Признак ошибки (СF=1); код ошибки (AL): 2 – файл не найден, 3-путь не найден, 5-доступ запрещен

8

36h

Получить объем свободного пространства на диске

Номер функции (АН), номер диска (DL): 0 - текущий диск, 1-А, 2-В и т. д.

AX - число секторов в кластере (если FFFFh - ошибка), BX - число свободных кластеров, CX - число байт в секторе.

Объем =AX*CX*BX (в байтах)

5Bh

Создать новый файл

Номер функции (AН), атрибуты файла (СХ=0), указатель на ASCIIZ строку с именем файла (DS:DX)

Признак ошибки (СF=1); код ошибки (AL): 2 – файл не найден, 3-путь не найден, 5-доступ запрещен

9

43h

Определить атрибуты защиты файла

Номер функции (AН), AL=0, указатель на ASCIIZ строку с именем файла (DS:DX)

Признак ошибки (СF=1); код ошибки (AL): 2 – файл не найден, 3-путь не найден, 5-доступ запрещен

Атрибуты файла (СХ: 0-й бит - только чтение, 1-й бит - скрытый, 2-й бит - системный),

5Аh

Создать временный файл

Номер функции (AН), атрибуты файла (СХ=0), указатель на строку, содержащую полученное имя файла (DS:DX)

Признак ошибки (СF=1); код ошибки (AL): 2 – файл не найден, 3-путь не найден, 5-доступ запрещен

10

4Dh

Определить код возврата последнего завершившегося процесса

Номер функции (АН)

Способ завершения (AH): 0-нормальный, 1-Ctrl-Break, 2- критическая ошибка, 3-осталась в памяти; код возврата (AL)

43h

Установить атрибуты защиты файла

Номер функции (AН), AL=1, атрибуты файла (СХ: 0-й бит - только чтение, 1-й бит - скрытый, 2-й бит - системный), указатель на ASCIIZ строку с именем файла (DS:DX)

Признак ошибки (СF=1); код ошибки (AL): 2 – файл не найден, 3-путь не найден, 5-доступ запрещен

3. ОРГАНИЗАЦИЯ СИСТЕМНЫХ ВЫЗОВОВ В ОС WINDOWS

3.1. Интерфейс прикладного программирования Win32 API

Системные вызовы в операционных системах семейства MS Windows, начиная с версии Windows 95, реализованы на основе интерфейса прикладного программирования, получившего название «Win32 API». Под Win32 API понимают совокупность функций, предоставляющих программисту возможность создавать приложения для операционных систем Windows 95/98/ME/NT/2000/XP, базирующихся на использовании 32-х разрядных процессоров Intel, начиная с i386 (и его аналогов). При этом, несмотря на различия между версиями операционной системы, основное множество функций API для них одно и то же. Большинство функций API доступны для вызова из программ на любом исходном языке программирования (в том числе и на ассемблере).

Функции API хранятся в так называемых динамических библиотеках (Dynamic Link Library), которые размещаются в файлах с расширением dll, таких как kernel. dll, user32.dll, gdi32.dll и некоторых других. Эти файлы размещаются в системном каталоге Windows (обычно C:\WINDOWS\SYSTEM).

Фактически функции API для Windows играют ту же самую роль, что и программные прерывания для MS DOS, однако вызов функций API производится более простым и привычным для программиста способом - через символические имена. Например, функция удаления файла вызывается по имени DeleteFile, функция установки системного времени - SetSystemTime и т. д.

При программировании на ассемблере передача параметров функциям Win32 осуществляется не через регистры процессора, а через стек. Результат работы функции API помещается в регистр EAX. Более сложные типы данных возвращаются через адреса памяти (указатели), передаваемые функции в виде входных параметров.

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

Подробное описание функций WIN32 API и их параметров можно найти в литературе [3-6], в файле справки win32.hlp (обычно размешается в каталоге C:\Program Files\Borland Shared\MSHelp\win32.hlp), а также на многочисленных сайтах Интернет (например, msdn. /library).

3.2. Типы данных, применяемые в Win32 API

Помимо совокупности функций API Windows поддерживает целый ряд специальных типов данных (например, HINSTANCE, HWND, LPSTR и т. п.), не совпадающих со стандартными типами, определенными в основных языках программирования. Использование типов, специально «изобретенных» для Windows, упрощает написание программы, делает ее более ясной и читабельной. Некоторые простейшие типы данных Windows приведены в таблице 2.

Таблица 2. Основные типы данных Windows

Тип

Определение С

Длина, б

Описание

BOOL

int

4

Логическая переменная, принимающая значения TRUE (ИСТИНА) или FALSE (ЛОЖЬ).

BYTE

unsigned char

1

Байтовое число без знака

DWORD

unsigned long

4

32-разрядное целое число без знака.

LONG

signed long

4

32-разрядное целое число со знаком.

UINT

unsigned int

4

32-разрядное целое число без знака.

LPSTR

char far *

4

Дальний указатель на строку символов с завершающим нулевым символом

WORD

unsigned short

2

16-разрядное целое число без знака.

HANDLE

unsigned long

4

Дескриптор объекта (четырехбайтовое целое число)

Особую роль в Windows играют специальные переменные - дескрипторы (хэндлы). Дескрипторы – это уникальные целые четырехбайтовые числа, применяемые для идентификации объектов, которые создаются и используются в системе. Большинство дескрипторов являются значениями индексов внутренних таблиц, которые Windows использует для доступа и управления своими объектами. Прикладная программа может получить или изменить данные, связанные с каким-либо объектом, только с помощью вызова функции API с указанием дескриптора соответствующего объекта. Для каждого вида объектов используется специальный дескрипторный тип, например – HWND – дескриптор окна, HDC - дескриптор контекста устройства, HFILE – дескриптор открытого файла, HLOCAL - дескриптор локального блока памяти и т. д. Общим для всех дескрипторов является наличие в описании первого символа “H”.

Помимо типов данных, представленных в таблице 2, в Windows существуют и другие, в том числе более сложные типы (структуры). Например, тип MSG представляет структуру, описывающую параметры выводимого на экран сообщения, а тип WNDCLASS – параметры окна приложения. В качестве примера рассмотрим структуру SYSTEMTIME – системное время, описываемую следующим образом:

typedef struct _SYSTEMTIME {
WORD wYear; //текущий год
WORD wMonth; //номер месяца (январь-1, и т. д.)
WORD wDayOfWeek; //день недели (вск-0, пн-1, …)
WORD wDay; //день месяца
WORD wHour; //час
WORD wMinute; //минуты
WORD wSecond; //секунды
WORD wMilliseconds; //миллисекунды

} SYSTEMTIME,
*PSYSTEMTIME;

При написании программ на языке C/C++ типы данных Windows и прототипы функций API определяются во включаемых заголовочных файлах Win32, основным из которых является файл windows. h. Помимо типов данных в этом файле определено более 1000 констант. Имена констант стандартизированы: они пишутся заглавными буквами и имеют вид «префикс_пояснение». Например, IDC_RESOURCE, CS_HREDRAW, WM_QUIT, DRIVE_UNKNOWN и т. п. Константы также широко применяются при установке значений параметров вызова функций API и при проверке результатов их выполнения.

Одной из особенностей программ, написанных для Windows, является использование так называемой «венгерской нотации» при записи имен переменных. Суть этой системы можно определить следующими правилами:

-  каждое слово в имени переменной пишется с прописной буквы и слитно с другими словами. Например, идентификатор для обозначения какой-то переменной может выглядеть следующим образом - MyVariable, YourVariable, VariableForSavingAnotherVariable и т. п.;

-  каждый идентификатор предваряется несколькими строчными символами, определяющими его тип. Например, целочисленная переменная MyVariable будет выглядеть как nMyVariable (n – общепринятый префикс для целочисленных переменных), символьная (char) переменная YourVariable превращается в cYourVariable. Указатель на строку символов, заканчивающуюся нулевым байтом, следут записать lpszVariableForSavingAnotlierVariable (lpsz - сокращение от Long Point то String with Zero). Как видим, префикс указателя может комбинироваться с другими префиксами. Примеры подобных префиксов приведены в таблице 3.

Таблица 3. Префиксы, применяемые в венгерской нотации

Префикс

Тип данных

Префикс

Тип данных

by

BYTE (unsigned char)

w

WORD (unsigned int)

c

char

dw

DWORD (unsigned long)

i

int

h

HANDLE

n

int или short

s

string

l

LONG (long)

sz

string с завершающим нулем

lp

far* (дальний указатель)

u

UINT (unsigned int)

Применение венгерской нотации не является обязательным, но позволяет упростить процесс чтения и понимания программ, а также делает переменные в некотором смысле самоопределенными - имя переменной определяется ее типом. Отметим также, что параметры функций API представлены в документации «по-венгерски».

3.3. Использование функций Win32 API при программировании на языке С/С++

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

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

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

Для применения функций Win32 API и предопределенных типов данных Windows С-программа должна использовать директивы препроцессора, включающие в процесс компиляции файл windows. h (и, возможно, другие файлы):

#include "windows. h"

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

BOOL GetVolumeInformation(

LPCTSTR lpRootPathName,

LPTSTR lpVolumeNameBuffer,

DWORD nVolumeNameSize,

LPDWORD lpVolumeSerialNumber,

LPDWORD lpMaximumComponentLength,

LPDWORD lpFileSystemFlags,

LPTSTR lpFileSystemNameBuffer,

DWORD nFileSystemNameSize);

Как видим, функция возвращает значение типа BOOL и имеет 8 параметров:

lpRootPpathName – входной параметр (in), являющийся указателем на строку символов, содержащую имя корневого каталога диска. Необходимо, чтобы строка завершалась символом / (backslash). Если указать значение NULL, то будет выбран текущий диск.

lpVolumeNameBuffer – выходной параметр (out), являющийся указателем на буфер, куда будет помещено имя диска.

nVolumeNameSize – входной параметр (in), содержащий длину буфера в символах.

lpVolumeSerialNumber – выходной параметр (out), являющийся указателем на переменную, содержащую серийный номер диска.

lpMaximumComponentLength – выходной параметр (out), являющийся указателем на переменную, содержащую максимальное количество символов в имени файла для данной файловой системы.,

lpFileSystemFlags – выходной параметр (out), являющийся указателем на переменную, содержащую флаги, характеризующие файловую систему. Возможные значения флагов представлены в виде набора констант с префиксом FILE_, которые в данном примере не рассматриваются.

lpFileSystemNameBuffer – выходной параметр (out), являющийся указателем на буфер, куда будет помещено имя файловой системы (возможные имена: FAT, NTFS и т. п.).

nFileSystemNameSize - входной параметр (in), содержащий длину буфера имени файловой системы в символах.

Возвращаемое значение типа BOOL:

0 - если по какой-либо причине информация о диске не может быть представлена (например, ошибка в исходных данных);

≠0 - в противном случае.

// Пример использования функции GetVolumeInformation

//

#include "windows. h"

#include "iostream. h"

void main()

{

char NameBuffer[MAX_PATH];

char SysNameBuffer[MAX_PATH];

DWORD VSNumber;

DWORD MCLength;

DWORD FileSF;

if (GetVolumeInformation("C:\\",NameBuffer,

sizeof(NameBuffer),&VSNumber,&MCLength,&FileSF,

SysNameBuffer, sizeof(SysNameBuffer)))

{

cout << NameBuffer << endl;

cout << SysNameBuffer << endl;

cout << VSNumber << endl;

}

else cout << “Ошибка” << endl;

}

В результате выполнения этой программы в консольном окне появится, например, следующее:

WIN98

FAT

Press any key to continue

Обратите внимание, что указатели типа LPSTR могут объявляться как char, а указатели на числовые переменные при передаче параметров записываются с помощью оператора &

3.4. Использование функций Win32 API при программировании на Ассемблере

При написании приложений, использующих вызовы функций Win32 API, на языке ассемблера следует руководствоваться следующими правилами:

·  Функции Win32 API выполняются в защищенном режиме процессора (прерывания DOS - в реальном или виртуальном режиме), поэтому при использовании функций Win32 API программа должна включать директиву.386

·  Модель памяти для Win32 приложений задается директивой. model flat

·  Вызов функций API производится с помощью команды call по адресу, задаваемому именем функции (например, call MessageBoxA). Прототипы функций размещаются в файле Import32.lib, называемом библиотекой импорта. Имена всех используемых системных функций описываются как внешние с помощью директивы extrn

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

·  Значение каждой функции возвращается в регистре EAX. Если функция возвращает структуру данных, то регистр EAX содержит код возврата, а адрес структуры необходимо передать функции как параметр.

Для пояснения указанных правил, рассмотрим пример программы, выводящей сообщение во всплывающее информационное окно, с помощью функции MessageBoxA, имеющей следующие параметры:

HWND hParentWnd, // дескриптор родительского окна
LPSTR lpszText, // текст сообщения

LPSTR lpsz Caption, // заголовок окна

DWORD nType // стиль окна

.386 ;тип процессора (i386 или старше)

;использование защищенного режима
.model flat, STDCALL ; модель памяти для Win32
;Описание используемых внешних процедур Win32 API:
extrn MessageBoxA:proc ;функция вывода сообщения
extrn ExitProcess:proc ;функция завершения процесса

.data ;сегмент данных
title db 'Изучаем Win32 API',0 ;заголовок окна
message db 'Это я, Bill Gates!',0 ;текст сообщения

.code ;сегмент кода
start:
push 40h ;стиль окна - одна кнопка "OK"

;и пиктограмма "i"

push offset title ;адрес строки с заголовком
push offset message ;адрес строки с сообщением
push 0 ;дескриптор программы-владельца

;создаваемого окна

call MessageBoxA ;вызов функции вывода сообщения

push 0 ;код завершения программы
call ExitProcess ;вызов функции завершения программы

end Start ;конец сегмента кода

Анализируя текст приведенного выше примера, обратите внимание на следующие обстоятельства:

·  используемые в приложении функции Win32 API перечисляются как внешние (директива extrn);

·  имена функций Win32 обычно дополняются символом A, например RemoveDirectoryA, GetComputerNameA (это означает, что применяются версии функций, использующие для представления символов кодировку ANSI);

·  названия функций записываются строго с соблюдением регистра (прописные и строчные буквы);

·  нельзя нарушать установленную последовательность записи параметров в стек;

·  типы параметров должны соответствовать указанным в прототипе функции;

·  указатели (адреса) параметров формируются с помощью оператора offset.

3.5. Рабочее задание

1.  Для заданного варианта (табл. 4) написать и отладить консольную программу на языке C и программу на языке ассемблера, обеспечивающую реализацию указанной функции Win32 API. В таблице символами [in] помечены параметры, содержащие исходные данные, а символами [out] – результаты работы вызываемой функции. Все входные параметры должны получить значения! Типы LPTSTR и LPCTSTR считать эквивалентными типу LPSTR. Программы представить в виде исполнимых (exe) файлов и продемонстрировать их работу запуском из командной строки.

2.  Программу на языке С организовать таким образом, чтобы ввод данных пользователя осуществлялся через командную строку. B языке C для работы с командной строкой используются параметры функции main():

main (int argc, char *argv[]);

где argc принимает значения числа параметров, записанных в командной строке при запуске программы, включая имя программы;

argv - символьный массив, содержащий параметры командной строки, причем argv[0] содержит имя программы, а argv[1],argv[2] и т. д. - 1-й, 2-й и т. д. параметры.

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

Производить контроль возвращаемого функцией API значения с выдачей соответствующих сообщений.

Настройка параметров среды Borland C++ для создания консольного приложения приведена в приложении.

3. В программе на языке ассемблера исходные данные следует задавать непосредственно в тексте программы. Необходимо производить контроль возвращаемого функцией API значения (регистр EAX) с выдачей соответствующих сообщений с помощью функции MessageBoxA.

При разработке программы на языке ассемблера рекомендуется создать командный файл asmwin. bat следующего вида (вместо слова путь нужно указать реальный путь доступа к соответствующим файлам):

del %1.exe
путь\tasm32 %1.asm /mx/m
путь\tlink32 %1.obj,,,путь\import32.lib /Tpe /aa
del %1.obj
del %1.map

Исходный текст разрабатываемой программы сохраняют в файле с расширением ".asm". В этом случае загрузочный файл (exe) может быть получен путем ввода в командной строке:

asmwin. bat имя_программы_без_расширения

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

5. Отчет по лабораторной работе должен содержать: текст задания, блок-схемы алгоритмов и распечатки текстов программ, результаты работы программ (скрин-шоты) в различных ситуациях.

Таблица 4. Описание функций Win32 API (варианты заданий)

Функция

Параметры и возвращаемое значение

1.   

Создание каталога

BOOL CreateDirectory (

LPCTSTR lpszPath,

LPSECURITY_ATTRIBUTES lpsa);

lpszPath - [in] имя каталога,

lpsa - [in] атрибуты безопасности (принять равным NULL).

Функция возвращает 0 (FALSE) в случае ошибки.

2.   

Удаление каталога

BOOL RemoveDirectory (

LPCTSTR lpszPath);

lpszPath [in] имя каталога

Функция возвращает 0 (FALSE) в случае ошибки.

3.   

Получение имени текущего каталога

DWORD GetCurrentDirectory (

DWORD cchCurDir,

LPTSTR lpszCurDir);

cchCurDir – [in] длина буфера (в байтах) для имени каталога

lpszCurDir - [out] буфер для имени каталога. Функция возвращает 0 в случае ошибки, или длину имени каталога в противном случае.

4.   

Замена текущего каталога

BOOL SetCurrentDirectory (

LPCTSTR lpszCurDir);

lpszCurDir – [in] имя каталога (относительное или полное).

5.   

Удаление файла

BOOL DeleteFile (

LPCTSTR lpFileName);

LpFileName - [in] имя удаляемого файла. Функция возвращает 0 (FALSE) в случае ошибки.

6.   

Переименование файла

BOOL MoveFile (

LPCTSTR lpszExisting,

LPCTSTR lpszNew);

lpszExisting – [in] имя существующего файла или каталога

lpszNew - [in] имя нового файла или каталога, который не должен существовать.

Функция возвращает 0 (FALSE) в случае ошибки.

7.   

Получение имени временного каталога Windows

DWORD GetTempPath (

DWORD nBufferLength,

LPTSTR lpBuffer);

nBufferLength – [out] длина буфера (в байтах) для имени каталога

lpBuffer – [out] буфер для имени каталога. Функция возвращает 0 в случае ошибки, или длину имени каталога в противном случае.

8.   

Получение имени компьютера

BOOL GetComputerName (

LPTSTR lpBuffer,
LPDWORD nSize);

nSize – [in] длина буфера;

lpBuffer - [out] буфер для имени.

Функция возвращает 0 (FALSE) в случае ошибки.

9.   

Получение имени системного каталога

UINT GetSystemDirectory (

LPTSTR lpBuffer,

UINT uSize);

lpBuffer - [out] буфер для имени;
uSize - [out] длина буфера.

Функция возвращает 0 в случае ошибки, или длину имени каталога в противном случае.

10. 

Получение имени пользователя

BOOL GetUserNameA (
LPTSTR lpBuffer,

LPDWORD nSize);

lpBuffer - [out] буфера для имени;
nSize –[out] указатель на длину буфера

Функция возвращает 0 (FALSE) в случае ошибки.

11. 

Получение имени каталога Windows

UINT GetWindowsDirectory (
LPTSTR lpBuffer,

UINT uSize);

lpBuffer -[out] буфер для имени;
uSize - [out] длина буфера.

Функция возвращает 0 в случае ошибки, или длину имени каталога в противном случае.

12. 

Получение информации о дисковом пространстве

(до 2 Гб)

BOOL GetDiskFreeSpace (

LPCTSTR lpRootPathName,

LPDWORD lpSectorsPerCluster,

LPDWORD lpBytesPerSector,

LPDWORD lpNumberOfFreeClusters,

LPDWORD lpTotalNumberOfClusters);

LpRootPathName - [in] имя корневого каталога (обязательно указать \).

LpSectorsPerCluster - [out] количество секторов в кластере

LpBytesPerSector - [out] количество байт в секторе

LpNumberOfFreeClusters - [out] количество свободных кластеров

LpTotalNumberOfClusters - [out] общее количество кластеров

Функция возвращает 0 (FALSE) в случае ошибки.

13. 

Получение заголовка консольного окна

DWORD GetConsoleTitle(

LPTSTR lpConsoleTitle,

DWORD nSize );

lpConsoleTitle - [out] указатель на буфер для строки заголовка

nSize - [in] размер буфера

Функция возвращает 0 в случае ошибки, или длину заголовка в противном случае.

14. 

Копирование файла.

BOOL CopyFile(

LPCTSTR lpExistingFileName,

LPCTSTR lpNewFileName,

BOOL bFailIfExists);

LpExistingFileName - [in] имя исходного файла (не более MAX_PATH)

lpNewFileName - [in] имя целевого файла

bFailIfExists - [in] TRUE, если требуется блокировать копирование в существующий файл, в противном случае FALSE.

Функция возвращает 0 (FALSE) в случае ошибки.

15. 

Задание заголовка консольного окна

BOOL SetConsoleTitle(

LPCTSTR lpConsoleTitle);

lpConsoleTitle - [in] строка заголовка

Функция возвращает 0 (FALSE) в случае ошибки.

16. 

Задание метки диска

BOOL SetVolumeLabel(

LPCTSTR lpRootPathName,

LPCTSTR lpVolumeName);

lpRootPathName - [in] имя корневого каталога (обязательно указать \).

lpVolumeName - [in] метка диска

Функция возвращает 0 (FALSE) в случае ошибки.

17. 

Получение каталога размещения DLL библиотек

DWORD GetDllDirectory(

DWORD nBufferLength,

LPTSTR lpBuffer);

nBufferLength - [in] размер символьного буфера.

LpBuffer - [out] указатель на буфер для размещения имени каталога

Функция возвращает 0 в случае ошибки, или длину имени каталога в противном случае.

18. 

Получение типа исполняемого файла

BOOL GetBinaryType(

LPCTSTR lpApplicationName,

LPDWORD lpBinaryType);

lpApplicationName - [in] полное имя файла

lpBinaryType - [out] указатель на возвращаемый код типа: 0 – Win32, 1 – Win64, 2 – MSDOS, 6 – Win16

Функция возвращает 0 (FALSE) в случае ошибки и если файл не является исполнимым

19. 

Получение типа диска

UINT GetDriveType (

LPCTSTR lpRootPathName);

lpRootPathName - [in] имя корневого каталога (обязательно указать \).

Функция возвращает код типа диска (0 – диск не найден, 1 – неверное имя корневого каталога, 2 – сменный диск, 3 - жесткий диск, 4 – внешний (сетевой) диск, 5 - компакт-диск, 6 - віртуальный диск)

20. 

Получение атрибутов файла

DWORD GetFileAttributes(

LPCTSTR lpFileName);

lpFileName - [in] имя файла

При успешном завершении функция возвращает код атрибута:

FILE_ATTRIBUTE_ARCHIVE – архивный,

FILE_ATTRIBUTE_HIDDEN – скрытый,

FILE_ATTRIBUTE_READONLY – только чтение,

FILE_ATTRIBUTE_SYSTEM - системный

FILE_ATTRIBUTE_TEMPORARY - временный.

В случае ошибки возвращаемое значение - INVALID_FILE_ATTRIBUTES.

21. 

Получить системное время

void GetSystemTime(

LPSYSTEMTIME lpSystemTime);

lpSystemTime [out] - указатель на структуру SYSTEMTIME

22. 

Получить версию ОС

DWORD GetVersion(VOID);

Возвращаемое значение:

Ст. бит=0, мл. байт=4 — WinNT;

Ст. бит=0, мл. байт=5 — Win2000/XP;

Ст. бит=1, мл. байт=4 — Win95/98/ME;

23. 

Получить информацию о логических дисках в числовом виде

DWORD GetLogicalDrives(VOID);

Возвращает 32-разрядное значение, каждый бит которого соответствует устройству: 1-й бит-A, 2-й бит-В и т. д.

24. 

Получить информацию о логических дисках в строковом виде

DWORD GetLogicalDrivesStrings(

DWORD nBufferLength,

LPSTR lpBuffer);

lpBuffer - [in] указатель на буфер для строки имен дисков

nBufferLength - [in] размер буфера

Функция возвращает 0 в случае ошибки, или длину заголовка в противном случае.

3.6. Контрольные вопросы

1.  Как организованы системные вызовы в ОС семейства Windows?

2.  Где размещаются коды системных функций Windows?

3.  Где описаны и с какой целью введены специальные типы данных Windows?

4.  Какие компоненты входят в состав включаемого файла windows. h?

5.  Что означает и для чего используется «венгерская нотация»?

6.  Поясните особенности организации оконных и консольных приложений Windows.

7.  Как организованы вызов функций API, передача параметров и получение результатов при создании приложений на языке С?

8.  Как организованы вызов функций API, передача параметров и получение результатов при создании приложений на языке Ассемблера?

ЛИТЕРАТУРА

1.  Справочник программиста персональных компьютеров типа IBM PC, XT и AT

2.  Персональный компьютер фирмы IBM и операционная система MS DOS

3.  Харт Дж. Системное программирование в среде WIN32 API - М.: Вильямс, 2001

4.  Справочник по функциям Wi 32 API, М:, «Горячая линия – Телеком» , 2002

5.  Румянцев программирования Win32 API, «Радио и Связь», 1999

6.  , Фролов для Windows NT. в 2-х томах — М.: ДИАЛОГ-МИФИ, 1996. — (Библиотека системного программиста; т. т. 26, 27)

ПРИЛОЖЕНИЕ. Настройка параметров проекта консольного приложения Win32 в среде Borland C++

При создании нового проекта необходимо вызвать с помощью меню (File/New/Project) диалоговое окно, представленное на рисунке, и установить приведенные значения параметров:

Учебно-методическое издание

СИСТЕМНЫЕ ВЫЗОВЫ

Методические указания к лабораторным работам по дисциплине "Операционные системы" для студентов специальностей

"Автоматизированные системы обработки информации и управления"

и "Информационные системы и технологии"

Подписано к печати

Формат 60х84/16 Усл. печ. л. 1,75 Тираж 100

Заказ № Изд № 206-06

Москва, ул. Образцова, 15

Типография МИИТа

Московский государственный университет путей сообщения (МИИТ)

Кафедра “Автоматизированные системы управления”

В. А. ВАРФОЛОМЕЕВ

СИСТЕМНЫЕ ВЫЗОВЫ

Методические указания к лабораторным работам по дисциплине "Операционные системы"

М О С К В А – 2006