#c #com #com-interface
Вопрос:
В моем приложении мне нужно отложить выпуск COM-интерфейсов до более позднего момента. Для этого я сохраняю указатели интерфейса std::vector<IUnknown*> COMInterfaces
, а затем перебираю все указатели и вызываю Release()
вот так:
for(IUnknown* item : COMInterfaces) item->Release();
Однако по следующей ссылке, в разделе 4.1.3, я прочитал:
В COM учитываются только интерфейсы, а не сами объекты. После того, как клиент получил ссылку на определенный интерфейс, он должен вызвать метод выпуска именно на этом интерфейсе, а не на другом интерфейсе, ссылающемся на тот же объект.
Итак, теперь я немного запутался, можно ли выпускать интерфейсы полиморфно или нет. Я не могу найти никакой документации, в которой четко указано, нормально это или нет.
Редактировать: Комментарии ниже подтверждают, что это работает, и я собираюсь использовать его таким образом. Тем не менее, любые указания на официальную документацию будут приветствоваться, а также любые объяснения того, почему иногда я вижу следующий код (это также SafeRelease()
определяется Microsoft)
template<class T>
void Release(T*amp; comInterface) {
if(comInterface) {
comInterface->Release();
comInterface = nullptr;
}
}
вместо
void Release(IUnknown*amp; comInterface) {
if(comInterface) {
comInterface->Release();
comInterface = nullptr;
}
}
Комментарии:
1. Чего вы не можете сделать, так это привести IUnknown* к чему-либо другому (вы всегда должны использовать QueryInterface, а не «сырое» приведение). Если вы этого не сделаете, то не должно быть никаких проблем.
2. Любой COM — интерфейс является неизвестным. Любой брошенный или брошенный, пока вы только звоните
AddRef()
Release()
, иQueryInterface()
должен быть в безопасности. Допустим, у вас естьIDispatch
интерфейс. Ты звонишьlpDisp->Release()
. Это дало бы тот же результат, если бы вы позвонили((IUnknown*) lpDisp)->Release()
.3. Я считаю, что этот параграф конкретно означает интерфейсы, которые можно найти только с
QueryInterface
помощью (а не путем понижения). В этот момент вступает в действие алмазное наследование, и каждый запрашиваемый интерфейс имеет свою собственную копиюIUnknown
. Эти копии могут иметь различные реализации трех методов, о чем, вероятно, предупреждает этот параграф4. Кстати, было бы безопаснее использовать
std::vector<CComPtr<IUnknown>>
вместо этого, тогда вам не придется звонитьRelease()
вручную. Таким образом, интерфейсы освобождаются автоматически, когдаvector
они выходят за рамки области действия, особенно если возникает неожиданное исключение.5. Ваша версия
Release
не может быть вызвана с помощью какого-либо другого типа указателя, кромеIUnknown*
конкретного. Это не связано с COM, просто базовая безопасность типов. Если бы вы могли перейтиDervied* p
к взятию функцииBase*amp;
, эта функция могла бы назначить какую-то не связаннуюAnotherDerived*
сp
ней .