MOV AH,25H ;функция установки вектора
MOV AL,60H ;номер вектора
INT 21H ;меняем прерывание
POP DS ;восстанавливаем DS

;---процедура прерывания
ROUT PROC FAR
PUSH AX ;сохраняем все изменяемые регистры
.
.
POP AX ;восстанавливаем регистры
MOV AL,20H ;эти две строки надо использовать
OUT 20H,AL ;только для аппаратных прерываний
IRET
ROUT ENDP

В конце кода каждого из Ваших аппаратных прерываний Вы должны
включить следующие 2 строчки кода:

MOV AL,20H
OUT 20H,AL

Это просто совпадение, что числа (20H) одни и те же в обеих
строках. Если аппаратное прерывание не заканчивается этими стро-
ками, то микросхема 8259 не очистит информацию регистра обслужи-
вания, с тем чтобы была разрешена обработка прерываний с более
низкими уровнями, чем только что обработанное. Отсутствие этих
строк легко может привести к краху программы, так как прерывания
от клавиатуры скорее всего окажутся замороженными и даже
Ctrl-Alt-Del окажется бесполезным. Отметим, что эта добавка не
нужна для тех векторов прерываний, которые являются расширениями
существующих прерываний, таким как прерывание 1CH, которое добав-
ляет код к прерыванию времени суток [2.1.7].
Когда программа завершается, должны быть восстановлены ориги-
нальные вектора прерываний. В противном случае последующая прог-
рамма может вызвать данное прерывание и передать управление на то
место в памяти, в котором Вашей процедуры уже нет. Функция 35
прерывания 21H возвращает текущее значение вектора прерывания,
помещая значение сегмента в ES, а смещение в BX. Перед установкой
своего прерывания получите текущее значение вектора, используя
эту функцию, сохраните эти значения, и затем восстановите их с
помощью функции 25H (как выше) перед завершением своей программы.
Например:

;---в сегменте данных:
KEEP_CS DW 0 ;хранит сегмент заменяемого прерывания
KEEP_IP DW 0 ;хранит смещение прерывания
;---в начале программы
MOV AH,25H ;функция получения вектора
MOV AL,1CH ;номер вектора
INT 21H ;теперь сегмент в ES, смещение в BX
MOV KEEP_IP,BX ;запоминаем смещение
MOV KEEP_CS,ES ;запоминаем сегмент


; ---в конце программы
CLI
PUSH DS ;DS будет разрушен
MOV DX,KEEP_IP ;подготовка к восстановлению
MOV AX,KEEP_CS ;
MOV DS,AX ;подготовка к восстановлению
MOV AH,25H ;функция установки вектора
MOV AL,1CH ;номер вектора
INT 21H ;восстанавливаем вектор
POP DS ;восстанавливаем DS
STI

Имеется пара ловушек, которых следует избегать при написании
прерывания. Если новая процедура прерывания должна иметь доступ к
данным, то необходимо позаботиться, чтобы DS был правильно уста-
новлен (обычно прерывание может использовать стек вызывающей
программы). Другая неприятность может заключаться в том, что при
завершении программы по Ctrl-Break вектор прерывания не будет
восстановлен, если только Вы не предусмотрите, чтобы программа
реакции на Ctrl-Break выполняла эту процедуру [3.2.8].

Низкий уровень.

Описанные выше функции MS DOS просто получают или изменяют
пару слов в младших ячейках памяти. Смещение вектора может быть
вычислено простым умножением номера вектора на 4. Например, чтобы
получить адрес прерывания 16H в ES:BX:

;---получение адреса прерывания 16H
SUB AX,AX ;устанавливаем ES на начало памяти
MOV ES,AX ;
MOV DI,16H ;номер прерывания в DI
SHL DI,1 ;умножаем на 2
SHL DI,1 ;умножаем на 2
MOV BX,ES:[DI] ;берем младший байт в BX
MOV AX,ES:[DI]+2 ;берем старший байт в ES
MOV ES,AX ;

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



    1.2.4 Дополнение к существующему прерыванию.



