【发布时间】:2021-11-17 08:13:55
【问题描述】:
迭代某些 COM 集合对象可能很麻烦,因此我尝试创建一些支持基于范围的迭代的 COM 指针。它们源自CComPtr。例如,这是我提出的一个 IShellItemArray 指针,它允许在其 IShellItems 上进行基于范围的迭代(因此您只需执行 for (const auto psi : psia) 即可对其进行迭代):
class CShellItemArrayPtr : public CComPtr<IShellItemArray>
{
public:
using CComPtr::CComPtr;
private:
class CIterator
{
public:
CIterator(IShellItemArray* psia) : m_hr(S_FALSE)
{
HRESULT hr;
hr = psia->EnumItems(&m_pesi);
if (SUCCEEDED(hr))
++*this;
}
const CIterator& operator++ ()
{
m_psi.Release();
m_hr = m_pesi->Next(1, &m_psi, NULL);
return *this;
}
BOOL operator!= (const HRESULT hr) const
{
return m_hr != hr;
}
IShellItem* operator* ()
{
return m_psi;
}
private:
CComPtr<IShellItem> m_psi;
CComPtr<IEnumShellItems> m_pesi;
HRESULT m_hr;
};
public:
CIterator begin() const
{
return CIterator(p);
}
HRESULT end() const
{
return S_FALSE;
}
};
同样,这是我想出的一个IShellWindows 指针,它允许基于范围的迭代对其单独的IWebBrowser2s:
class CShellWindowsPtr : public CComPtr<IShellWindows>
{
public:
using CComPtr::CComPtr;
private:
class CIterator
{
public:
CIterator(IShellWindows* psw) : m_hr(S_FALSE)
{
HRESULT hr;
CComPtr<IUnknown> punk;
hr = psw->_NewEnum(&punk);
if (SUCCEEDED(hr))
{
hr = punk->QueryInterface(&m_pev);
if (SUCCEEDED(hr))
++*this;
}
}
const CIterator& operator++ ()
{
m_pwb2.Release();
CComVariant var;
m_hr = m_pev->Next(1, &var, NULL);
if (m_hr == S_OK)
var.pdispVal->QueryInterface(&m_pwb2);
return *this;
}
BOOL operator!= (const HRESULT hr) const
{
return m_hr != hr;
}
IWebBrowser2* operator* () const
{
return m_pwb2;
}
CComPtr<IWebBrowser2> m_pwb2;
CComPtr<IEnumVARIANT> m_pev;
HRESULT m_hr;
};
public:
CIterator begin() const
{
return CIterator(p);
}
HRESULT end() const
{
return S_FALSE;
}
};
我的问题是,是否有一种聪明的方法可以将这种迭代行为抽象为更通用(可能是模板化)的类。我不确定如何去做,或者实际上是否可行。感谢您的任何意见。
【问题讨论】: