КаталогИндекс раздела
НазадОглавлениеВперед


14. Обработка ошибок в DOS

14.1. Обработчик прерывания 24

При возникновении критической ошибки DOS вызывает прерывание 0x24, вектор которого указывает на обработчик критической ошибки. Стандартный обработчик критической ошибки находится в резидентной части COMMAND.COM. Эта программа выдает сообщения типа: "Device not ready/Abort, Retry, Ignore, Fail?". Но пользователь может (и это, по-видимому, предусмотрено в системе) установить свой обработчик критической ошибки, перехватив вектор его прерывания. Адрес прежнего обработчика (как мы уже видели) сохраняется в PSP программы и автоматически восстанавливается системой при завершении программы.

Когда обработчик критической ошибки получает управление, регистры содержат такую информацию:

Обработчик критической ошибки должен вернуть в регистре AX код решения:
0- игнорировать ошибку;
1- повторить операцию;
2- завершить программу;
3- снять системный вызов, в котором произошла ошибка.
Из обработчика критической ошибки нельзя обращаться к функциям DOS с номерами выше 0x0C, исключение составляет функция 0x59, о которой будет сказано ниже.

В программном примере 14.1 устанавливается собственный обработчик ошибки, который запоминает информацию об ошибке и заканчивается с кодом 3 - снять системный вызов. Информация об ошибке затем распечатывается.
Ошибочные ситуации, которые возникают при работе примера 14.1, - чтение информации с неготового диска и вывод на неготовый принтер. Читатель может самостоятельно расширить пример другими сбойными ситуациями.


/*====                    ПРИМЕР 14.1                 ====*/
/*====           Обработка  критической  ошибки       ====*/
#include   <dos.h>
#include  <stdio.h>
#define byte unsigned char
#define word unsigned int
void interrupt new_24();
void interrupt (* old_24)();  /* адрес старого обработчика критической ошибки */
/* информация об ошибке,  запомненная в обработчике */
byte save_ah,  save_al,  class,  actions;
word save_di, save_bp, save_si,   ext_code,   locate;
/*   сообщения   */
char *msg1[]= {"ИГНОРИРОВАТЬ","ПОВТОРИТЬ","СНЯТЬ"};
char *msg2[]=
     {"системная обл.","FAT","каталог","обл.данных"};
char *msg3[]={"защита от записи","неизвестное устройство",
   "диск не готов","неизвестная команда","ошибка CRC",
   "неправильная структура запроса","ошибка поиска",
   "неизвестный тип диска","сектор не найден",
   "конец бумаги","ошибка записи","ошибка чтения",
   "общий сбой","наруш.режима разделения",
   "наруш.блокировки","ошибка смены диска",
   "FCB недоступен","переполн.буфера разделения" };
union REGS rr;
struct SREGS sr;
int dos;
FILE *f;
main() {
  /* получить версию DOS */
  rr.h.ah=0x30; intdos(&rr,&rr);
  if ((dos=rr.h.al)==3) dos=0;
  /* перехват вектора */
  old_24=getvect(0x24); setvect(0x24,new_24);
  /* эксперимент 1 */
  save_ah=save_al=save_di=save_bp=save_si=0;
  /* получить адрес DPB (при неготовом диске) */
  rr.h.ah=0x32;
  rr.h.dl=2;
  intdosx(&rr,&rr,&sr);
  error_scan();
  /* эксперимент 2 */
  save_ah=save_al=save_di=save_bp=save_si=0;
  /* печатать (при неготовом принтере) */
  fprintf(stdprn,"aaa");
  error_scan();
  /* восстановление вектора (необязательно) */
  setvect(0x24,old_24);
  }
/*-------------------------------------*/
/*== Распечатка информации об ошибке ==*/
error_scan() {
int i; byte k; char *s;
  if (!(save_ah|save_al|save_di|save_bp|save_si))
    printf("Ошибки нет\n");
  else {
    printf("\nОшибка при ");
    if (save_ah&1) printf("записи, ");
    else printf("чтении, ");
    if (save_ah&0x80){
      printf("устройство ");
      s=(char far *)MK_FP(save_bp,save_si)+10;
      for (i=0; i<8; i++,s++) printf("%c",*s);
      printf("\n");
      }
    else {
      printf("диск %c\n",save_al+'A');
      printf("Место ошибки - %s\n",msg2[(save_ah>>1)&3]);
      }
    for (i=0,k=0x20; k>0x04; k>>=1,i++)
      if (save_ah&k) printf("Можно %s\n",msg1[i]);
      else printf("Нельзя %s\n",msg1[i]);
    printf("Тип ошибки - %s\n",msg3[save_di]);
    printf("РАСШИРЕННАЯ ИНФОРМАЦИЯ:\n");
    printf("   Код ошибки - %04Xh\n",ext_code);
    printf("   Класс ошибки - %02Xh\n",class);
    printf("   Действия - %02Xh\n",actions);
    printf("   Место - %02Xh\n",locate);
    }
  printf("Нажмите любую клавишу...\n"); getch();
  }
/*-------------------------------------*/
/*== Обработчик критических ситуаций ==*/
void interrupt new_24
           (bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flgs)
word bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flgs;  {
  /* сохранение основной информации об ошибке */
  save_ah=ax>>8; save_al=ax&0xff; save_di=di;
  save_bp=bp; save_si=si;
  /* получение расширенной информации об ошибке */
  rr.h.ah=0x59;  /* функция 59 */
  rr.x.bx=dos;
  intdos(&rr,&rr);
  ext_code=rr.x.ax;
  class=rr.h.bh;
  actions=rr.h.bl;
  locate=rr.h.ch;
  /* действия - отменить запрос */
  ax=3;
}

14.2. Расширенная информация об ошибке.

Начиная с DOS 2.0, те функции DOS, при выполнении которых могут возникать ошибки, индицируют наличие ошибки установкой флага CY, при этом регистр AX содержит код ошибки. Следующие коды ошибок могут возвращаться в регистре AX: 1-ошибка номера функции DOS10-ошибка в окружении 2-файл не найден11-ошибка формата 3-путь не найден12-ошибка кода доступа 4-слишком много открытых файлов13-ошибка даты 5-доступ отвергнут14-(не используется) 6-ошибка дескриптора файла15-задан неверный диск 7-ошибка в MCB16-удаление текущего оглавления 8-нехватка памяти17-не то же самое устройство 9-ошибка адреса блока памяти18-больше нет искомых файлов Начиная с версии DOS 3.0 имеется функция 0x59, выдающая расширенную информацию об ошибке. При обращении к этой функции регистр BX должен содержать номер версии DOS (0 - для версии 3). На выходе функции регистр AX содержит расширенный код ошибки, BH - класс ошибки, BL - код предполагаемых действий, CH - локализацию ошибки.

Расширенные коды ошибок:

19 - 36-соответствуют кодам 0 - 17, передаваемым обработчику критической ошибки в регистре DI;
36 - 49-зарезервировано;
50 - 60-ошибки, связанные с работой в сети;
61 - 63-ошибки спуллинга печати;
55 - 72-ошибки, связанные с работой в сети;
73 - 79-зарезервировано;
80-файл уже существует;
81-зарезервировано;
82-невозможно создать элемент каталога;
83-сбой при обработке прерывания по критической ошибке;
84-слишком много перенаправлений;
85-повторяющееся перенаправление;
86-неправильный пароль;
87-неправильный параметр;
88-ошибка в данных сети.

Классы ошибок:

1-нехватка ресурса (памяти, описателей файлов и т.п.);
2-временная ситуация;
3-превышение пользователем своих полномочий;
4-внутренняя ошибка DOS;
5-ошибка оборудования;
6-системная ошибка DOS;
7-ошибка применения (некорректный запрос, неверные параметры и т.п.);
8-запрошенный файл или другой объект найден;
9-неверный формат файла, диска и т.п.;
10-файл или другой объект захвачен другим пользователем;
11-ошибка носителя;
12-файл или другой объект уже существует;
13-неивестный класс.

Предполагаемые действия:

1-повторить операцию несколько раз;
2-повторить операцию после задержки;
3-повторить ввод данных для DOS пользователем;
4-снять задачу, выполнив операции завершения (закрытие файлов, обновление индексов, освобождение памяти и т.п.);
5-снять задачу, не выполняя операции завершения;
6-игнорировать ошибку;
7-повторить операцию после выполнения пользователем каких-то действий.

Локализация ошибки:

1-место ошибки не определено;
2-ошибка на блочном устройстве;
3-зарезервировано;
4-ошибка на символьном устройстве;
5-ошибка в памяти.

Обработчик критической ошибки в примере 14.1 обращается к функции 0x59 и запоминает также расширенную информацию об ошибке. Чтобы не перегружать пример строковыми константами на печать выводятся только коды ошибки, класса и т.д., а не смысловые сообщения.



КаталогИндекс раздела
НазадОглавлениеВперед