使用带有COM接口的STL智能指针

using STL smart pointers with COM interfaces

本文关键字:STL 智能 指针 接口 COM      更新时间:2023-10-16

我正在尝试使用标准的C 库智能指针,该指针使用MS COM用于其大多数功能的库(我必须说我对COM并不熟悉)。因此,我有以下unique_ptr

的自定义代码
struct COMDeleter {
    template<typename T> void operator()(T* ptr) {
        if (ptr) ptr->Release();
    }
};

在示例代码中,我们有类似的东西:

class MyClass
{
public:
    MyClass(IDeckLink * device) 
      : m_deckLink(device)
    {            
    }  
    MyClass::~MyClass()
    {
        if (m_deckLink != NULL)
        {
            m_deckLink->Release();
            m_deckLink = NULL;
        }
    } 
    IDeckLink * m_deckLink;
};

这可以替换为:

class MyClass
{
public:
    MyClass(IDeckLink * device) 
    {  
        m_deckLink.reset(device);
    }   
    std::unique_ptr<IDeckLink, COMDeleter>  m_deckLink;
};

现在,我有另一个称为 IDeckLinkInput的接口,我想以类似的方式包装,但是初始化的方式与以下方式不同:

IDeckLinkInput* m_deckLinkInput = NULL;
if (m_deckLink->QueryInterface(IID_IDeckLinkInput, (void**) &m_deckLinkInput) != S_OK)
        return false;

所以,如果我有一个智能排列,则是:

std::unique_ptr<IDeckLinkInput, COMDeleter> m_deckLinkInput(nullptr);

我不确定如何像上面的初始化函数一起使用它?它甚至可以做到吗?还是我应该坚持使用旧样式C ?

类似的东西:

template<class U, class T>
std::unique_ptr<U, COMDeleter>
upComInterface( GUID guid, T const& src ) {
  if (!src) return {};
  T* r = nullptr;
  if (src->QueryInterface( guid, (void**)&r) != S_OK)
    return {};
  return {r, {}};
}

然后我们:

auto deckLink = upComInterface<IDeckLinkInput>( IID_IDeckLinkInput, deckLink );

这里有一个小的干违规行为 - 每次执行此操作时,必须重复IDeckLinkInputIID_IDeckLinkInput之间的链接,并弄错了它会导致行为不确定。

我们可以通过多种机制来解决此问题。就个人而言,我会选择标签调度类型:

namespace MyComHelpers {
  template<class T> struct com_tag_t {using type=T; constexpr com_tag_t(){};};
  template<class T> constexpr com_tag_t<T> com_tag{};
  template<class T>
  constexpr void get_com_guid( com_tag_t<T> ) = delete; // overload this for your particular types
  template<class T>
  constexpr GUID interface_guid = get_com_guid( com_tag<T> );
}

现在我们可以将类型与GUID相关联。在IDeckLinkInput的名称空间中,这样做:

constexpr GUID get_com_guid( MyComHelpers::com_tag_t<IDeckLinkInput> ) {
  // constexpr code that returns the GUID
}

然后,我们重写GET接口函数:

std::unique_ptr<U, COMDeleter>
com_cast( T const& src ) {
  if (!src) return {};
  T* r = nullptr;
  if (src->QueryInterface( MyComHelpers::interface_guid<T>, (void**)&r) != S_OK)
    return {};
  return {r, {}};
}

和使用变为:

auto declLink = com_cast<IDeckLinkInput>(m_deckLinkInput);

有很多方法可以将类型与GUID相关联,包括特征类。constexpr基于ADL的查找功能和可变模板只是一种方式。

代码未测试。