русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Программирование субпроцессов


Дата добавления: 2015-06-12; просмотров: 901; Нарушение авторских прав


16.6.1.1. Процедура SwapVectors. При запуске среды Турбо Паскаль или созданного в ней выполнимого файла первым делом происходит смена ряда системных векторов прерываний на векторы отладчика среды и системной библиотеки. Однако адреса системных векторов не теряются, а запоминаются в переменных типа Pointer с именами SaveIntNN, где NN — номер прерывания (эти переменные являются предопределенными и привносятся вместе с системной библиотекой).

Пока программа работает сама по себе, нет особой необходимости восстанавливать системные векторы. Но если в программе организуется запуск субпроцесса, то будет разумнее, если он будет использовать именно системные векторы прерываний, а не специальные.

Процедура SwapVectors восстанавливает векторы прерываний, которые сохранены в переменных SaveIntNN, записывая одновременно в эти же переменные предыдущие векторы. Поэтому второй вызов SwapVectors вновь восстановит «отключенные» процедуры прерываний и сохранит в переменных последние активные адреса. Вообще говоря, можно даже взять за правило, чтобы в текстах программ соблюдалось требование четности вызовов процедуры SwapVectors.

Обычно эта процедура используется как «обрамляющая» для вызова Exec и в тех случаях, когда надо вернуться на время к исходным векторам, т.е. к тем, что были до запуска программы. О {379} номерах сохраняемых прерываний можно справиться в интерактивной подсказке среды программирования по модулю System.

16.6.1.2. Процедура Ехес( ExeFile, ComLine : String ). Эта процедура служит для запуска субпроцесса. Программа, в которой используются вызовы процедуры Exec, должна иметь в своем начале директиву распределения памяти {$М...}. Кроме того, рекомендуется до вызова Exec и сразу после него вставлять процедуру SwapVectors.

В процедуру передается два строковых аргумента: ExeFile — имя файла или полное имя файла (в обоих случаях обязательно указывать расширение имени) — это просто имя того файла, который нужно «запустить» из программы; ComLine — строка из аргументов, которые передаются запускаемому файлу.



Рассмотрим пример. Пусть в командной строке MS-DOS дается команда

С:\> format a: /s

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

Ехес( 'format.com', 'a: /s' );

или даже

Ехес( 'c:\dos\format.com', 'a: /s' );

если файл format.com лежит не в текущем каталоге, а в C:\DOS.

Строка ComLine может быть и пустой. Это означает, что в запускаемую программу не передаются никакие параметры. Имя запускаемого файла всегда должно присутствовать.

Второй пример: в строке MS-DOS слияние файлов задается командой

С:\> copy a.txt + b.txt c.txt

Но COPY — встроенная команда командного процессора и не является запускаемым файлом. Чтобы реализовать ее как субпроцесс, необходимо запускать командный процессор COMMAND.COM и передавать ему текст команды в виде параметров:

Ехес( 'connmand.com', '/с copy a.txt+b.txt c.txt' );

Важно не забывать включить в командную строку первым по счету ключ /c для командного процессора. Если забыть это сделать, то получится «выход в DOS», и вернуться из субпроцесса можно будет только через подачу команды EXIT с клавиатуры. Ключ /р тоже не годится для субпроцесса, поскольку заставляет выполниться файл AUTOEXEC.BAT, что вряд ли к месту при запуске субпроцесса. А {380} ключ /c выполнит команды из строки и автоматически завершит субпроцесс.

При запуске командного процессора через процедуру Exec более правильным будет вставлять полное его имя, а оно, в свою очередь, может быть получено автоматически через функцию модуля DOS GetEnv. В этом случае организация выхода в DOS для свободной работы с возвратом по команде EXIT, например, запишется следующим образом:

Ехес( GetEnv( 'COMSPEC' ), '' );

Можно через командный процессор запускать и самостоятельные файлы. Так, пример с форматированием может быть переписан в виде

Ехес( GetEnv( 'COMSPEC' ), '/с format a: /s' );

Обращаем внимание, что здесь расширение '.СОМ' у команды format уже не обязательно. Подобный запуск имеет свои особенности. Первая — это незначительный перерасход памяти, и им можно пренебречь. Вторая особенность важнее: если запускается субпроцесс, то можно при помощи функции DosExitCode проанализировать, чем и как он закончился. Написав, например, в программе

Exec( 'subproc.exe', Parameters );

можно быть уверенным, что анализ завершения субпроцесса будет соответствовать действительности. Но запуск

Exec( GetEnv( 'COMSPEC' ), '/с subproc '+Parameters );