Хотя и не часто, но иногда бывает полезно добавить код к су-
ществующему прерыванию. В качестве примера рассмотрим программы,
которые преобразуют одно нажатие клавиши в длинные определяемые
пользователем символьные строки (макроопределения клавиатуры).
Эти программы используют факт, что весь ввод с клавиатуры посту-
пает поступает через функцию 0 прерывания 16H BIOS [3.1.3]. Все
прерывания ввода с клавиатуры DOS вызывают прерывание BIOS для
получения символа из буфера клавиатуры. Поэтому необходимо моди-
фицировать лишь прерывание 16H, таким образом, чтобы оно служило
шлагбаумом для макроопределений, после чего любая программа будет
получать макроопределения, независимо от того, какое прерывание
ввода с клавиатуры она использует.
Конечно, модифицировать прерывания BIOS и DOS непросто, пос-
кольку BIOS расположена в ПЗУ, а DOS поступает без листинга и они
ограничены размерами отведенной для них памяти. Но Вы можете
написать процедуру, которая предшествует и/или следует за соот-
ветствующим прерыванием, и эта процедура может вызываться при
вызове прерывания DOS или BIOS. Например, в случае прерывания
16H, Вам нужно написать процедуру и указать на нее вектором пре-
рывания для 16H. Оригинальное значение вектора 16H тем временем
переносится в какой-либо неиспользуемый вектор, скажем, 60H.
Новая процедура просто вызывает прерывание 60H, чтобы использо-
вать оригинальное прерывание 16H; поэтому когда программа вызы-
вает прерывание 16H, управление передается Вашей процедуре, кото-
рая затем вызывает оригинальное прерывание 16H, которая по завер-
шении опять возвращает управление Вашей процедуре, а из нее уже
Вы возвращаетесь в то место программы, из которого был вызов
прерывания 16H. После того как это сделано, в новой процедуре
может содержаться любой код, как до, так и после вызова прерыва-
ния 60H. На рис. 1-3 показана диаграмма этой процедуры. Вот крат-
кая сводка необходимых действий:

1. Создать новую процедуру, вызывающую прерывание 60H.
2. Перенести вектор прерывания для 16H в 60H.
3. Изменить вектор 16H, чтобы он указывал на новую процедуру.
4. Завершить программу, оставляя ее резидентной [1.3.4].



    Раздел 3. Управление программами.



Большинство программ загружаются в память, запускаются, а
затем удаляются операционной системой при завершении. Языки высо-
кого уровня обычно не имеют альтернативы. Но для программистов на
ассемблере имеется другая возможность и данный раздел демонстри-
рует ее. Некоторые программы действуют как драйверы устройств
или драйверы прерываний и они должны быть сохранены в памяти
("резидентными") даже после их завершения (вектора прерываний
обеспечивают механизм, посредством которого последующие программы
могут обращаться к резидентным процедурам). Иногда программе
необходимо запустить из себя другую программу. На самом деле DOS
позволяет программе загрузить в память вторую копию COMMAND.COM,
которая может использована как средство интерфейса с пользовате-
лем или выполнения команд типа COPY или DIR.
Программы могут быть в двух форматах: .EXE или .COM. Программы
первого типа могут быть больше 64K, но они требуют некоторой
обработки перед тем, как DOS загрузит их в память. С другой сто-
роны COM программы существуют прямо в том формате, который нужен
для загрузки в память. COM программы особенно полезны для корот-
ких утилит. В обоих случаях код, составляющий программу, предва-
ряется в памяти префиксом программного сегмента (PSP). Это об-
ласть размером 100H байт, которая содержит информацию необходимую
DOS для работы программы; PSP также обеспечивает место для файло-
вых операций ввода/вывода [5.3.5]. При загрузке EXE файла и DS и
ES указывают на PSP. Для COM файлов CS также сначала указывает на
PSP. Отметим, что MS DOS 3.0 имеет функцию, которая возвращает
номер сегмента PSP. Это функция 62H прерывания 21H; ей ничего не
надо подавать на входе, а в BX возвращается номер параграфа.
Одна из причин, по которой интересно положение PSP, состоит в
том, что его первое слово содержит номер прерывания DOS, которое
будет приводить к завершению программы. Когда выполняется послед-
ний оператор RET программы, то значения на вершине стека указы-
вают счетчику команд (регистр IP) на начало PSP, таким образом
код завершения выполняется как следующая инструкция программы.
Дальнейшее обсуждение этого смотрите в пунктах [1.3.4] и [1.3.6].

