Библиотека программиста

«Программирование, как и любовь - это одно слово, за которым скрывается бесчисленное множество занятий»

Главная страница > Технология COM > 57. Обработка ошибок в Windows

57. Обработка ошибок в Windows

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

UINT SetErrorMode ( UINTuMode ); {UINT=LongWord}

Параметр uMode может принимать одно из следующих значений или их комбинацию:

Значение

Толкование

0

Обработка ошибок системой по умолчанию, при которой выводится сообщение об ошибке

SEM_FAILCRITICALERRORS

Система не выводит сообщение об ошибке, а посылает его (message) процессу

SEM_NOALIGNMENTFAULTEXCEPT

Для 64-битной версии Windows: система обрабатывает ошибки выравнивания невидимо для вызывающего процесса процесса и порожденных им другим процессов. После установки этого значения последующие попытки его отмены игнорируются

SEM_NOGPFAULTERRORBOX

Система не выводит сообщение об общем нарушении защиты (GP). Этот режим должен устанавливаться только отладчиками, которые обрабатывают такие ошибки самостоятельно с помощью соответствующего обработчика ИС

SEM_NOOPENFILEERRORBOX

Сообщение о не найденном файле не выводится, а передается процессу

Функция SetErrorMode возвращает предыдущий режим.

Обратить внимание пользователя на ошибку можно с помощью инвертирования (flash) заголовка окна приложения:

FlashWindow(hwnd, TRUE); Sleep(500); FlashWindow(hwnd, TRUE);

MessageBeep(MB_ICONEXCLAMATION);

Функция FlashWindowEx предоставляет дополнительные возможности по управлению визуализацией оповещения пользователя об ошибке. Она имеет такой заголовок:

function FlashWindowEx(var pfwi: FLASHWINFO): BOOL;

PFLASHWINFO = ^FLASHWINFO;

FLASHWINFO = record

cbSize: UINT;

hwnd: HWND;

dwFlags: DWORD;

uCount: UINT;

dwTimeout: DWORD;

end;

Функции обычно сообщают о наличии ошибки путем возвращения значений 0, - 1 или Null, которые могут быть проанализированы вызывающей программной единицей. Кроме того, система предоставляет возможность установить внутренний код ошибки, называемый кодом последней ошибки (last-error code). Если функция завершается успешно, она, обычно, не устанавливает код ошибки; в противном случае она может сделать это с помощью функции SetLastError:

VOID SetLastError( DWORDdwErrCode);

Бит 29 кода ошибки зарезервирован для кодов ошибок приложений и позволяет отличить их от кодов ошибок системы. Значения остальных бит определяются программистом и должны быть оговорены в описании функции. Отметим, что код ошибки поддерживается системой для каждого потока в отдельности.

Получить код ошибки можно с помощью функции GetLastError:

DWORD GetLastError(VOID);

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

Значения системных кодов сообщений (их несколько сотен) об ошибках можно узнать из файла Windows.h или из раздела MSDN System Error Codes.

Приложение для аварийного завершения работы может использовать функцию FatalAppExit:

VOID FatalAppExit(

UINT uAction, // зарезервировано

LPCTSTR lpMessageText // строка с завершающим нулем длиной до 35 символов

);

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

Примечание. Попытки воспользоваться функцией SetErrorMode успеха не имели (проект TestErrorHandling)

Procedure TForm1.Button1Click(Sender: TObject);

var

f : TextFile;

E : TEdit;

p : PInteger;

Begin

// SetErrorMode(SEM_FAILCRITICALERRORS);

// SetErrorMode(SEM_NOOPENFILEERRORBOX);

