16.6.2. Процедура Keep и резидентные программы

Процедура Кеер( ExitCode : Word ), пожалуй, наименее описанная в руководстве по Турбо Паскалю. Ее назначение — завершать выполнение программы, выдавая в DOS код, заданный параметром ExitCode и оставлять ее в памяти ПЭВМ, т.е. делать программу резидентно находящейся в памяти. Ставится эта процедура в тексте программы последней по очередности выполнения. Внешне она аналогична процедуре Halt(n), но в отличие от последней резервирует память. Программы, разрабатываемые как резидентные, должны обязательно иметь в первых строках директиву распределения памяти {$М ... } , в которой указываются необходимые для резервирования объемы памяти под стек и кучу (динамические объекты и данные).

Организация резидентных программ — дело достаточно сложное и требующее хороших системных знаний. Ведь мало оставить программу в памяти ПЭВМ — надо еще «заставить» ее реагировать на прерывания, возвращать управление и т.п. Это подразумевает наличие в тексте вставок машинных кодов и процедур с директивой interrupt, что вовсе не упрощает написание программ. Тяжело дается и отладка «резидентов» — после каждой неудачи, как правило, приходится перезапускать ПЭВМ.

Тем не менее ниже мы приводим пример резидентной программы. Она использует ряд функций модуля CRT и специальные приемы определения начала видеопамяти (см. разд. 20.1) и копирования экрана процедурой Move (рис. 16.18).

- 385 -

| { $М 1024, 0, 0} { директивы распределения памяти }

| PROGRAM HideScr;

{ Резидентная программа скрытия экрана от любопытных глаз во время отсутствия программиста. Работает во всех режимах текста и использует пароль (если задан) для возврата }

| USES CRT, DOS;

| VAR

| OldAttr : Byte; { последний цвет символов }

| WX, WY : Byte; { последнее место курсора }

| ScrAddr : Word; { сегмент начала экрана }

| Buffer : Array [1..8000] of Byte; {буфер для экрана }

| PS : String[20]; { нужна для ввода пароля }

| b : Boolean; { значение параметра BREAK }

| CONST

| Password : String[20] = ' '; { задаваемый пароль входа }

| {$F+}

| PROCEDURE MyInt05H; INTERRUPT; { процедура прерывания }

| VAR с : Char;

| BEGIN

| GetCBreak(b); { запоминание статуса BREAK }

| SetCBreak( False ); { отключение проверки ^Break }

| OldAttr := TextAttr; { запоминание последнего цвета }

| WX := WhereX; { запоминание позиции курсора }

| WY := WhereY;

| TextAttr := 7; { неяркий цвет }

| if (Mem[0:$410] and $30) = $30 { начало экрана: }

| then ScrAddr := $B000 { моно – режим }

| else ScrAddr := $B800; { цветной режим }

| Move(Mem[ScrAddr:0],buffer,8000); { экран -> в буфер }

| FillChar(Mem[ScrAddr:0], 8000, 0); { затемнение экрана }

| repeat {цикл опроса пароля }

| ClrScr; { гашение экрана }

| repeat until KeyPressed; { ждать до нажатия }

| while KeyPressed do с := ReadKey;{ сброс нажатия }

| Write( #10'Пароль возврата? ' ); { Ввод пароля, но }

| TextAttr := 0; ReadLn(PS); TextAttr := 7; { вслепую! }

| until PS=Password; { Пароль введен ? }

| Move(buffer, Mem[ScrAddr:0],8000); { буфер-> на экран }

| GotoXY( WX, WY ); { курсор на место }

| TextAttr := OldAttr; { снова старый цвет }

| SetCBreak(b); { восстановление статуса BREAK }

| END;

| {$F-}

Рис. 16.18

- 386 -

| { Запускающая часть программы }

| BEGIN

| CheckBreak := False;

| Write(#10#13'Программа закрытия экрана'#10#13

| Запуск');

| Write(#10' HIDESCR [пароль возврата]'#10#10#13);

| WriteLn( 'Для включения нажмите PrintScreen'#10#13 );

| Password := ParamStr(1); {пароль из командной строки }

| SetIntVec($00,SaveInt00); {Необходимые операции подго- }

| SetIntVec($1B,SaveInt1B); {товки резидентной работы }

| SetIntVec($05,@MyInt05H); {подстановка прерывания 05 }

| Кеер(0); { <-- То, ради чего построен пример! }

| END.

Рис. 16.18 (окончание)

- 387 -