Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

MS-DOS для программиста

© Александр Фролов, Григорий Фролов
Том 18, М.: Диалог-МИФИ, 1995, 254 стр.

[Назад] [Содеожание] [Дальше]

3.4. Запуск программ из программ

Ваша программа может при необходимости запустить другую exe- или com-программу.

Программа, составленная на языке ассемблера, запускает другую программу с помощью функции 4Bh прерывания INT 21h . Для выполнения той же задачи из программ, составленных на языке С, следует использовать разнообразные функции, входящие в состав стандартной библиотеки системы разработки.

Сначала рассмотрим процедуру запуска программы при помощи функции 4Bh прерывания INT 21h .

Перед вызовом прерывания вы должны загрузить регистры процессора следующим образом:

Регистр Содержимое
AH 4Bh
AL Код подфункции (0, 1, 2, 3, 5)
DS:DX Указатель на текстовую строку в формате ASCIIZ , содержащую путь к запускаемой программе
ES:BX Указатель на блок параметров EPB

После возврата из прерывания флаг переноса CF устанавливается в 0, если ошибок не было, и в 1 - при обнаружении ошибок. Если произошла ошибка, ее код записывается в регистр AX:

Код ошибки Описание
1 Неверный код подфункции
2 Не найден файл запускаемой программы
3 Указанный путь не найден
4 Слишком много открытых файлов
5 Нет доступа
8 Нет памяти для загрузки программы
10 Длина блока среды больше 32 Кбайт
11 Неправильный формат запускаемого exe-файла

Функция 4Bh прерывания INT 21h имеет несколько подфункций:

Код Описание
0 Загрузить и выполнить программу
1 Загрузить, но не выполнять программу
2 Загрузить, но не выполнять программу (недокументированная подфункция)
3 Загрузить программу как оверлей (не создавая при этом блок PSP )
5 Подготовить программу для выполнения

Опишем эти подфункции более подробно.

Загрузка и выполнение программы

Для функции 0 регистры DS:DX должны указывать на полный путь запускаемой программы в формате ASCIIZ (т. е. на текстовую строку, закрытую двоичным нулем). Блок параметров EPB (Exec Parameter Block ) в этом случае имеет следующий формат:

Смещение, байт Размер, байт Имя поля Описание
0 2 seg_env Сегментный адрес среды, которая создается родительской программой для запускаемой программы. Если в этом поле находится 0, то для запускаемой программы копируется среда родительской программы
2 4 cmd Дальний адрес строки параметров для запускаемой программы. Эта строка должна иметь такой же формат, как и в PSP , т. е. в начале строки находится байт со значением, равным количеству символов в строке параметров, а затем - сама строка параметров
6 4 fcb1 Адрес блока FCB . Этот адрес будет записан в блок PSP со смещением 5Ch
10 4 fcb2 Адрес блока FCB . Этот адрес будет записан в блок PSP со смещением 6Ch

Запущенной программе доступны все файлы, открытые родительской программой.

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

Для примера приведем исходный текст простой программы SPARM (листинг 3.5), которая запускает программу с именем parm.com из текущего каталога. Программу parm.com мы уже рассматривали (листинг 3.2). Эта программа выводит на экран параметры, полученные ей при запуске через командную строку.


Листинг 3.5. Файл sparm\sparm.asm


  .MODEL  tiny
  DOSSEG
  .DATA

path         db "PARM.COM",0
command_line db 11,"Parm1 Parm2"
epb          dw 0
cmd_off      dw ?
cmd_seg      dw ?
fcb1         dd ?
fcb2         dd ?

  .CODE
  .STARTUP
