Раздел инициализации
Раздел инициализации программы резидентного калькулятора очень небольшой и целиком помещается в нижеследующей функции main().
void interrupt tsr_ap(); /* вход в прикладную программу */
main()
struct address
char far *p;
;
/* адрес прерывания печати экрана */
struct address far *addr = (struct address far *) 20;
addr->p = (char far *) tsr_ap;
set_vid_mem();
tsr(2000);
TSR-программа первым делом должна заменить адрес программы обработки прерывания 5 указателем функции, определенной в самой TSR-программе. Есть несколько способов изменения адреса в таблице векторных прерываний. Один из способов состоит в использовании системного вызова DOS. Однако неудобство использования функции DOS заключается в том, что она требует задания значения адресного сегмента в регистре ЕS, который недоступен при использовании функции int86(). Некоторые компиляторы, как например Турбо Си, включают специальные функции, предназначенные для установки адреса в таблице прерываний. Однако способ, предлагаемый здесь, будет работать при использовании практически любого компилятора. Функция tsr_ap() является точкой входа в прикладную часть TSR-программы. Она использует указатель на содержимое таблицы векторов, соответствующее прерыванию 5. (Напоминаем, что вектор 5 расположен по адресу 20(4х5) в таблице, поскольку каждый вектор имеет размер 4 байта. Некоторые TSR-программы восстанавливают исходное значение адреса. Но при использовании приводимых здесь программ вы должны будете перезагружать систему, чтобы восстановить исходные значения векторов прерываний.
В предыдущих разделах, проверка режима работы видеосистемы производилась динамически теми программами, которые с ней работали. Однако в данном случае это неприменимо, поскольку требует использования системных вызовов DOS. Вместо этого значение глобального указателя vid_mem устанавливается с помощью функции set_vid_mem, приводимой ниже.
set_vid_mem()
int vmode;
vmode = video_mode();
if((vmode!=2) && (vmode!=3) && (vmode!=7))
printf(" video must be in 80 column text mode");
exit (1);
/* установить соответствующий адрес видеопамяти */
if(vmode==7) vid_mem = (char far *) 0xB0000000;
else vid_mem = (char far *) 0xB8000000;
Наконец, выход из функции main() ocyществляется путем обращения к функции tsr(), приведенной ниже.
/* завершить выполнение, но оставить резидентной */
tsr(size)
unsigned size;
union REGS r;
r.h.ah = 49; /* завершить и оставить резидентной */
r.h.al = 0; /* код возврата */
r.x.dx = size;
int86(0x21, &r, &r);
Параметр size, определяемый в регистре DX, используется для того, чтобы сообщить DOS, сколько памяти требуется для размещения ТSR-программы. Размер памяти определяется в 16-байтных параграфах. Иногда бывает трудно определить, сколько памяти необходимо для размещения программы. И если в этом случае вы разделите размер загрузочного модуля вашей программы (файла с расширением .EXE) на 16, а полученную величину умножите на 2, то будете застрахованы от ошибки. Точно определить размер необходимой памяти трудно, поскольку загрузочные модули частично накладываются друг на друга при загрузке и необязательно размещаются в непрерывной области. (Если вы намереватесь продавать свои программы, то наверняка хотели бы знать точно, сколько потребуется памяти, чтобы не оказаться слишком расточительным. Наиболее просто это можно определить экспериментальным путем). Код возврата, устанавливаемый в регистре AL, передается системе.
После завершения выполнения функции маin() программа остается в памяти, и никакая другая программа не может быть загружена на ее место. Это значит, что прикладная часть программы в любой момент времени готова быть запущенной нажатием клавиши PT SCR.