[ATL][trick] обработка исключений
От: Alexander G Украина  
Дата: 25.11.09 14:46
Оценка: 103 (7)
ATL бросает исключения. В основном это <atlsecurity.h>, также при преобразовании строк при ошибке с локалью. Например, CString::MakeLower бросает. В дебаге там сначала идут ассерты, в релизе — сразу исключения.

Кидает он их хитро:

1. Если требуется, чтобы он кидал пользовательские исключения, можно определить _ATL_CUSTOM_THROW и определить свою AtlThrow(HRESULT hr).
2. Если требуется отказаться от C++ исключений, определить _ATL_NO_EXCEPTIONS и он кидает SEH.
3. Иначе кидает CAtlException.

CAtlException неприятная штука, тем, что это не наследник std::exception, а всего лишь тривиальный враппер для HRESULT. Раузмеется, сам HRESULT в качестве исключения был бы ещё хуже, но даже CAtlException требует своего catch. Поэтому целесообразно определить свой AtlThrow, бросающий наследника std::exception.

Т.к. оригинальный AtlThrow — макро, свой тоже можно определить как макро, дополнительно передав __FILE__ и __LINE__ и получив больше контекста. boost::exception подходит для этой цели, но непосредственно BOOST_THROW_EXCEPTION не подходит, т.к. этот макрос создаёт локальные объекты, требующие раскрутки, а AtlThrow используется в ATL совместно с SEH-обработкой.

Ниже вроде рабочий пример, пробовать в релизе, чтобы сразу был ексепшн, без ассерта.

#include <Windows.h>
#include <iostream>
#include <limits>
#include <stdexcept>
#include <boost/exception.hpp>

__declspec(noinline, noreturn) void
  MyAtlThrow(HRESULT hr, char const * func, char const* file, int line);

#define _ATL_CUSTOM_THROW

#define AtlThrow(hr) MyAtlThrow( \
  hr, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__)

#include <atlbase.h>
#include <atlstr.h>

//////////////////////////////////////////////////////////////////////////

class com_error : public std::exception
{
public:
  explicit com_error(HRESULT hr) : hr_(hr) {}

  const char *what( ) const  {
    return "TODO: Use FormatMessage with hr_";
  }

private:
  HRESULT hr_;
};

__declspec(noinline, noreturn) void
MyAtlThrow(HRESULT hr, char const * func, char const* file, int line)
{
  boost::throw_exception(boost::enable_error_info(com_error(hr)) 
    << boost::throw_function(func) 
    << boost::throw_file(file) 
    << boost::throw_line(line));
}

int main()
{
  try
  {
    CString s;
    int i = -1;
    s.Tokenize(_T("wr"), i);
  }
  catch (std::exception& ex)
  {
    std::cout << boost::diagnostic_information(ex);
  }
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.