Для справки приводим значение полей PSP:

Смещение Размер поля Значение
0H DW номер функции DOS завершения программы
2H DW размер памяти в параграфах
4H DW резерв
6H DD длинный вызов функции диспатчера DOS
AH DD адрес завершения (IP,CS)
EH DD адрес выхода по Ctrl-Break (IP,CS)
12H DD адрес выхода по критической ошибке
16H 22 байта резерв
2CH DW номер параграфа строки среды
2EH 46 байтов резерв
5CH 16 байтов область параметров 1 (формат FCB)
6CH 20 байтов область параметров 2 (формат FCB)
80H 128 байтов область DTA по умолчанию/получает
командную строку программы



    1.3.1 Манипуляции с памятью.



Когда MS DOS загружает программу, то она помещается в младшую
область памяти, сразу же за COMMAND.COM и установленными драйве-
рами устройств или другими утилитами, которые резидентны в памя-
ти. В этот момент времени вся память за программой отведена этой
программе. Если программе нужна память для создания области дан-
ных, то она может приближенно вычислить где в памяти кончается ее
код и затем поместить требуемую область данных в любое место за
концом кода. Для определения адреса конца программы поместите в
конце программы псевдосегмент типа:

ZSEG SEGMENT
;
ZSEG ENDS

В ассемблере IBM PC ZSEG будет последним сегментом, так как
сегменты располагаются в алфавитном порядке. С другими ассембле-
рами нужно действительно поместить эти строки в конце программы.
В самой программе достаточно поставить оператор MOV AX,ZSEG и AX
будет указывать на первый свободный сегмент памяти за программой.
Такой подход будет работать до тех пор, пока программа не
будет предполагать о наличии памяти, которой на самом деле нет.
Он не будет также работать в многопользовательской среде, когда
несколько программ могут делить между собой одну и ту же область
адресов. Для решения этой проблемы MS DOS имеет возможность отс-
леживать 640K системной памяти и отводить по требованию программы
блоки памяти любого размера. Блок памяти - это просто непрерывная
область памяти, его максимальный размер определяется размером
доступной памяти, в частности, он может быть больше одного сег-
мента (64K). Если затребован слишком большой блок, то DOS выдает
сообщение об ошибке. Любая возможность перекрытия блоков исключе-
на. Кроме того MS DOS может освобождать, урезать или расширять
существующие блоки. Хотя программа не обязана использовать эти
средства, но удобно и предусмотрительно делать это. Некоторые
функции DOS требуют, чтобы были использованы средства управления
памятью DOS, например, завершение резидентной программы [1.3.4]
или вызов другой программы из данной [1.3.2].
Прежде чем отвести память, существующий блок (вся память от
начала программы до конца) должен быть обрезан до размера прог-
раммы. Затем, при создании блока, DOS создает 16-байтный управ-
ляющий блок памяти, который расположен непосредственно перед
блоком памяти. Первые 5 байтов этого блока имеют следующее значе-
ние:

байт 0 ASCII 90 - если последний блок в цепочке, иначе
ASCII 77.
байты 1-2 0 если блок освобожден
байты 3-4 размер блока в 16-байтных параграфах

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