{ E.Text:='aaaaaaaaaaaaa'; { меняется заголовок формы, а ошибки нет!}

{ FatalAppExit(0,'Приплыли!'); { работает }

ShowMessage(IntToStr(

SetErrorMode(SEM_NOGPFAULTERRORBOX)));

E:=nil;

E.Text:='aaaaaaaaaaaaa'; { все равно ошибки нет!}

E.Font.Size:=13; {всегда ошибка "Access violation ..."}

{ p:=Addr(E);

p^:=123;}

{ AssignFile(f,'asd'); Reset(f); сообщение об ошибке выводится всегда}

End;

Обработка ошибок в СОМ.

Обработка ошибок при работе с СОМ объектами с точки зрения клиентского приложения основана на использовании значения HResult, возвращаемого функциями СОМ библиотек и методами СОМ объектов. Разработчик СОМ объекта со своей стороны должен приложить усилия для того, чтобы предоставить пользователям СОМ объектов возможность получить код ошибки и ее текстовое представление. Рассмотрим сначала механизм обработки ошибок клиентским приложением.

Значение HResult, возвращаемое большинством API-функций и методов СОМ, представляет собой 32-битовое целое число определенного формата:

Кодировка HResult

Биты

Обозначение

Значение

31

severity code

Бит наличия ошибки (1 – ошибка есть, 0 – ошибки нет)

27..30

reserved

Зарезервированы

16..26

facility code

Область, ответственная за ошибку

0..15

Код, идентифицирующий ошибку или предупреждение

Коды областей (facility code) зарезервированы Microsoft и являются уникальными. В настоящее время определены коды областей, приведенные в следующей таблице.

Константа

Значение

Описание

FACILITY_NULL

0

Общие коды состояния (типа S_OK)

FACILITY_RPC

1

Ошибки RPC

FACILITY_DISPATCH

2

Ошибки интерфейса IDispatch для позднего связывания

FACILITY_STORAGE

3

Ошибки IStorage и IStream. Коды со значением до 256, имеют тот же смысл, что и коды ошибок DOS

FACILITY_ITF

4

Коды состояния, возвращаемые большинством методов интерфейсов. Действительный смысл ошибки определяется каждым интерфейсом в отдельности. Из этого следует, что два одинаковых значения, возвращенные разными интерфейсами, могут иметь различный смысл

FACILITY_WIN32

7

Коды ошибок функций Win32, возвращающих значения типа HResult

FACILITY_WINDOWS

8

Дополнительные коды ошибок интерфейсов, определенных Microsoft

Для задания кодов ошибок в Windows используются константы в таком формате:

<Facility>_<Severity>_<Reason>

Здесь:

<Facility> – имя области или другой отличающий идентификатор (исключается для FACILITY_NULL);

<Severity> – буква S или E, обозначающая успех или ошибку;

<Reason> – идентификатор, поясняющий причину ошибки.

Примеры:

S_OK (FACILITY_NULL)

STG_E_FILENOTFOUND (FACILITY_STORAGE)

DISP_E_EXCEPTION (FACILITY_DISPATCH)

Эти и другие коды ошибок определены в Windows, а в Delphi они определены в файле Windows.pas.

Для анализа и обработки значений HResult можно использовать следующие функции Delphi, определенные в Windows.pas.

Функция

Назначение

function Succeeded(Status: HRESULT): BOOL;

Возвращает true, если значение Status не указывает на ошибку

function Failed(Status: HRESULT): BOOL;

Возвращает false, если значение Status указывает на ошибку

function IsError(Status: HRESULT): BOOL;

Возвращает true, если значение Status указывает на ошибку

function HResultCode(hr: HRESULT): Integer;

Возвращает целочисленное значение аргумента

function HResultFacility(hr: HRESULT): Integer;

Возвращает код области facility

function HResultSeverity(hr: HRESULT): Integer;

Возвращает код наличия или отсутсвия ошибки severity

function MakeResult(sev, fac, code: Integer): HResult;

Возвращает значение HResult, полученное как комбинация кодов Severity, Facility и Reason

Приведенные в таблице функции аналогичны соответствующим функциям и макросам, определенным в Windows.

Для получения текстового описания какой-либо ошибки можно воспользоваться файлом Windows.pas или файлом Windows.h (секции файлов OLE Error Codes) путем поиска полученного значения HResult (в шестнадцатеричной системе). Другой и более удобный способ – это использование утилиты Error Lookup из Microsoft Visual Studio Tools. Единственное входное данное для нее – это код ошибки. Вот пример ее использования:



Еще один способ получения текстового описания ошибки является использование функции Win32 API FormatMessage, главным недостатком которой является довольно громоздкий формат ее вызова.

Еще описания ошибок можно найти в файлt OleDbErr.mc (Microsoft Visual Studio). Вот фрагмент этого файла с описанием одной из ошибок:

MessageId=0x0e01 Facility=Interface Severity=CoError
SymbolicName = DB_E_ROWLIMITEXCEEDED

Language=English

Creating another row would have exceeded the total number of active

rows supported by the rowset





<< Предыдущая статья
«56. Апартаменты и многопоточность в СОМ»
Следующая статья >>
58. Разработка активных форм ActiveForm