HRESULT¶
HRESULT — это 32-битный целочисленный тип данных со знаком, используемый в операционных системах семейства Microsoft Windows и в COM-технологии (Component Object Model) для возврата статуса выполнения функций и методов. В отличие от традиционного булева результата, HRESULT кодирует не только факт успеха или ошибки, но и дополнительную информацию: severity (уровень серьёзности), facility (область происхождения) и код ошибки.
¶Структура и формат
HRESULT представляет собой знаковое 32-битное число (тип long в C/C++). Биты распределены следующим образом:
- Бит 31 (S) — severity (серьёзность):
0— успех (success),1— неудача (failure). - Биты 30–28 (R, C, N) — зарезервированные биты, используемые для внутренних целей (например, для кодов, возвращаемых из пользовательских заголовков).
- Биты 27–16 (Facility) — код области (facility), указывающий на подсистему, которая вернула результат (например,
FACILITY_WIN32,FACILITY_ITF,FACILITY_RPC). - Биты 15–0 (Code) — непосредственно код ошибки или статуса, уникальный в пределах данной facility.
Для удобства работы в Windows SDK определены макросы: SUCCEEDED(hr) и FAILED(hr), которые проверяют только бит severity. Это означает, что значения типа S_FALSE (успех, но с отрицательным результатом) считаются успешными, хотя их числовое значение не равно нулю.
¶Основные значения
Существует ряд стандартных констант HRESULT, определённых в заголовочных файлах Windows:
- S_OK (
0x00000000) — операция завершилась успешно. - S_FALSE (
0x00000001) — операция завершилась успешно, но с отрицательным результатом (например, «элемент не найден» при поиске). - E_FAIL (
0x80004005) — неопределённая ошибка. - E_OUTOFMEMORY (
0x8007000E) — недостаточно памяти. - E_INVALIDARG (
0x80070057) — один из аргументов недопустим. - E_NOTIMPL (
0x80004001) — метод не реализован. - E_ACCESSDENIED (
0x80070005) — отказ в доступе. - E_POINTER (
0x80004003) — недопустимый указатель.
Для преобразования системных кодов ошибок Win32 в HRESULT используется макрос HRESULT_FROM_WIN32(x). Обратное преобразование выполняется функцией HRESULT_CODE(hr).
¶Применение в COM и Win32
В COM каждый метод интерфейса объявляется как возвращающий HRESULT. Это позволяет единообразно обрабатывать ошибки, возникающие в разных компонентах, независимо от языка программирования. Возвращаемые данные при этом передаются через выходные параметры.
В Win32 API, начиная с ранних версий Windows, многие функции возвращают HRESULT (например, функции работы с реестром, службами, оболочкой). При этом часть функций возвращает обычный BOOL или DWORD, и для них применяются отдельные правила проверки.
¶Обработка ошибок
При программировании на C/C++ принято проверять результат вызова через макросы SUCCEEDED/FAILED. В языках высокого уровня (C#, Visual Basic .NET) среда автоматически преобразует HRESULT в исключения: если бит severity равен 1, генерируется исключение COMException или Marshal.ThrowExceptionForHR.
В отладочных целях строковое описание ошибки можно получить с помощью функции FormatMessage или утилиты Error Lookup Tool, входящей в состав Windows SDK.
¶Связанные типы
Существуют производные типы: STATUS (в ядре Windows, 32-битный, но с иной структурой битов), NTSTATUS (используется в драйверах и системных вызовах), а также DWORD для кодов ошибок Win32. Несмотря на внешнее сходство, эти типы не являются взаимозаменяемыми без явного преобразования.
¶Критика и особенности
Одной из проблем HRESULT является его «неочевидность» для начинающих разработчиков: значение S_FALSE часто воспринимается как ошибка, хотя формально является успехом. Кроме того, из-за того, что код ошибки занимает лишь 16 бит, в некоторых случаях возникают коллизии между ошибками из разных facility. Тем не менее, тип остаётся стандартом де-факто для всех COM- и большинства системных API Windows на протяжении более трёх десятилетий.
¶Источники
- Microsoft Learn: «HRESULT (COM)» — документация по структуре и макросам.
- Microsoft Windows SDK: заголовочные файлы
winerror.h,winnt.h. - Книга Дона Бокса «Сущность технологии COM» (1998).
- MSDN Magazine: статьи об обработке ошибок в COM.
