Разработка клиента с использованием специальных указателей
Как вы, вероятно, догадались, лексемы _com_lliD и com_ptr_t представляют собой шаблоны классов, первый из них создает новый класс C++, который инкапсулирует функциональность зарегистрированного интерфейса ISay, а второй – класс указателя на этот класс. Операция typedef удостоверяет появление нового типа данных ISayPtr. Отныне объекты типа ISayPtr являются указателями на класс, скроенный по сложному шаблону. Цель – избавить пользователя от необходимости следить за счетчиком ссылок на интерфейс isay, то есть вызывать методы AddRef и Release, и устранить необходимость вызова функции CoCreatelnstance. Заботы о выполнении всех этих операций берет на себя новый класс. Он таким образом скрывает от пользователя рутинную часть работы с объектом СОМ, оставляя лишь творческую. В этом и заключается смысл качественной характеристики smart pointer ("сообразительный" указатель).
Характерно также то, что методы нашего интерфейса (Say и SetWord) заменяются на эквивалентные виртуальные методы нового шаблонного класса (raw_say и raw_setword). Сейчас уместно вновь проанализировать код клиентского приложения и постараться увидеть его в новом свете, зная о существовании нового типа ISayPtr. Теперь становится понятной строка объявления:
ISayPtr pSay (CLSID_CoSay);
Которая создает объект pSay класса, эквивалентного типу ISayPtr. При этом вызывается конструктор класса. Начиная с этого момента вы можете использовать smart указатель pSay для вызова методов интерфейса ISay. Рассмотрим содержимое второго файла заголовков MyComTLib.tli:
// Created by Microsoft (R) C/C++ Compiler. // // d:\my projects\saytlibclient\debug\MyComTLib.tli // // Wrapper implementations for Win32 type library // D:\My Projects\MyComTLib\Debug\MyComTLib.tlb // compiler-generated file. – DO NOT EDIT! #pragma once // // interface ISay wrapper method implementations // inline HRESULT ISay::Say () HRESULT _hr = raw_Say(); if (FAILED(_hr)) _com_issue_errorex(_hr, this,_uuidof(this)); return _hr; inline HRESULT ISay::SetWord (_bstr_t word) { HRESULT _hr – raw_SetWord(word); if (FAILED (_hr)) _com_issue_errorex (_hr, this, _ uuidof (this)); return _hr; }
Как вы видите, здесь расположены тела wrapper-методов, заменяющих методы нашего интерфейса. Вместо прямых вызовов методов Say и Setword теперь будут происходить косвенные их вызовы из функций-оберток (raw_Say и raw_SetWord), но при этом исчезает необходимость вызывать методы Createlnstance и Release. Подведем итог. СОМ-интерфейс первоначально представлен в виде базового абстрактного класса, методы которого раскрываются с помощью ко-класса. При использовании библиотеки типов некоторые из его чисто виртуальных функций заменяются на не виртуальные inline-функции класса-обертки, которые внутри содержат вызовы виртуальных функций и затем проверяют код ошибки. В случае сбоя вызывается обработчик ошибок _com_issue_errorex. Таким образом smart-указатели помогают обрабатывать ошибки и упрощают поддержку счетчиков ссылок.
Примечание
В рассматриваемом коде использован специальный miacc_bstr_t предназначенный для работы с Unicode-строками. Он является классом-оберткой для BSTR, упрощающим работу со строками типа B.STR. Теперь можно не заботиться о вызове функции SysFreeString, так как эту работу берет на себя класс _bstr_t.