Обработка ошибок

Источник: thalion

Обработчик ошибок.

Мы должны создать что-то вроде системы визуализации и контроля над ошибками. Т.к. вывод текста с помощью GDI (Graphical Device Interface) не очень быстрый, то мы будем записывать наши ошибки в текстовый файл. Еще мы добавим возможность выхода из программы при возникновении ошибки. Создадим класс CError для выполнения всех этих вещей. Прототип класса приведен ниже:

class CError
{ 
  public: 
    FILE *fErrorLog; 
    bool bQuit; 
    LPSTR lpzMessage; 

    CError (LPSTR, bool); 
    ~CError (); 

    ProcessError (DWORD); 
};

fErrorLog - указатель на файл, в который мы будем записывать все ошибки.

bQuit - переменная булевского типа. Значение этой переменной - надо или нет закрывать программу, если произошла ошибка.

lpzMessage - текущее сообщение об ошибке. Память под сообщение будет выделяться динамически при возникновении ошибки для лучшего быстродействия в плане использования памяти и customizability.

СError() - Конструктор нашего класса. Вызывается при объявлении экземпляра нашего класса. Получает два параметра- строку с именем файла для записи ошибок и переменную булевского типа, true означает необходимость закрытия программы при возникновении ошибки, false не означает необходимость закрытия программы при возникновении ошибки.

~CError() - Деструктор нашего класса. Вызывается при уничтожении экземпляра нашего класса.

ProcessError() - Эта функция будет выполнять основную работу по обработке ошибок.

Теперь непосредственно реализация класса. В первую очередь напишем конструктор и деструктор:

CError::CError (LPSTR lpzFileName, bool bQuitOnError) 
{
  fErrorLog = fopen (lpzFileName, "wt"); 
  bQuit = bQuitOnError; 
} 

CError::~CError () 
{ 
}

Конструктор очень прост. Он всего лишь открывает файл (имя файла- первый параметр) для записи в текстовом режиме и устанавливает флаг выхода (bQuit) равным значению второго параметра.
Деструктор пока пуст.

Теперь главная часть нашего обработчика ошибок. Пока она очень простая, но будет увеличиваться по мере добавления новых ошибок.

CError::ProcessError (DWORD dwError)
{
  DWORD dwMsgSize;

  switch (dwError) 
  {
    default:
      dwMsgSize = strlen ("Unkown error:\n");
      lpzMessage = (LPSTR) malloc (dwMsgSize + 1);
      strcpy (lpzMessage, "Unkown error:\n");
      break;
  }
  if (fErrorLog != NULL)
  {
    fprintf (fErrorLog, lpzMessage);
  }
  if (lpzMessage != NULL)
  {
    free (lpzMessage);
  }
  if (bQuit == true)
  {
    if (fErrorLog != NULL)
    {
      fclose (fErrorLog);
    }

    PostQuitMessage (dwError);
  }

  return 0;
} ;

Сначала, мы объявляем переменную для запоминания длины строки с описанием ошибки. После этого мы используем оператор switch, что бы узнать, что у нас за ошибка. На данный момент используется только default (и все ошибки у нас обрабатываются одинаково - записываем в файл строку "Unkown error:"). Он делает три вещи: вычисляет длину строки (описание ошибки), выделяет под нее память и записывает эту строку в переменную нашего класса, lpzMessage. Далее мы проверяем необходимость записи ошибки в файл, и, если это нужно, записываем ее. После этого мы освобождаем память, выделенную под нашу строку, и в конце проверяем флаг bQuit- надо ли закрыть программу и файл ( файл закрываем, только если он открыт :). Если надо - делаем.

Комментарии.

Первое - когда понадобится добавить ошибку, мы должны вставить код до default.
Второе - мы не делаем никаких проверок (удачно ли открылся файл, правильно ли выделилась память и т.д.). Это ваше домашнее задание.

Это все об обработке ошибок.

Использование класса CError.

В первую очередь надо объявить экземпляр класса:
CError ErrorHandling ("errors.log", true);

Теперь добавим в наше Win32 приложение обработчик ошибок, который мы написали выше.

К примеру, мы хотим обработать ошибку, которая возникает при неудачной регистрации класса окна. Для этого в файле Error.h (там у нас прототип нашего класса) пишем

#define ERROR_REGISTER_CLASS 1

В функции ProcessError надо добавить следующий кусок кода (перед default):

  case ERROR_REGISTER_CLASS:
    dwMsgSize = strlen ("Could'nt register class...\n");
    lpzMessage = (LPSTR) malloc (dwMsgSize + 1);
    strcpy (lpzMessage, "Could'nt register class...\n");
    break;

Регистрация будет выглядеть так:

  if (!RegisterClass(&wc))
  {
    ErrorHandling.ProcessError (ERROR_REGISTER_CLASS);
    return (false);
  }

Теперь, если регистрация класса завершилась не успешно, в файл errors.log будет записано Could'nt register class..., а программа завершит свою работу


Страница сайта http://www.interface.ru
Оригинал находится по адресу http://www.interface.ru/home.asp?artId=22087