и т.д., как показано на рис. 1-4. Как только Вы начали использо-
вать систему распределения памяти DOS, то Вы обязаны придержи-
ваться ее. Если программа изменит содержимое управляющего блока,
то цепочка будет разорвана и DOS начнет выдавать сообщения об
ошибке.
MS DOS обеспечивает три функции распределения памяти, номера
от 48H до 4AH прерывания 21H. Функция 48H отводит блок памяти, а
49H - освобождает блок памяти. Третья функция ("SETBLOCK") ме-
няет размер памяти, отведенной для программы; эта функция должна
быть использована перед двумя остальными. После ее выполнения
можно спокойно отводить и освобождать блоки памяти. Программа
должна освободить все отведенные ею блоки перед завершением.
Иначе эта память будет недоступной для последующего использова-
ния.

Средний уровень.

Все три функции распределения памяти прерывания 21H используют
16-битный адрес начала блока памяти, с которым они оперируют.
Этот адрес соответствует сегменту, с которого начинается блок
(блок всегда начинается со смещения 0 данного сегмента). Таким
образом реальный адрес ячейки начала блока равен этому адресу,
умноженному на 16. Также, для всех трех функций, BX содержит
число 16-байтных разделов памяти (параграфов), которые будут
отводиться или освобождаться. Если функция не может быть выполне-
на, то устанавливается флаг переноса, а в AX возвращается код
ошибки, объясняющий причину. Возможны три кода ошибки:

7 разрушен управляющий блок памяти
8 недостаточно памяти для выполнения функции
9 неверный адрес блока памяти

Функция отведения блока использует коды 7 и 8, а освобождения - 7
и 9, в то время как функция изменения блока использует все три
кода. В следующем примере сначала отводится блок, размером 1024
байта. При этом BX содержит требуемое число 16-байтных парагра-
фов, а при завершении стартовый адрес блока равен AX:0 (т.е.
смещение 0 в сегменте со значением, содержащимся в AX). Вторая
часть примера освобождает этот же блок, как и требуется при за-
вершении программы. В данном случае значение полученное в AX
помещается в ES. DOS следит за размером блока и знает какое коли-
чество параграфов надо освободить.

;---отведение блока размером 1024 байта
MOV AH,48H ;номер функции
MOV BX,64 ;требуем 64 параграфа
INT 21H ;пытаемся отвести блок
JC ERROR ;обрабатываем ошибку в случае неудачи
MOV BLOCK_SEG,AX;иначе сохраняем адрес блока
.
;---освобождаем тот же блок
MOV AX,BLOCK_SEG ;получаем стартовый адрес блока
MOV ES,AX ;помещаем его в ES
MOV AH,49H ;номер требуемой функции
INT 21H ;освобождаем блок памяти


Наконец, приведем пример использования функции 4AH. ES содер-
жит значение сегмента PSP, т.е. самого первого байта памяти, с
которого загружена программа. Это значение присваивается ES при
старте задачи. Для использования SETBLOCK надо либо вызывать эту
функцию в самом начале программы (прежде чем ES будет изменен),
либо сохранить его начальное значение для последующего использо-
вания.
BX содержит требуемый размер блока в 16-байтных параграфах.
Для определения этого размера поместите добавочный "искуственный"
сегмент в конец программы. В макроасссемблере IBM PC сегменты
располагаются в алфавитном порядке, поэтому Вы можете поместить
его в любое место программы, при условии, что его имя это что-то
вроде "ZSEG". В других ассемблерах действительно помещайте фик-
тивный сегмент в конец программы. Программа может прочитать пози-
цию этого сегмента и, сравнивая ее со стартовым сегментом, полу-
чить количество памяти, требуемое самой программе. В момент заг-
рузки программы и ES и DS содержат номер параграфа самого начала
программы в префиксе программного сегмента; для COM файлов CS
также указывает на эту позицию, но для EXE файлов это не так.
;---освобождение памяти (ES имеет значение при старте)
MOV BX,ZSEG ;получаем # параграфа конца программы + 1
MOV AX,ES ;получаем # параграфа начала программы
SUB BX,AX ;вычисляем размер программы в параграфах
MOV AH,4AH ;номер функции
INT 21H ;освобождаем память
JC MEMORY_ERROR ;проверяем на ошибку

