Пользовательская программа может в ходе своего выполнения запустить другую программу из COM- или EXE-файла. Эта возможность обеспечивается функцией DOS 4BH.
Подфункция 0 этой функции выполняет загрузку и запуск другой программы. Для загружаемой (порожденной) программы DOS выделяет память из своего ресурса, следовательно, программа-родитель должна обеспечить наличие свободной памяти в системе (в первую очередь это относится к COM-родителям, так как при их загрузке весь ресурс памяти DOS отдается им). Для запуска программа-родитель должна сформировать строку вызова, содержащую имя файла вызываемой программы (с полным маршрутом, если файл находится не в текущем каталоге) и построить EPB (Exec Parameters Block - Блок Параметров Выполнения) - EPB содержит сегментный адрес окружения, которое копируется в сегмент окружения создаваемый для порожденной программы (если этот адрес 0,то в него копируется окружение родителя) и адреса строки параметров и двух блоков FCB, помещаемых в PSP порожденной программы. При обращении к функции 0x4B в регистр AL записывается код подфункции, в регистры DS:DX - адрес строки вызова, а в ES:BX - адрес EPB. Родитель запрашивает у оператора строку вызова, формирует EPB и обращается к функции 0x4B. Это обращение вызывает загрузку порождаемой программы и передачу ей управления. Порожденная программа получает свой PID и сообщает оператору его и PID родителя, из PSP находит свой сегмент окружения и выводит на экран окружение и строку вызова, а также строку параметров из PSP. Перед завершением порожденная программа запрашивает у оператора код завершения и завершается по функции DOS 4CH, передавая ей полученный код завершения. Программа-родитель, когда к ней возвращается управление, получает этот код завершения при помощи функции 4DH.
Текст програми завантажувача COMфайлів:
#pragma inline
#include <dos.h>
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
#include <alloc.h>
int main(int argc, char *argv[]){
int handle; //файл
unsigned bytes; //колич байт для чтения с файла
void far *beginPSP; //начало PSP
void far *farptr; //начало кучи
void far *beginfile; //начало кода
int far *ret; //установл int 20h
long flength, memory; //длина файла, колич памяти
if (argc<1) return 0; //если нет аргум
if (_dos_open(argv[1],O_RDONLY | O_BINARY,&handle)!=0){ //открытие ф
puts("\nError !\n"); return 0;
}
flength=filelength(handle);
memory=flength+16-flength%16; //выравнивание к параграфу
memory+=0x0100; //добавить PSP
farptr=(void far*)farmalloc(memory); //выдел памяти
if(farptr==NULL) { puts("\nNot enouth memory !\n"); return 0; }
beginPSP=(int far*)farptr; //вычисление начала PSP
asm mov ax,word ptr beginPSP+2
asm add ax,1 //выравнивание PSP к para
asm mov word ptr beginPSP,0
asm mov word ptr beginPSP+2,ax
ret=(int far*)beginPSP; //помещение int 20h
*ret=0xCD20;
beginfile=beginPSP; //вычисление начала кода
asm {
mov ax,beginfile+2 //пропускаем PSP
add ax,16
mov word ptr beginfile,0
mov word ptr beginfile+2,ax
}
printf("\nRun:%s ",argv[1]);
if (_dos_read(handle, beginfile, flength, &bytes) != 0) { //чтение ф
puts("\nReading failed\n"); return 0;
}
else
printf("\nRead: %d bytes read\n", bytes); //чтение n байт
close(handle); //закрытие
asm jmp goprogram
asm start dd 0 //адрес кода
goprogram:
asm {
mov ax,offset cs:end
mov cx,seg cs:end
push ds
mov bx,0
mov ds,bx
mov bx,128
mov ds:[bx],ax
mov ds:[bx+2],cx
pop ds
}
asm {
mov ax,0x100 смещение кода
mov bx,word ptr beginPSP+2
mov word ptr cs:start,ax //загружаем начало
mov word ptr cs:start+2,bx
mov ax,memory
xor dx,dx
xor cx,cx //обнуляем регистры
push di
xor di,di
push si
xor si,si
push bp
xor bp,bp
push ds
mov ds,bx //устанавл сегм регистры
push es
mov es,bx
xor ax,ax
xor bx,bx
call cs:start //jmp far
}
asm end label byte
asm {
pop es
pop ds
pop bp
pop si
pop di
}
puts("End");
farfree(farptr);
return 1;
}
Текст програми завантажувача EXEфайлів:
#include <io.h>
#include <dos.h>
#include <stdio.h>
#include <conio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
struct head_exe
{
unsigned int MZ; // 5A4Dh - признак файла .EXE ('MZ')
unsigned int PartPag; // длина последнего блока файла (обычно игнорируется)
unsigned int PageCnt; // длина файла в 512-байтных блоках
unsigned int NumTable; // число элементов в таблице настройки адресов
unsigned int HdrSize; // длина заголовка в 16-байтных параграфах
unsigned int MinMem; // минимальный объем памяти
unsigned int MaxMem; // максимальный объем памяти
unsigned int ReloSS; // сегментное смещение сегмента стека (для установки SS)
unsigned int ExeSP; // значение SP, устанавливаемое при входе
unsigned int ContrSum; // контрольная сумма - ноль минус сумма без переноса всех слов файла
unsigned int ExeIP; // значение IP, устанавливаемое при входе (стартовый адрес)
unsigned int ReloCS; // сегментное смещение сегмента кода
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.