;
; Освобождаем лишнюю память за концом программы
;
  mov     bx, OFFSET last ; смещение конца программы

  mov     cl,4    ; вычисляем длину программы в параграфах
  shr     bx,cl

  add     bx,17   ; добавляем 1 параграф для
                  ; выравнивания и 256 байт для стека

  mov     ah, 4Ah ; изменяем размер выделенного
  int     21h     ; блока памяти

  mov     ax,bx   ; устанавливаем новое значение
  shl     ax,cl   ;  для указателя стека
  dec     ax
  mov     sp,ax

  mov     bx,OFFSET command_line ; адрес командной
  mov     cmd_off,bx             ; строки для блока EPB 
  mov     cmd_seg,ds

  mov     ax,ds
  mov     es,ax

  mov     bx, OFFSET epb  ; ES:BX указывают на EPB 
  mov     dx, OFFSET path ; DS:DX указывают на путь
                          ; к файлу запускаемой программы

  mov     ax, 4B00h      ; AH = 4Bh
                         ; AL = 0 загрузить и выполнить
  int     21h
  .EXIT   0

last:   db ?
END

Программа SPARM освобождает всю неиспользуемую ей память, после чего на освободившееся место загружает программу parm.com. Такая процедура необходима потому, что MS-DOS выделяет всю имеющуюся память в распоряжение запускаемой com-программы. Поэтому при попытке запустить программу без предварительного освобождения части памяти функция 4Bh вернет код ошибки 8 (нет памяти для загрузки программы).

Для изменения размера блока памяти, выделенного программе, мы использовали функцию 4Ah прерывания INT 21h .

Загрузка программы без выполнения

Подфункции 1 и 2 прерывания INT 4Bh используются операционной системой MS-DOS для собственных нужд (это внутренние подфункции MS-DOS). Они также необходимы для создания программ-отладчиков, таких как, например, debug.com или td.exe. Мы приведем недокументированный формат блока EBP для этих функций.

Для подфункции 1 блок EBP имеет следующий формат:

Смещение, байт Размер, байт Имя поля Описание
0 2 seg_env Сегментный адрес среды, которая создается родительской программой для запускаемой программы. Если в этом поле находится 0, то для запускаемой программы копируется среда родительской программы
2 4 cmd Дальний адрес строки параметров для запускаемой программы
6 4 fcb1 Адрес блока FCB . Этот адрес будет записан в блок PSP со смещением 5Ch
10 4 fcb2 Адрес блока FCB . Этот адрес будет записан в блок PSP со смещением 6Ch
14 4 ss_sp В это поле после завершения работы запускаемой программы будет записано содержимое регистров SS:SP
18 4 entry_p Адрес точки входа в загруженную программу, который нужно записать в регистры CS:IP при запуске программы

Формат блока EPB для подфункции 2:

Смещение, байт Размер, байт Имя поля Описание
0 2 seg_env Сегментный адрес среды, которая создается родительской программой для запускаемой программы. Если в этом поле находится 0, то для запускаемой программы копируется среда родительской программы
2 4 cmd Дальний адрес строки параметров для запускаемой программы
6 4 fcb1 Адрес блока FCB . Этот адрес будет записан в блок PSP со смещением 5Ch
10 4 fcb2 Адрес блока FCB . Этот адрес будет записан в блок PSP со смещением 6Ch

Загрузка программного оверлея

Подфункция 3 используется для загрузки программных оверлеев . Оверлей загружается в адресное пространство родительской программы, поэтому MS-DOS не заказывает дополнительной памяти и не строит PSP . Формат EPB для этой подфункции:

Смещение, байт Размер, байт Имя поля Описание
0 2 seg_env Сегментный адрес, по которому загружается программа
2 4 reloc Фактор перемещения. Для exe-программ обычно содержит то же значение, что и поле seg_env, для com-программ в этом поле находится значение 0

Следующий фрагмент программы загружает программу parm.com как оверлей без передачи ей управления (программа загружается в буфер buff):

  .DATA
path    db "PARM.COM",0
epb     dw 0
reloc   dd 0
  .CODE
  .STARTUP

  mov     ax,ds
  mov     es,ax
  mov     bx,SEG buff
  mov     epb,bx

  mov     bx,OFFSET epb  ; ES:BX указывают на EPB 
  mov     dx,OFFSET path ; DS:DX указывают на путь
                         ; загружаемой программы

  mov     ax, 4B03h ; AH = 4Bh
                    ; AL = 0 загрузить оверлей
  int     21h
