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);
}
}