Читаем Сущность технологии СОМ. Библиотека программиста полностью

Объекты, которые сбрасывают исключения СОМ, должны использовать интерфейс ISupportErrorInfo , чтобы показывать, какие интерфейсы поддерживают исключения. Этот интерфейс используется клиентами, чтобы установить, верный ли результат дает GetErrorInfo[2]. Этот интерфейс предельно прост:


[ object, uuid(DFOB3060-548F-101B-8E65-08002B2BD119) ]

interface ISupportErrorInfo: IUnknown

{

HRESULT InterfaceSupportsErrorInfo([in] REFIID riid);

}


Предположим, что класс PugCat, рассмотренный в этой главе, сбрасывает исключения из каждого поддерживаемого им интерфейса. Тогда его реализация будет выглядеть так:


STDMETHODIMP PugCat::InterfaceSupportsErrorInfo(REFIID riid)

{

if (riid == IIDIAnimal || riid == IIDICat || riid == IIDIDog || riid == IIDIPug) return SOK;

else return SFALSE;

}


Ниже приведен пример клиента, который надежно обрабатывает исключения, используя ISupportErrorInfo и GetErrorInfo:


void TellPugToSnore(/*[in]*/ IPug *pPug)

{

// call a method

// вызываем метод

HRESULT hr = pPug->Snore();

if (FAILED(hr))

{

// check to see if object supports СОМ exceptions

// проверяем, поддерживает ли объект исключения СОМ

ISupportErrorInfo *psei = 0;

HRESULT hr2 =pPug->QueryInterface( IIDISupportErrorInfo, (void**)&psei);

if (SUCCEEDED(hr2))

{

// check if object supports СОМ exceptions via IPug methods

// проверяем, поддерживает ли объект исключения СОМ через методы

IPug hr2 = psei->InterfaceSupportsErrorInfo(IIDIPug);

if (hr2 == SOK)

{

// read exception object for this logical thread

// читаем объект исключений для этого логического потока

IErrorInfo *реi = 0;

hr2 = GetErrorInfo(0, &pei);

if (hr2 == SOK)

{

// scrape out source and description strings

// извлекаем строки кода и описания

BSTR bstrSource = 0, bstrDesc = 0;

hr2 = pei->GetDescription(&bstrDesc);

assert(SUCCEEDED(hr2));

hr2 = pei->GetSource(&bstrSource);

assert(SUCCEEDED(hr2));

// display error information to end-user

// показываем информацию об ошибке конечному пользователю

MessageBoxW(0, bstrDesc ? bstrDesc : L"«, bstrSource ? bstrSource : L»", MBOK);

// free resources

// высвобождаем ресурсы

SysFreeString(bstrSource);

SysFreeString(bstrDesc);

pei->Release();

}

}

psei->Release();

}

}

if (hr2!= SOK)

// something went wrong with exception

// что-то неладно с исключением

MessageBox(0, «Snore Failed», «IPug», MBOK);

}


Довольно просто отобразить исключения СОМ в исключения C++, причем в любом месте. Определим следующий класс, который упаковывает объект исключений СОМ и HRESULT в один класс C++:


struct COMException

{

HRESULT mhresult;

// hresult to return

// hresult для возврата IErrorInfo *mpei;

// exception to throw

// исключение для выбрасывания

COMException(HRESULT hresult, REFIID riid, const OLECHAR *pszSource, const OLECHAR *pszDesc, const OLECHAR *pszHelpFile = 0, DWORD dwHelpContext = 0)

{

// create and init an error info object

// создаем и инициализируем объект информации об ошибке

ICreateErrorInfo *рсеi = 0;

HRESULT hr = CreateErrorInfo(&pcei);

assert(SUCCEEDED(hr));

hr = pcei->SetGUID(riid);

assert(SUCCEEDED(hr));

if (pszSource) hr=pcei->SetSource(constcast(pszSource));

assert(SUCCEEDED(hr));

if (pszDesc) hr=pcei->SetDescription(constcast(pszDesc));

assert(SUCCEEDED(hr));

if (pszHelpFile) hr=pcei->SetHelpFile(constcast(pszHelpFile));

assert(SUCCEEDED(hr));

hr = pcei->SetHelpContext(dwHelpContext);

assert(SUCCEEDED(hr));

// hold the HRESULT and IErrorInfo ptr as data members

// сохраняем HRESULT и указатель IErrorInfo как элементы данных

mhresult = hresult;

hr=pcei->QueryInterface(IIDIErrorInfo, (void**)&mpei);

assert(SUCCEEDED(hr));

pcei->Release();

}

};


С использованием только что приведенного С++-класса COMException показанный выше метод Snore может быть модифицирован так, чтобы он преобразовывал любые исключения C++ в исключения СОМ:


STDMETHODIMP PugCat::Snore(void)

{

HRESULT hrex = SOK;

try

{

if (this->IsAsleep()) return this->DoSnore();

else throw COMException(PUGEPUGNOTASLEEP, IIDIPug, OLESTR(«PugCat»), OLESTR(«I am not asleep!»));

}

catch (COMException& ce)

{

// a C++ COMException was thrown

// было сброшено исключение COMException C++

HRESULT hr = SetErrorInfo(0, ce.mpei);

assert(SUCCEEDED(hr));

ce.mpei->Release();

hrex = ce.mhresult;

}

catch (…)

{

// some unidentified C++ exception was thrown

// было выброшено какое-то неидентифицированное исключение C++

COMException ex(EFAIL, IIDIPug, OLESTR(«PugCat»), OLESTR(«A C++ exception was thrown»));

HRESULT hr = SetErrorInfo(0, ex.mpei);

assert(SUCCEEDED(hr));

ex.mpei->Release();

hrex = ex.mhresult;

}

return hrex;

}


Заметим, что реализация метода заботится о том, чтобы не позволить чисто С++-исключениям переходить через границы метода. Таково безусловное требование СОМ.


Где мы находимся?

Перейти на страницу:

Похожие книги

C++: базовый курс
C++: базовый курс

В этой книге описаны все основные средства языка С++ - от элементарных понятий до супервозможностей. После рассмотрения основ программирования на C++ (переменных, операторов, инструкций управления, функций, классов и объектов) читатель освоит такие более сложные средства языка, как механизм обработки исключительных ситуаций (исключений), шаблоны, пространства имен, динамическая идентификация типов, стандартная библиотека шаблонов (STL), а также познакомится с расширенным набором ключевых слов, используемым в .NET-программировании. Автор справочника - общепризнанный авторитет в области программирования на языках C и C++, Java и C# - включил в текст своей книги и советы программистам, которые позволят повысить эффективность их работы. Книга рассчитана на широкий круг читателей, желающих изучить язык программирования С++.

Герберт Шилдт

Программирование, программы, базы данных