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 -