;---
ZSEG SEGMENT
ZSEG ENDS



    1.3.2 Запуск одной программы из другой.



MS DOS обеспечивает функцию EXEC (номер 4BH прерывания 21H),
реализующую вызов одной программы из другой. Первая программа
называется "родителем", а загружаемая и запускаемая - "потомком".

Высокий уровень.

В Бейсик версии 3.0 введена команда SHELL. Со значительными
ограничениями она позволяет бейсиковской программе загрузить и
выполнить другую программу. Формат этой команды SHELL ком_строка.
Командная строка может быть просто именем программы или она может
содержать кроме имени параметры, которые обычно следуют за именем
программы в командной строке. Если ком_строка не указана, то
загружается копия COMMAND.COM и появляется запрос операционной
системы. В этот момент можно выполнить любую команду MS DOS, а по
завершению вернуть управление бейсиковской программе, введя ко-
манду EXIT.
Имеется ряд ограничений при использовании SHELL. Если загру-
жаемая программа меняет режим работы дисплея, то он не будет
автоматически восстановлен при возврате. Перед загрузкой програм-
мы все файлы должны быть закрыты, и это не может быть программа,
которая остается резидентной после завершения. Обсуждение ряда
других проблем содержится в руководстве по Бейсику.

Средний уровень.

Функция 4BH более сложна, чем остальные, требуя четырех подго-
товительных шагов:

1. Подготовить в памяти место, доступное программе.
2. Создать блок параметров.
3. Построить строку, содержащую накопитель, путь и имя прог-
раммы.
4. Сохранить значения регистров SS и SP в переменных.

Поскольку при загрузке программы MS DOS выделяет ей всю дос-
тупную память, то необходимо освободить место в памяти. Если не
освободить часть памяти, то не будет места для загрузки второй
программы. В [1.3.1] объяснено как это сделать с помощью функции
SETBLOCK. После того как память освобождена, Вы должны просто
поместить в BX требуемое число 16-байтных параграфов, заслать 4AH
в AH и выполнить прерывание 21H, делая доступным программе именно
то число параграфов, которое ей требуется.
Блок параметров, на который должны указывать ES:BX это
14-байтный блок блок памяти, в который Вы должны поместить сле-
дующую информацию:

DW сегментный адрес строки среды
DD сегмент и смещение командной строки
DD сегмент и смещение первого FCB
DD сегмент и смещение второго FCB


