| 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);
  }
}
 | 


![[Назад]](../../prev.gif)
![[Содеожание]](../../sod.gif)
![[Дальше]](../../next.gif)