скорее всего даст нормальное завершение субпроцесса, даже если subproc.exe сломает дисковод, сожжет монитор и завершится фатальной ошибкой. Просто в этом случае будет рассматриваться работа самого процессора COMMAND.COM, а не того субпроцесса, который он запускает и выполняет. А процессор редко дает сбои. Следует помнить об этом внутреннем различии, хотя внешний эффект будет неразличим (если, конечно, речь идет не о сжигании мониторов!).

О функции DosExitCode речь еще пойдет ниже. Кроме нее, можно анализировать ход выполнения субпроцесса через системную переменную модуля DOS DosError. После выполнения вызова Exec переменная DosError может содержать значения:

0 — все в порядке, нормальное выполнение;

2 — не найден файл-субпроцесс;

8 — не хватает памяти для запуска;

10 — несоответствие среды DOS;

11 — ошибка в формате команд. {381}

Появление значения DosError, равного 8, говорит о том, что надо повысить значение максимального размера кучи в директиве компилятора {$М ... }.

Сбой в субпроцессе или даже невозможность его запустить зачастую не приводят ни к каким внешним эффектам — просто ничего не происходит. И определить, в чем ошибка, можно только через переменную DosError и функцию DosExitCode. Пример программы, запускающей различные субпроцессы, дан после описания функции DosExitCode (рис. 16.17):

16.6.1.3. Функция DosExitCode : Word. Эта функция анализирует завершение субпроцесса. В возвращаемом значении типа Word скомбинированы два значения. Старший байт содержит одно из значений, приведенных в табл. 16.8.

Таблица 16.8

Hi Значение кода
Субпроцесс был прерван нажатием Ctrl+Break (по прерыванию 23Н)
Субпроцесс был прерван из-за ошибки какого-либо устройства
Субпроцесс завершился процедурой Keep и остался резидентным

Младший байт содержит код завершения программы-субпроцесса, переданный через процедуру завершения: Halt(n) или Keep(n), где n — код окончания. Если таких команд в программе не было, то код завершения будет равен 0.

На рис. 16.17 приведен пример, объединяющий процедуры и функции организации субпроцессов.

{$М 1512, 0, 0 ресурсы для запускающей программы } USES DOS, CRT; {Функция запускает файл ExeFile с параметрами Parameters и возвращает логическое значение True, если запуск был удачен. Коды завершения субпроцесса возвращаются в переменных ErrorLevel и ExitHiByte. }

Рис. 16.17 {382}

FUNCTION Execute( ExeFile, Parameters : String; VAR ErrorLevel, ExitHiByte : Byte ) : Boolean; VAR Wrd : Word; { промежуточная переменная } BEGIN SwapVectors; { установка векторов DOS } Exec(ExeFile, Parameters); { сам запуск субпроцесса } SwapVectors; { возврат векторов TURBO } Wrd := DosExitCode; { запомним код завершения } ErrorLevel := Lo( Wrd ); { код выхода из процесса } ExitHiByte := Hi( Wrd ); { код способа выхода } Execute := False; { пусть сначала будет так } case DosError of { анализ вызова Exec } 0 : begin { все в порядке } Execute := True; { Меняем значение функции } Exit { и выходим из нее } end; 2 : WriteLn(#10'He найден файл ', ExeFile ); 8 : WriteLn(#10'He хватает памяти для субпроцесса ) else WriteLn(#10'Ошибка DOS номер ', DosError ) end {case} END; VAR { ===== ПРИМЕР ВЫЗОВОВ ==== } Er, Ex : Byte; Ch : Char; BEGIN ClrScr; { очистка экрана } CheckBreak := True; ' Repeat { "вечный" цикл } WriteLn( 'Нажмите :' ); WriteLn{ ' ':15, '[D] - для выхода в DOS' ); WriteLn( ‘’:15, '[S] - для запуска субпроцесса' ); WriteLn( ‘’:15, '[Q] - для завершения работы' ); repeat Ch := UpCase( ReadKey ) { Выборочный опрос } until ( Ch in [ 'D','S','Q'] ); { клавиатуры. } case Ch of { Действия : } 'D' : begin { 1.Выход в MS-DOS. } HighVideo; Write( #10'Для возврата введите EXIT...' ); LowVideo; if Execute(GetEnv('COMSPEC'),' ',Er,Ex) then; end;

Рис. 16.17 {383}

'S' : begin { 2. Запуск файла. } if not Execute('outer.exe',' ', Er, Ex ) then Halt; { запуск неудачен } if Ex = 1 then { Вы нажали ^Break:} WriteLn(#10'Процесс прерван с консоли.' ); end; 'Q' : Exit { 3. Выход из программы. } end; {case} until False { условие "вечного" цикла } END.

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

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

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

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

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

{$М 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 {385}

{ Запускающая часть программы } 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 (окончание) {386}



<== предыдущая лекция | следующая лекция ==>
Организация субпроцессов и резидентных программ | Низкоуровневые средства работы с принтером


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.909 сек.