Как правильно обрабатывать ошибки? У меня есть код, подобный следующему, который обрабатывает все коды ошибок, которые я обнаружил на MSDN, и все же иногда получаю ошибку «Неизвестно».
HRESULT hr = pwb->Navigate2(&URL, &Flag, &TargetFrameName, &PostData, &Headers);
if(FAILED(hr))
{
std::string message("Navigate2 failed with reason: ");
switch(hr)
{
// The operation was successful.
case S_OK:
message.append("S_OK");
break;
// One or more parameters are invalid.
case E_INVALIDARG:
message.append("E_INVALIDARG");
break;
// Out of memory.
case E_OUTOFMEMORY:
message.append("E_OUTOFMEMORY");
break;
// The operation failed.
case E_FAIL:
message.append("E_FAIL");
break;
case E_ACCESSDENIED:
message.append("E_ACCESSDENIED");
break;
case E_POINTER:
message.append("E_POINTER");
break;
case E_UNEXPECTED:
message.append("E_UNEXPECTED");
break;
default:
message.append("Unknown");
}
}
Существует довольно много вариантов обработки ошибок COM. Стратегии включают использование каскадирования if SUCCEEDED()
или централизованная функция обработки ошибок с использованием goto on FAILED()
среди других. Там есть хорошая информация о MSDN.
Что касается интерпретации кодов ошибок, FormatMessage()
будет часто облегчать вашу работу — вот пример из MSDN (включено ниже для ясности)
#include <stdio.h>
#include <windows.h>
#include <tchar.h>
void ErrorDescription(HRESULT hr)
{
if(FACILITY_WINDOWS == HRESULT_FACILITY(hr))
hr = HRESULT_CODE(hr);
TCHAR* szErrMsg;
if(FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&szErrMsg, 0, NULL) != 0)
{
_tprintf(TEXT("%s"), szErrMsg);
LocalFree(szErrMsg);
} else
_tprintf( TEXT("[Could not find a description for error # %#x.]\n"), hr);
}
В приведенном выше вызове флаги указывают, что окна будут выделять память для сообщений об ошибках (которые вы должны освободить — используйте LocalFree()
) и что он будет искать сообщения об ошибках в таблицах системных сообщений (FORMAT_MESSAGE_FROM_SYSTEM
). Иногда (или часто в зависимости от типа используемых библиотек) — в таблицах системных сообщений не будет найдено соответствующих описаний ошибок.
В подобных случаях вы можете либо самостоятельно обработать описание ошибки (как вы это делали в своем примере), либо попытаться напрямую загрузить таблицы сообщений библиотеки. Для этого используйте FORMAT_MESSAGE_FROM_HMODULE
и поставьте ручку модуля в качестве lpSource
параметр к FormatMessage()
функция.
Вот пример:
std::wstring StackExample::getLastError( HRESULT hr )
{
LPWSTR lpMsgBuf;
DWORD ret;
std::wstring def(L"(UNNKOWN)");
ret = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_HMODULE,
GetModuleHandle(TEXT("imapi2.dll")),
hr,
0,
(LPWSTR) &lpMsgBuf,
0, NULL );
if(ret)
{
std::wstring last(lpMsgBuf);
LocalFree(lpMsgBuf);
return last;
}
return def;
}
HRESULT
коды ошибок на самом деле LONG
тип с блоками битов, имеющих индивидуальное значение. То есть нереально обрабатывать каждую ошибку в switch
заявление.
Если у вас есть конкретная обработка для конкретного кода ошибки, вы делаете это. В противном случае вы, как правило, проверяете возвращенные на успех / неудачу, используя SUCCEEDED
а также FAILED
макросы:
if(FAILED(nResult))
{
// TODO: Handle the failed operation here
}
Смотрите также: Коды ошибок в COM:
Чтобы проверить, успешен ли метод COM, изучите старший бит
возвращенный HRESULT. Заголовки Windows SDK предоставляют два макроса, которые
сделать это проще: макрос SUCCEEDED и макрос FAILED.
Макрос SUCCEEDED возвращает TRUE, если HRESULT является кодом успеха и FALSE
если это код ошибки.