Шаблоны CComPtr и CComQIPtr предлагает нам ATL. Так что ести вы не используете ATL у себя в проекте, то ваш выбор однозначен - _com_ptr_t. Тут даже думать не надо - особого смысла пораждать зависимость от ATL ради CComPtr/CComQIPtr нет.
У _com_ptr_t есть полезный макрос для создания конкретных типов (через typedef): _COM_SMARTPTR_TYPEDEF. Выглядит это так:
// = typedef _com_ptr_t<...> IFooBarPtr;Еще бОльшая прелесть состоит в том, что для большинства интерфейсов уже заданы такие typedef-ы, то есть можно смело писать
_COM_SMARTPTR_TYPEDEF(IFooBar, __uuidof(IFooBar));
...
IFooBarPtr FooBar;
IHTMLDocument2Ptr Document;
без соответствующего тайпдефа. Однако засада в том, что сделаны не все тайпдефы и для некоторых интерфейсов придется либо самим объявлять тип через _COM_SMARTPTR_TYPEDEF или использовать _com_ptr_t напрямую._com_ptr_t, как и CComQIPtr умеют вызывать QueryInterface "на ходу", что довольно удобно:
IDispatchPtr RawDocument = GetDocument();Небольшим плюсом CComQIPtr может служить его бОльшая лаконичность по сравнению с _com_ptr_t:
IHTMLDocument2Ptr Document(RawDocument); // здесь автоматически вызывается QueryInterface
CComQIPtr<IHTMLDocument4> Document;
vs
_com_ptr_t<IHTMLDocument4, &__uuidof(IHTMLDocument4)> Document;
Вывод из этого я делаю такой: если используете ATL — берите CComQIPtr, если нет — _com_ptr_t. Если вдруг придется "слезть" с ATL, то будет довольно просто перевести код с CComQIPtr на _com_ptr_t.
Post scriptum
Все перечисленные выше умные указатели переопределяют operator& так, что он возвращает адрес обычного указателя, вместо адреса умного указателя. Это очень удобно для таких вот вызовов, которых в COM предостаточно:
IWebBrowserPtr Browser = GetBrowser();Соответственно, если будет желание положить элемент в контейнер, то оператору & очень желательно вернуть прежнюю логику. Например, обернув умный указатель в CAdapt из ATL:
IDispatchPtr Document;
// calling HRESULT STDMETHODCALLTYPE get_Document(IDispatch **ppDisp);
Browser->get_Document(&Document);
std::vector< CAdapt< CComQIPtr<IDispatch> > > ObjectsА если понадобится, то можно в любой момент сделать "срезку" до CComQIPtr/_com_ptr_t с его переопределенным оператором &:
BOOST_FOREACH(CComQIPtr<IDispatch> &Object, Objects)
Browser->get_Document(&Object);
PPS. Дискуссии по теме: здесь и здесь.
5 комментариев:
для CComPtr и CComQIPtr у меня тоже образовалось несколько полезных макросов
#define DEFINE_COMPTR(Intf) typedef CComPtr< Intf > Intf##Ptr;
#define DEFINE_COMQIPTR(Intf, pIID) typedef CComQIPtr< Intf, pIID> Intf##QIPtr;
#define DEFINE_SMART_PTR_IID(Intf, pIID)\
DEFINE_COMPTR(Intf); \
DEFINE_COMQIPTR(Intf, pIID);
#define DEFINE_SMART_PTR(Intf) DEFINE_SMART_PTR_IID(Intf, &IID_##Intf)
используем
DEFINE_SMART_PTR(IPropertyBag);
в коде объявляем
IPropertyBagPtr pPropBag = IPropertyBagQIPtr(pUnknown);
и еще вопрос не совсем по теме.
CComPtr это часть ATL, _com_ptr_ это часть Visual Studio. Одного нет в бесплатном варианте (express), другого нет в поставке eclipse.
Есть ли какая-то отдельная библиотека умных указателей для того чтобы без лишних задержек по времени убрать ATL из списка зависимостей или надо снова изобретать велосипед, написав свою реализацию?
CTpaHHoe: Рецепт прост - взять boost::intrusive_ptr<IUnknown> и добавить какую-нибудь обертку для QueryInterface по вкусу. Пример.
>Вывод из этого я делаю такой: если >используете ATL — берите >CComQIPtr, если нет — _com_ptr_t.
Com на С++ без ATL - как то смешно звучит :)
>> Com на С++ без ATL - как то смешно звучит :)
таковы особенности программирования не под Visual C++
Отправить комментарий