15 октября 2007

Windows exceptions

Функции WinAPI сообщают об ошибках в C-стиле - через коды ошибок. Классика C++ - сообщать об ошибках через исключения. Достаточно обернуть вызов функции в специальный "адаптер", и брюки превращаются в элегантные шорты:
#include <comdef.h>

inline void TESTHR(HRESULT hr)
{
if (FAILED(hr))
_com_issue_error(hr);
};

...
TESTHR(::CoCreateGuid(&UniqueID));
Типичный адаптер для обработки ошибок COM. Не помешает иметь такой же адаптер для не-COM функций:
#include <windows.h>

inline void TestWinFn(BOOL WindowsFunctionResult)
{
if (!WindowsFunctionResult)
throw WindowsError(::GetLastError());
}

...
TestWinFn(::ConvertSidToStringSid(SID, &StringSID));
Единственное - не хватает того самого класса WindowsError.
#include <windows.h>
#include <exception>
#include <Loki/ScopeGuard.h>

class WindowsError : public std::exception
{
public:
WindowsError(DWORD ErrorCode = ::GetLastError())
std::exception(Message(ErrorCode).c_str()),
_ErrorCode(ErrorCode) {}

DWORD ErrorCode() const { return _ErrorCode; }

private:
static std::wstring Message(DWORD ErrorCode)
{
std::wstring Result;
LPVOID Buffer = NULL;

if (::FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
ErrorCode,
0, // Default language
(LPTSTR) &Buffer,
0,
NULL))
{
LOKI_ON_BLOCK_EXIT(LocalFree, Buffer);
Result.assign((LPCWSTR)Buffer);
}

return Result;
}

private:
DWORD _ErrorCode;
};

PS. Кто не использует Loki - сюда.

2 комментария:

Not a kernel guy комментирует...

Тут есть одна проблема. Бросать исключения на каждый вызов во-первых дорого, а во-вторых идеологически не совсем правильно. Бросать нужно только тогда, когда возникла "непредвиденная" ситуация. Например CreateFile, возвращающий File not found в большинстве случаев не является непредвиденной ситуацией и такое эффективнее обрабатывать проверяя код ошибки.

Raider комментирует...

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

Если понятно что делать с ошибкой, то бросать исключение не надо, ты верно заметил.

Вобщем, голову на плечах иметь никто не отменял ;)