MS-DOS для программиста© Александр Фролов, Григорий ФроловТом 19, М.: Диалог-МИФИ, 1995, 253 стр. 3.12. Обработка критических ошибокОперационная система MS-DOS позволяет программам устанавливать собственный обработчик критических ошибок аппаратуры. Мы уже говорили о том, что вектор 0000h:0090h, соответствующий прерыванию INT 24h , содержит адрес обработчика критических ошибок. Этот обработчик получает управление от операционной системы, когда драйвер какого-либо устройства обнаруживает ошибку аппаратуры. Обратите внимание на то, что обработчик критических ошибок не вызывается при работе с диском через прерывания INT 25h или INT 26h. Тем более, он не вызывается при работе с диском на уровне прерывания INT 13h . При запуске программы операционная система MS-DOS копирует адрес обработчика в префикс сегмента программы PSP, а после завершения работы программы - восстанавливает его из PSP. Стандартный обработчик MS-DOS выводит на экран сообщение: Abort, Retry, Ignore, Fail? Если ваша программа должна сама обрабатывать ошибки аппаратуры, она может установить свой собственный обработчик критических ошибок. Анализ регистровКогда обработчик получает управление, регистры
процессора содержат информацию, необходимую для
определения причины и места появления ошибки:
Обработчик критических ошибок не должен пользоваться функциями MS-DOS с кодами, большими чем 0Ch (из-за того, что функции MS-DOS не реентерабельны). Программа обработки критических ошибок может вывести на экран сообщение об ошибке и запросить оператора о необходимых действиях. Ей разрешено также получить дополнительную уточняющую информацию об ошибке с помощью функции 59h прерывания INT 21h или узнать версию MS-DOS с помощью функции 30h этого же прерывания. Дополнительная информация об устройстве, в котором произошла ошибка, может быть получена с использованием адреса заголовка драйвера устройства, который передается операционной системой при вызове обработчика в регистрах BP:SI. Анализ стекаДля определения номера функции MS-DOS, в которой
произошла критическая ошибка,
программа-обработчик может выполнить анализ
стека. Когда обработчик получает управление,
стек имеет следующую структуру:
Выполнив анализ регистра AH, можно определить номер функции MS-DOS, при вызове которой произошла ошибка, а зная содержимое остальных регистров - и все параметры этой функции. Код действияПосле выполнения всех необходимых действий
программа обработки критических ошибок должна
возвратить в регистре AL код действия, которое
должна выполнить операционная система для
обработки данной ошибки:
При открытии файлов с помощью функции 6Ch программа может заблокировать вызов обработчика критических ошибок. Функции библиотеки Borland C++Для составления программы обработки критических ошибок вы можете воспользоваться языком ассемблера или функциями стандартной библиотеки Borland C++ с именами _dos_getvect , _dos_setvect , _chain_intr . Однако лучше всего использовать специально предназначенные для этого функции _harderr , _hardresume и _hardretn . _harderrФункция _harderr предназначена для установки нового обработчика критических ошибок, она имеет следующий прототип: void _harderr (void (far *handler)()); Параметр handler - указатель на новую функцию обработки критических ошибок. _hardresumeФункция _hardresume и описанная ниже функция _hardretn должны быть использованы в обработчике критических ошибок, установленном функцией _harderr . Функция _hardresume возвращает управление операционной системе, она имеет прототип: _hardresume (int result); Параметр result может иметь следующие значения (в
соответствии с необходимыми действиями):
Эти параметры описаны в файле dos.h. _hardretnФункция _hardretn возвращает управление непосредственно программе, передавая ей код ошибки, определяемый параметром функции error: void _hardretn (int error); При этом программа получает код ошибки error после возврата из вызванной ей функции MS-DOS. Если ошибка произошла при выполнении функции с номером, большим чем 38h, дополнительно устанавливается флаг переноса. Если номер функции был меньше указанного значения, в регистр AL записывается величина FFh. Функция обработки критических ошибокФункция обработки критических ошибок handler имеет следующие параметры: void far handler(unsigned deverror, unsigned errcode, unsigned far *devhdr); Первый параметр - код ошибки устройства. Он равен содержимому регистра AX при вызове обработчика прерывания INT 24h . Аналогично, параметр errcode соответствует содержимому регистра DI - код ошибки. Третий параметр devhdr - это указатель на заголовок драйвера устройства (передаваемый в регистрах BP:SI). Программа CRITERRДля демонстрации использования функций установки обработчика критических ошибок приведем программу, которая пытается создать каталог на диске А:. Эта программа сама обрабатывает критические ошибки, запрашивая у оператора информацию о необходимых действиях. Листинг 3.8. Файл criterr\criterr.cpp
// Эту программу можно запускать только из командной
// строки. При запуске из интегрированной среды
// Borland C++ возможен конфликт с используемым в этих
// средах обработчиком критических ошибок
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <direct.h>
#include <string.h>
#include <dos.h>
#include <bios.h>
void far hhandler(unsigned deverr,
unsigned doserr, unsigned far *hdr);
void _bios_str(char *p);
int main()
{
// Устанавливаем обработчик критических ошибок
_harderr (hhandler);
// Моделируем критическую ошибку.
// Выполняем попытку создать каталог на диске А:.
// Если мы "забудем" вставить в дисковод
// дискету, будет вызван обработчик
// критической ошибки
printf("\nВставьте (или не вставляйте) "
"дискету в дисковод A:"
"\nи нажмите любую клавишу...\n");
getch();
// Создаем каталог
if(mkdir ("a:\\test_ctl"))
{
printf("\nОшибка при создании каталога");
return(-1);
}
else
{
// Удаляем только что созданный каталог
rmdir ("a:test_ctl");
}
return 0;
}
// Новый обработчик критических ошибок
#pragma argsused
void far hhandler(unsigned deverr,
unsigned doserr, unsigned far *hdr)
{
int ch;
static char buf[200];
// Выводим сообщение о критической ошибке
sprintf(buf,"\n\r"
"\n\rКод ошибки устройтсва: %04.4X"
"\n\rКод ошибки DOS: %d"
"\n\r\n\r"
"\n\rВыполняемые действия:"
"\n\r 0 - повторить"
"\n\r 1 - отменить"
"\n\r 2 - завершить"
"\n\r----> ?",
deverr, doserr);
_bios_str(buf);
// Вводим ответ с клавиатуры
ch = _bios_keybrd(_KEYBRD_READ) & 0x00ff;
_bios_str("\n\r");
switch(ch)
{
case '0': // Пытаемся повторить операцию
default:
_hardresume (_HARDERR_RETRY);
case '2': // Завершаем работу программы
_hardresume (_HARDERR_ABORT);
case '1': // Возврат в DOS с кодом ошибки
_hardretn (doserr);
}
}
// Программа для вывода строки символов на экран
// с помощью функции BIOS 0Eh
void _bios_str(char *ptr)
{
union REGS inregs, outregs;
inregs.h.ah = 0x0e;
for(; *ptr; ptr++)
{
inregs.h.al = *ptr;
int86(0x10, &inregs, &outregs);
}
}
|

