Каково использование CComPtr над CComQIPtr в COM?

Может ли кто-нибудь объяснить, что такое использование CComPtr над CComQIPtr в COM?

CComPtr<ISampleInterface> Sample1;
CComQIPtr<ISampleInterface> Sample2;

Ответ 1

CComQIPtr предназначен для случаев, когда вы хотите вызвать QueryInterface() удобным образом, чтобы узнать, поддерживается ли интерфейс:

IInterface1* from = ...
CComQIPtr<IInterface2> to( from );
if( to != 0 ) {
   //supported - use
}

Таким образом вы можете запросить интерфейс от указателя на любой (несвязанный) COM-интерфейс и проверить, удалось ли выполнить этот запрос.

CComPtr используется для управления объектами, которые, безусловно, поддерживают некоторый интерфейс. Вы используете его как обычный интеллектуальный указатель с подсчетом ссылок. Это похоже на CComQIPtr, но не позволяет описанную выше процедуру usecase, и это дает вам лучшую безопасность типов.

Этот код:

IUnknown* unknown = ... ;
CComQIPtr<IDispatch> dispatch( unknown );

компилирует и, возможно, дает нулевой указатель, если unknown связан с объектом, который не реализует IDispatch. Теперь вам нужно проверить это во время выполнения, что хорошо, если вы хотите проверить время выполнения, но это плохо, если вы предпочитаете проверку типа времени компиляции.

Этот код:

IUnknown* unknown = ... ;
CComPtr<IDispatch> dispatch( unknown );

будет просто не компилироваться - это дает

ошибка C2664: 'ATL :: CComPtr :: CComPtr (IDispatch *) throw()': не может преобразовать параметр 1 из 'IUnknown *' в 'IDispatch *'

который обеспечивает лучшую безопасность времени компиляции.

Ответ 2

template<class T,
   const IID* piid = &__uuidof(T)>
class CComQIPtr: public CComPtr<T>

Бывший автоматически выводит UUID данного типа, используя аргумент шаблона по умолчанию.

Ответ 4

Замечание о ответе sharptooth. Просто попытался скомпилировать sth. как

CComQIPtr<IInterface2> to( from );

и потерпел неудачу. Присвоение вместо этого было выполнено:

CComQIPtr<IInterface2> to = from;

К сожалению, у меня нет времени анализировать это дальше...

Ответ 5

"ATL использует CComQIPtr и CComPtr для управления указателями интерфейса COM. Оба класса выполняют автоматический подсчет ссылок через вызовы AddRef и Release. Перегруженные операторы обрабатывают операции указателя. CComQIPtr дополнительно поддерживает автоматический запрос интерфейсов, хотя QueryInterface."

И где вы используете один над другим?

Если вы не хотите называть 'QueryInterface()' 'вручную', используйте 'CComQIPtr':

CComQIPtr( T* lp );

CComQIPtr( const CComQIPtr< T, piid >& lp );

Если вы передаете тип указателя, полученный из T, конструктор устанавливает p в параметр T * и вызывает AddRef. Если вы передаете тип указателя, не полученный из T, конструктор вызывает QueryInterface для установки p на указатель интерфейса, соответствующий piid.