;
; Работа с загруженной программой
........
;
  .EXIT   0
buff:   dd 100 dup(?)
  END

Подготовка программы для выполнения

Подфункция 5 используется для загрузки и предварительной подготовки программы к выполнению . Она впервые появилась в MS-DOS версии 5.0. Вы можете использовать ее вместо недокументированных подфункций 1 и 2.

Если программа, запущенная с помощью подфункции 5, попытается определить версию MS-DOS, ей будет предоставлен не истинный номер версии, а определенный с учетом действия драйвера setver.

Напомним, что с помощью драйвера setver MS-DOS может "обмануть" программу, сообщив ей, что работает MS-DOS, например, версии 3.31 или любой другой версии, указанной пользователем. Такая возможность требуется в тех случаях, когда программа была рассчитана на конкретную версию MS-DOS, но, тем не менее, способна работать и в новой версии.

Для подфункции 5 указатель, расположенный в регистрах DS:DX, должен указывать на структуру EXECSTATE, описанную ниже:

Смещение, байт Размер, байт Имя поля Описание
0 2 Reserved Зарезервировано
2 2 Flags Тип программы: 0 - com-программа, 1 - exe-программа, 2 - оверлей
4 4 ProgName Указатель на текстовую строку ASCIIZ , содержащую имя программы
8 2 PSP Сегмент блока PSP новой программы
10 4 StartAddr Стартовый адрес CS:IP новой программы
14 4 ProgSize Общий размер программы с учетом размера блока PSP

Запуск программ из программ, составленных на языке С

Пользователи языка С имеют в своем распоряжении несколько возможностей запустить программу.

Самый простой способ - использовать функцию system . Эта функция может выполнить любую команду MS-DOS или любую программу, а также пакетный файл. Например:

system("FORMAT A:");

При использовании этой функции должен быть доступен файл command.com .

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

Bad command or file name

Код возврата в этом случае будет 0 - как будто все хорошо!

Другая возможности запустить программу - использовать функции spawn и exec.

Функция spawn и ее разновидности запускают программу как дочерний процесс. Функция exec загружает новую программу как оверлей на место старой и передает ей управление без возврата. После завершения дочерней программы управление будет передано программе command.com или программе, которая запустила родительскую программу.

Семейство функций spawn обеспечивает запуск дочерней программы, передавая ей родительскую или с специально сформированную среду. Кроме того, в файле process.h описаны параметры, которые можно передать функции spawn:

Параметр Описание
P_WAIT Выполнение родительской программы задерживается до завершения дочерней программы
P_NOWAIT Родительская программа продолжает выполнение сразу после запуска дочерней программы. Этот параметр имеет смысл только для мультизадачных операционных систем
P_OVERLAY Загружает программу как оверлей и передает ей управление. Этот режим соответствует функции exec в том смысле, что родительская программа не получит управления после завершения дочерней

Ниже мы привели исходный текст программы SPARM1 (листинг 3.6), которая запускает программу parm.com с помощью функции spawnlpe. Эта функция входит в стандартную библиотеку Borland C++ и позволяет не только запустить программу, но и сформировать для нее среду, а также передать параметры.


Листинг 3.6. Файл sparm1\sparm1.cpp


#include <stdio.h>
#include <conio.h>
#include <process.h>

int main(void)
{
  char *env[] = { "PARMVAR=d:\\VARS", NULL };
  int rc;

  rc = spawnlpe(P_WAIT ,"parm","parm",
    "Parm1", "Parm2", NULL, env);

  if(rc == -1)
    printf("Невозможно запустить процесс");
  else
    printf("\nПроцесс завершен");
  return rc;
}

[Назад] [Содеожание] [Дальше]