Автор: mabu (Корпорация «Пакетные файлы»)

Опубликовано:

Исправлено:

Версия документа: 1

Тип данных HRESULT

HRESULT содержит информацию о результате вызова функции. Хотя из названия HRESULT можно было бы заключить, что это описатель (Handle) результата, на самом деле это не так. Название возникло по историческим причинам, просто расшифровывай его как «вот результат» (here is the result). HRESULT похож на код ошибки Windows, но это не одно и то же, и смешивать их не следует.

Внутреннее устройство HRESULT

В заголовочном файле winnt.bi (входит в windows.bi) тип данных HRESULT описан как 32‐битное знаковое целое число:

Type HRESULT As LONG

Детальный разбор

Биты числа313029282726 25 24 23 22 21 20 19 18 17 1615 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
ОписаниеSeverityRCNrFacilityКод возврата
Бит 31:
Признак критичности: 1 если произошла ошибка, 0 при успешном результате.
Биты с 30 по 27:
Зарезервированы.
Биты с 26 по 16:
Идентификатор средства: какая часть операционной системы выдаёт данный код возврата.
Биты с 15 по 0:
Код ошибки или причина успеха. Определяется корпорацией Microsoft или пользователем.

Признак критичности

Бит 31 (Severity) — это признак критичности. Позволяет использовать HRESULT для индикации как успешного выполнения функций, так и при ошибке.

Константа критичностиЗначениеОписание
SEVERITY_SUCCESS0Функция отработала успешно
SEVERITY_ERROR1Функция завершилась ошибкой

Идентификатор средства

Пятнадцать битов — с 30-го по 16-й — содержат идентификатор средства (Facility). Он указывает, какая часть операционной системы выдаёт данный код возврата. Поскольку операционную систему разрабатывает корпорация Microsoft, она зарезервировала право определения идентификаторов средств за собой.

Константа идентификатора средстваЗначениеИсточник ошибки
FACILITY_NULL0Стандартные коды возврата
FACILITY_RPC1Удалённый вызов процедур RPC
FACILITY_DISPATCH2Объект автоматизации
FACILITY_STORAGE3Хранилище OLE
FACILITY_ITF4COM или OLE интерфейс сторонних разработчиков
FACILITY_WIN327Декорированная ошибка функций Windows
FACILITY_WINDOWS8Подсистема Windows
FACILITY_SECURITY9Уровень безопасности

В том случае, если стандартных значений недостаточно, то при создании собственных HRESULT следует устанавливать идентификатор средства в FACILITY_ITF.

Смысл кода возврата, отмеченного с помощью FACILITY_ITF, специфичен для возвращающих его функций и является уникальным только в пределах данной функции. Одно и то же значение кода возврата в FACILITY_ITF, возвращаемое двумя различными функциями, может иметь разные значения.

Иногда функция вызывает другие функции, возвращающие HRESULT и отмеченные FACILITY_ITF. В этом случае такие коды возврата следует преобразовывать в специфичные для твоей функции; не следует отдавать их «как есть».

Все COM‐определённые коды FACILITY_ITF имеют значение кода в диапазоне &h0000-&h01FF. Хотя использование любых кодов в FACILITY_ITF является законным, рекомендуется использовать только значения кода в диапазоне &h0200-&hFFFF для уменьшения путаницы с любыми COM‐определёнными ошибками.

Некоторые предопределённые HRESULT

В таблице приведены часто используемые константы HRESULT. По соглашению в названиях успешных кодов содержится S_, а в названиях кодов ошибок E_.

КонстантаЗначениеОписание
S_OK&h00000000Функция отработала успешно. В некоторых случаях этот код также означает логическую истину.
S_FALSE&h00000001Функция отработала успешно и возвращает логическую ложь. Это несколько противоречит обычной практике программирования, где 0 — это ложь, а не-0 — истина.
E_PENDING&h8000000AДанные, необходимые для завершения операции, пока отсутствуют.
E_NOTIMPL&h80004001Метод не реализован.
E_NOINTERFACE&h80004002Запрашиваемый интерфейс не поддерживается.
E_POINTER&h80004003Указатель недействителен.
E_ABORT&h80004004Операция прервана.
E_FAIL&h80004005Ошибка по неуказанной причине.
E_UNEXPECTED&h8000FFFFПроизошёл катастрофический сбой.
E_ACCESSDENIED&h80070005Доступ запрещён.
E_HANDLE&h80070006Описатель недействителен.
E_OUTOFMEMORY&h8007000EНевозможно выделить память.
E_INVALIDARG&h80070057Один или несколько аргументов неправильные.

Большой и длинный список HRESULT можно найти в статье на MSDN «HRESULT Values».

Использование HRESULT

Макросы SUCCEEDED и FAILED

Для проверки успешного или ошибочного результата функции нельзя сравнивать HRESULT с каким‐либо одним кодом. Например, если функция завершилась успешно, то нельзя ожидать возврата только S_OK, и наоборот — при ошибке нелья ждать только E_FAIL. Следует использовать предопределённые макросы SUCCEEDED и FAILED.

' Вызываем функцию и получаем HRESULT:
Dim hr As HRESULT = SomeFunction(param)

' Не делай так:
If hr = E_FAIL Then
    Print "Ошибка"
End If
If hr = S_OK Then
    Print "Успешно"
End If

' Следует делать так:

' Проверка на ошибку:
If FAILED(hr) Then
    Print "Ошибка"
End If

' Проверка на успех:
If SUCCEEDED(hr) Then
    Print "Успешно"
End If

Макрос HRESULT_CODE

Получает код возврата.

Dim hr As HRESULT = SomeFunction(param)
Dim Code As Integer = HRESULT_CODE(hr)

Макрос HRESULT_FACILITY

Получает идентификатор средства.

Dim hr As HRESULT = SomeFunction(param)
Dim Facility As Integer = HRESULT_FACILITY(hr)

Макрос HRESULT_SEVERITY

Получает признак критичности.

Dim hr As HRESULT = SomeFunction(param)
Dim Severity As Integer = HRESULT_SEVERITY(hr)

Макрос MAKE_HRESULT

Создаёт собственный HRESULT. Все идентификаторы средств зарезервировала за собой корпорация Microsoft, поэтому стороннему разработчику следует использовать FACILITY_ITF, а код возврата начинать с &h0200.

' Создаём собственный HRESULT с ошибкой:
Const CUSTOM_E_PROTOCOLPERMISSION As HRESULT = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, &h0201)

' Создаём собственный HRESULT с успехом:
Const CUSTOM_S_PROTOCOLACCESS As HRESULT = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_ITF, &h0201)

При именовании констант собственных HRESULT хорошей практикой является приписывание слева имени компонента или приложения. Например:

AIRPLANE_E_LANDINGWITHGEARUP
HELICOPTER_S_ROTORRPMGREEN

Макрос HRESULT_FROM_WIN32

Создаёт HRESULT из ошибки Windows. В этом случае признак критичности автоматически принимает значение SEVERITY_ERROR, а идентификатор средства — FACILITY_WIN32.

' Получаем код ошибки Windows:
Dim dwError As DWORD = GetLastError()

' Упаковываем его в HRESULT:
Dim hr As HRESULT = HRESULT_FROM_WIN32(dwError)