Страница 2 из 7
Обработка исключительных ситуаций
Прежде чем перейти к примерам, нам необходимо рассмотреть обработку исключительных ситуаций. Как говорилось ранее, директива #import использует для генерации исключительных ситуаций класс _com_error. Этот класс инкапсулирует генерируемые значения HRESULT, а также поддерживает работу с интерфейсом IErrorInfo для получения более подробной информации об ошибке. Внесём соответствующие изменения в наш пример: #import "sampl.dll"
void SamplFunc () { try { using namespace SAMPLLib; ISamplObjectPtr obj(L"SAMPLLib.SamplObject"); ISamplObjectPtr obj2 = obj->Metod(1l,L"12345"); obj->Prop = SAMPLLib::SamplType2; obj2->Prop = obj->Prop; } catch (_com_error& er) { printf("_com_error:\n" "Error : %08lX\n" "ErrorMessage: %s\n" "Description : %s\n" "Source : %s\n", er.Error(), (LPCTSTR)_bstr_t(er.ErrorMessage()), (LPCTSTR)_bstr_t(er.Description()), (LPCTSTR)_bstr_t(er.Source())); } } При изучении файла sampl.tli хорошо видно как директива #import генерирует исключения. Это происходит всегда при выполнении следующего условия: if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
Этот способ, безусловно, является универсальным, но могут возникнуть некоторые неудобства. Например, метод MoveNext объекта Recordset ADO возвращает код, который не является ошибкой, а лишь индицирует о достижении конца набора записей. Тем не менее, мы получим исключение. В подобных случаях придётся использовать либо вложенные операторы try {} catch, либо корректировать wrapper, внося обработку исключений непосредственно в тело сгенерированных процедур. В последнем случае, правда, придется подключать файлы *.tlh уже обычным способом, через #include. Но делать это никто не запрещает. Наконец, настало время рассмотреть несколько практических примеров. Я приведу четыре примера работы с MS Word, MS Excel, ADO DB и ActiveX Control. Первые три примера будут обычными консольными программами, в последнем примере я покажу, как можно заменить класс COleDispatchDriver сгенерированный MFC Class Wizard'ом на классы полученные директивой #import. Для первых двух примеров нам понадобиться файл следующего содержания: // Office.h
#define Uses_MSO2000
#ifdef Uses_MSO2000 // for MS Office 2000 #import "C:\Program Files\Microsoft Office\Office\MSO9.DLL" #import "C:\Program Files\Common Files\Microsoft Shared\VBA\VBA6\VBE6EXT.OLB" #import "C:\Program Files\Microsoft Office\Office\MSWORD9.OLB" \ rename("ExitWindows","_ExitWindows") #import "C:\Program Files\Microsoft Office\Office\EXCEL9.OLB" \ rename("DialogBox","_DialogBox") \ rename("RGB","_RGB") \ exclude("I","IPicture") #import "C:\Program Files\Common Files\Microsoft Shared\DAO\DAO360.DLL" \ rename("EOF","EndOfFile") rename("BOF","BegOfFile") #import "C:\Program Files\Microsoft Office\Office\MSACC9.OLB" #else // for MS Office 97 #import "C:\Program Files\Microsoft Office\Office\MSO97.DLL" #import "C:\Program Files\Common Files\Microsoft Shared\VBA\VBEEXT1.OLB" #import "C:\Program Files\Microsoft Office\Office\MSWORD8.OLB" \ rename("ExitWindows","_ExitWindows") #import "C:\Program Files\Microsoft Office\Office\EXCEL8.OLB" \ rename("DialogBox","_DialogBox") \ rename("RGB","_RGB") \ exclude("I","IPicture") #import "C:\Program Files\Common Files\Microsoft Shared\DAO\DAO350.DLL" \ rename("EOF","EndOfFile") rename("BOF","BegOfFile") #import "C:\Program Files\Microsoft Office\Office\MSACC8.OLB" #endif
Этот файл содержит подключение библиотек типов MS Word, MS Excel и MS Access. По умолчанию подключаются библиотеки для MS Office 2000, если на вашем компьютере установлен MS Office 97, то следует закомментировать строчку #define Uses_MSO2000 Если MS Office установлен в каталог отличный от "C:\Program Files\Microsoft Office\Office\", то пути к библиотекам также следует подкорректировать. Обратите внимание на атрибут rename, его необходимо использовать, когда возникают конфликты имён свойств и методов библиотеки типов с препроцессором. Например, функция ExitWindows объявлена в файле winuser.h как макрос: #define ExitWindows(dwReserved,Code) ExitWindowsEx(EWX_LOGOFF,0xFFFFFFFF) В результате, там, где препроцессор встретит имя ExitWindows, он будет пытаться подставлять определение макроса. Этого можно избежать при использовании атрибута rename, заменив такое имя на любое другое. |