автоматически восстановлен при возврате. Перед загрузкой програм-
мы все файлы должны быть закрыты, и это не может быть программа,
которая остается резидентной после завершения. Обсуждение ряда
других проблем содержится в руководстве по Бейсику.
Средний уровень.
Функция 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. Hапример, в строку может быть помещено
VERIFY = ON. Просто начните строку с первого элемента, завершив
его символом ASCII 0, потом запишите следующий и т.д. За послед-
ним элементом должны следовать два символа ASCII 0. Строка должна
начинаться на границе параграфа (т.е. ее адрес по модулю 16 дол-
жен быть равен нулю). Это вызвано тем, что соответствующий вход в
блоке параметров, указывающий на строку, содержит только 2-байт-
ное сегментное значение. Все это не нужно, если новая программа
может работать с той же строкой среды, что и программа "роди-
тель". В этом случае надо просто поместить два символа ASCII 0 в
первые 2 байта блока параметров.
Следующие 4 байта блока параметров указывают на командную
строку для загружаемой программы. "Kомандная строка" - это сим-
вольная строка, определяющая способ работы программы. При загруз-
ке программы из DOS она может иметь вид вроде EDITOR A:CHAPTER1\
NOTES.MS. При этом вызывается редактор и ему передается имя файла
в подкаталоге накопителя A для немедленного открытия. Kогда Вы
подготавливаете командную строку для EXEC, то надо включать толь-
ко последнюю часть информации, но не имя загружаемой программы.
Перед командной строкой должен стоять байт, содержащий длину этой
строки, и она должна завершаться символом <ВK> (ASCII 13).
Последние 8 байтов блока параметров указывают на управляющие
блоки файлов (FCB). FCB содержит информацию об одном или двух
файлах, указанных в командной строке. Если открываемых файлов
нет, то надо заполнить все 8 байт символом ASCII 0. В [5.3.5]
объяснено, как работает FCB. Hачиная с версии MS DOS 2.0, исполь-
зование FCB необязательно и Вы можете не включать информацию FCB,
вместо этого используя новую конвенцию дескриптора файлов (file
handler), в которой доступ к файлу предоставляется по кодовому
номеру, а не через FCB (также обсуждается в [5.3.5]).
Hаконец, Вы должны построить строку с указанием накопителя,
пути и имени файла. Эта строка именует загружаемую программу.
DS:DX указывает на эту строку при выполнении EXEC. Эта строка -
стандартная строка ASCIIZ, т.е. ничего более, чем стандартная
спецификация файла, завершаемая кодом ASCII 0. Hапример, это
может быть B:\NEWDATA\FILER.EXE, где символом обозна-
чен код 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. Kогда
эти команды используются из программы, загружается и запускается
вторая копию 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 оставляет ее резидентной
в памяти. CS должен указывать на начало PSP для того, чтобы эта
функция работала правильно. В программах COM, CS сразу устанавли-
вается соответствующим образом, поэтому надо просто завершить
программу прерыванием 27H. В программах EXE , CS первоначально
указывает на первый байт, следующий за PSP (т.е. 100H). При нор-
мальном завершении EXE программы последняя инструкция RET вытал-
кивает из стека первые положенные туда значения: PUSH DX / MOV
AX,0 / PUSH AX. Поскольку DS первоначально указывает на начало
PSP, то при получении этих значений из стека счетчик команд ука-
зывает на смещение 0 в PSP, где при инициализации записывается
инструкция INT 20H. Поэтому INT 20H выполняется, а это стандарт-
ная функция для завершения программы и передачи управления в DOS.
Hа рис. 1-5 показан этот процесс. Чтобы заставить прерывание 27H
работать в EXE программе надо поместить 27H во второй байт PSP
(первый содержит машинный код инструкции INT), а затем завершить
программу обычным RET. Для обоих типов файлов прежде чем выпол-
нить прерывание 27H, DX должен содержать смещение конца програм-
мы, отсчитываемое от начала PSP.
Средний уровень.
Вектор прерывания устанавливается с помощью функции 25H преры-
вания 21H, как показано в [1.2.3] (здесь используется вектор
70H). Позаботьтесь, чтобы процедура оканчивалась IRET. Kроме
самой процедуры, устанавливаемая программа не должна делать ниче-
го, кроме инициализации вектора прерывания, присвоения DX значе-
ния смещения конца процедуры и завершения. Для COM файлов просто
поместите оператор INT 27H в конец программы. Для EXE файлов
поместите этот оператор в первое слово PSP и завершите программу
обычным оператором RET. Для того чтобы выполнить процедуру, впос-
ледствии загруженная программа должна вызвать INT 70H.
Приведены примеры для обоих типов файлов (COM и EXE). В обоих
установлена метка FINISH для отметки конца процедуры прерывания
(напоминаем, что знак $ дает значение счетчика команд в этой