Строка среды - это строка, состоящая из одной или более специ-
фикаций, которым следует MS DOS при выполнении программы. Элемен-
ты строки среды такие же, как и те что можно обнаружить в диско-
вом файле CONFIG.SYS. Например, в строку может быть помещено
VERIFY = ON. Просто начните строку с первого элемента, завершив
его символом ASCII 0, потом запишите следующий и т.д. За послед-
ним элементом должны следовать два символа ASCII 0. Строка должна
начинаться на границе параграфа (т.е. ее адрес по модулю 16 дол-
жен быть равен нулю). Это вызвано тем, что соответствующий вход в
блоке параметров, указывающий на строку, содержит только 2-байт-
ное сегментное значение. Все это не нужно, если новая программа
может работать с той же строкой среды, что и программа "роди-
тель". В этом случае надо просто поместить два символа ASCII 0 в
первые 2 байта блока параметров.
Следующие 4 байта блока параметров указывают на командную
строку для загружаемой программы. "Командная строка" - это сим-
вольная строка, определяющая способ работы программы. При загруз-
ке программы из DOS она может иметь вид вроде EDITOR A:CHAPTER1\
NOTES.MS. При этом вызывается редактор и ему передается имя файла
в подкаталоге накопителя A для немедленного открытия. Когда Вы
подготавливаете командную строку для EXEC, то надо включать толь-
ко последнюю часть информации, но не имя загружаемой программы.
Перед командной строкой должен стоять байт, содержащий длину этой
строки, и она должна завершаться символом <ВК> (ASCII 13).
Последние 8 байтов блока параметров указывают на управляющие
блоки файлов (FCB). FCB содержит информацию об одном или двух
файлах, указанных в командной строке. Если открываемых файлов
нет, то надо заполнить все 8 байт символом ASCII 0. В [5.3.5]
объяснено, как работает FCB. Начиная с версии MS DOS 2.0, исполь-
зование FCB необязательно и Вы можете не включать информацию FCB,
вместо этого используя новую конвенцию дескриптора файлов (file
handler), в которой доступ к файлу предоставляется по кодовому
номеру, а не через FCB (также обсуждается в [5.3.5]).
Наконец, Вы должны построить строку с указанием накопителя,
пути и имени файла. Эта строка именует загружаемую программу.
DS:DX указывает на эту строку при выполнении EXEC. Эта строка -
стандартная строка ASCIIZ, т.е. ничего более, чем стандартная
спецификация файла, завершаемая кодом ASCII 0. Например, это
может быть B:\NEWDATA\FILER.EXE<NUL>, где символом <NUL> обозна-
чен код ASCII 0.
После того как вся указанная информация подготовлена, остается
последняя задача. Поскольку все регистры будут изменены вызывае-
мой задачей, то надо сохранить сегмент стека и указатель стека, с
тем чтобы они могли быть восстановлены, когда управление будет
возвращено вызвавшей задаче. Для их сохранения создайте перемен-
ные. Поскольку значение регистра DS также будет изменено, то эти
переменные не могут быть найдены, до тех пор пока не будут повто-
рены операторы MOV AX,DSEG и MOV DS,AX. После того как SS и SP
сохранены, поместите 0 в AL, для выбора операции "загрузка и
запуск" (EXEC используется также для оверлеев [1.3.5]). Затем
поместите 4AH в AH и вызовите прерывание 21H. В этот момент запу-
щены две программы, причем программа "родитель" находится в оста-
новленном состоянии. MS DOS предоставляет возможность программе
потомку передать родителю код возврата, таким образом могут быть
переданы ошибки и статус. В [7.2.5] объяснено как это сделать.
Что касается самой функции запуска, то при возникновении ошибки
устанавливается флаг переноса, а регистр AX в этом случае будет
возвращать 1 - для неправильного номера функции, 2 - если файл не
найден, 5 - при дисковой ошибке, 8 - при нехватке памяти, 10 -
если неправильна строка среды и 11 - если неверен формат.


Приводимый пример - простейший из возможных, но часто больше
ничего и не надо. Здесь оставлен нулевым блок параметров и не
создана строка среды. Это означает, что загружаемой программе не
будет передаваться командная строка и что среда будет такой же,
как и для вызывающей программы. Вы должны только изменить распре-
деление памяти, создать имя и (пустой) блок параметров и сохра-
нить значения SS и SP.

;---в сегменте данных
FILENAME DB 'A:TRIAL.EXE',0 ;загружаем TRIAL.EXE
PARAMETERS DW 7DUP(0) ;нулевой блок параметров
KEEP_SS DW 0 ;переменная для SS
KEEP_SP DW 0 ;переменная для SP

;---перераспределение памяти
MOV BX,ZSEG ;получить # параграфа конца
MOV AX,ES ;получить # параграфа начала
SUB BX,AX ;вычислить размер программы
MOV AH,4AH ;номер функции
INT 21H ;перераспределение
;---указываем на блок параметров
MOV AX,SEG PARAMETERS ;в ES - сегмент
MOV ES,AX ;
MOV BX,OFFSET PARAMETERS ;в BX - смещение
;---сохранить копии SS и SP
MOV KEEP_SS,SS ;сохраняем SS
MOV KEEP_SP,SP ;сохраняем SP
;---указываем на строку имени файла
MOV DX,OFFSET FILENAME ;смещение - в DX
MOV AX,SEG FILENAME ;сегмент - в DS
MOV DS,AX ;
;---загрузка программы
MOV AH,4BH ;функция EXEC
MOV AL,0 ;выбираем "загрузку и запуск"
INT 21H ;запускаем задачу
;---впоследствии, восстанавливаем регистры
MOV AX,DSEG ;восстанавливаем DS
MOV DS,AX ;
MOV SS,KEEP_SS ;восстанавливаем SS
MOV SP,KEEP_SP ;восстанавливаем SP

;---в конце программы создаем фиктивный сегмент
ZSEG SEGMENT ;см. [1.3.1]
ZSEG ENDS



    1.3.3 Использование команд интерфейса с пользователем из программы.



Программа может иметь в своем распоряжении полный набор команд
интерфейса с пользователем DOS, таких как DIR или CHKDSK. Когда
эти команды используются из программы, загружается и запускается
вторая копию COMMAND.COM. Хотя такой подход может сэкономить
много усилий при программировании, для его успешной реализации
требуется достаточное количество памяти для этой второй копии и
Ваша программа может попасть в ловушку если памяти недостаточно.

Высокий уровень.

Бейсик 3.0 может загрузить вторую копию COMMAND.COM с помощью
оператора SHELL. SHELL обсуждается в [1.3.2]. COMMAND.COM загру-
жается когда не указано имя файла, поэтому вводя просто SHELL, Вы
получаете запрос MS DOS. В этот момент можно использовать любую
из утилит DOS, включая командные файлы. Для возврата в вызвавшую
программу надо ввести EXIT.

Средний уровень.

В этом случае к примеру, приведенному в [1.3.2] нужно добавить
командную строку. Обычно она начинается с байта длины строки,
затем следует сама командная строка и, наконец, код ASCII 13. При
передаче команды COMMAND.COM Вы должны указать /C перед строкой
(см. пункт "Вызов вторичного командного процессора" руководства
по MS DOS). Вы должны также указать накопитель, на котором нахо-
дится COMMAND.COM, поместив имя накопителя в начале командной
строки. Чтобы вывести каталог накопителя A:, а COMMAND.COM при
этом находится на накопителе B:, нужна строка:

COMMAND_LINE DB 12,'B: /C DIR A:',13

Следующий кусочек кода устанавливает адрес командной строки в
блок параметров, используемый в примере [1.3.2]:

LEA BX,PARAMETERS ;получение адреса блока пар-ров
MOV AX,OFFSET COMMAND_LINE ;получение смещения ком. строки
MOV [BX]+2,AX ;пересылка в 1-е 2 байта блока
MOV AX,SEG COMMAND_LINE ;получение сегмента ком. строки
MOV [BX]+4,AX ;пересылка во 2-е 2 байта блока



    1.3.4 Сохранение программы в памяти после завершения.



Программы, оставленные резидентными в памяти, могут служить в
качестве утилит для других программ. Обычно такие программы вызы-
ваются через неиспользуемый вектор прерывания. MS DOS рассматри-
вает такие программы как часть операционной системы, защищая их
от наложения других программ, которые будут загружены впоследст-
вии. Резидентные программы обычно пишутся в форме COM, что обсуж-
дается в пункте [1.3.6]. Программы, написанные в форме EXE оста-
вить резидентными в памяти немного труднее.
Завершение программы прерыванием 27H оставляет ее резидентной