迭代某些 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;
}
};
我的問題是是否有一種聰明的方法可以將這種迭代行為抽象為一個更通用的(可能是模板化的)類。我不確定如何去做,或者這是否實際上可能。感謝您提供任何意見。
uj5u.com熱心網友回復:
所有IEnum...介面都有一個共同的設計,即使它們輸出不同的元素型別。這種設計可以適用于 C 模板,所以我建議分離CIterator成一個獨立的模板類,它可以迭代任何IEnum...介面,然后擁有CShellWindowsPtr并CShellItemArrayPtr使用該類。例如
void CEnumRelease(CComVariant &value)
{
value.Clear();
}
template <typename IntfType>
void CEnumRelease(CComPtr<IntfType> &value)
{
value.Release();
}
// other overloads as needed...
template <typename Intf>
void CEnumTransform(CComVariant &src, CComPtr<Intf> &dest)
{
if (src.vt & VT_TYPEMASK) == VT_UNKNOWN) {
IUnknown *punk = (src.vt & VT_BYREF) ? *(src.ppunkVal) : src.punkVal;
if (punk) punk->QueryInterface(IID_PPV_ARGS(&dest));
}
else if ((src.vt & VT_TYPEMASK) == VT_DISPATCH) {
IDispatch *pdisp = (src.vt & VT_BYREF) ? *(src.ppdispVal) : src.pdispVal;
if (pdisp) pdisp->QueryInterface(IID_PPV_ARGS(&dest));
}
}
template <typename SrcIntf, typename DestIntf>
void CEnumTransform(CComPtr<SrcIntf> &src, CComPtr<DestIntf> &dest)
{
if (src) src->QueryInterface(IID_PPV_ARGS(&dest));
}
// other overloads as needed...
#include <type_traits>
template<typename IEnumType, typename ElementType, typename IntermediateType = ElementType>
class CEnumIterator
{
public:
CEnumIterator() : m_enum()
{
}
CEnumIterator(CComPtr<IEnumType> &enum) : m_enum(enum)
{
*this;
}
CEnumIterator& operator ()
{
CEnumRelease(m_currentValue);
if (m_enum) {
if constexpr (!std::is_same_v<IntermediateType, ElementType>) {
IntermediateType tmp;
if (m_enum->Next(1, &tmp, NULL) != S_OK)
m_enum.Release();
else
CEnumTransform(tmp, m_currentValue);
}
else {
if (m_enum->Next(1, &m_currentValue, NULL) != S_OK) {
m_enum.Release();
}
}
return *this;
}
bool operator == (const CEnumIterator &rhs) const
{
return m_enum == rhs.m_enum;
}
bool operator != (const CEnumIterator &rhs) const
{
return m_enum != rhs.m_enum;
}
ElementType& operator* ()
{
return m_currentValue;
}
private:
CComPtr<IEnumType> m_enum;
ElementType m_currentValue;
};
class CShellItemArrayPtr : public CComPtr<IShellItemArray>
{
public:
auto begin() const
{
CComPtr<IEnumShellItems> enum;
if (p) p->EnumItems(&enum);
return CEnumIterator<IEnumShellItems, CComPtr<IShellItem>>(enum);
}
auto end() const
{
return CEnumIterator<IEnumShellItems, CComPtr<IShellItem>>();
}
};
class CShellWindowsPtr : public CComPtr<IShellWindows>
{
public:
auto begin() const
{
CComPtr<IEnumVARIANT> enum;
if (p) {
CComPtr<IUnknown> punk;
if (SUCCEEDED(p->_NewEnum(&punk) && punk)
punk->QueryInterface(IID_PPV_ARGS(&enum));
}
return CEnumIterator<IEnumVARIANT, CComPtr<IWebBrowser2>, CComVariant>(enum);
}
auto end() const
{
return CEnumIterator<IEnumVARIANT, CComPtr<IWebBrowser2>, CComVariant>();
}
};
uj5u.com熱心網友回復:
CComPtr<IShellItemArray>在這種情況下,在派生自的類中使用模板會導致決議沖突。這可以通過更改p為 來解決CComPtr<T_array>::p。
CIterator begin() const
{
return CIterator(CComPtr<T_array>::p);
}
現在可以添加模板,如下所示。
我只對這段代碼進行了一次測驗!,我只是在記錄解析度
template<typename T_array, typename T_item, typename T_enum>
class CShellItemArrayPtr : public CComPtr<T_array>
{
class CIterator
{
CComPtr<T_item> m_psi;
CComPtr<T_enum> m_pesi;
HRESULT m_hr;
public:
CIterator(T_array* psia) : m_hr(S_FALSE)
{
HRESULT 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; }
T_item* operator* () { return m_psi; }
};
public:
CIterator begin() const { return CIterator(CComPtr<T_array>::p); }
HRESULT end() const { return S_FALSE; }
};
用法:
CShellItemArrayPtr<IShellItemArray, IShellItem, IEnumShellItems> arr;
if SUCCEEDED(filedlg->GetResults(&arr))
for (auto it : arr)
{
...
it->GetDisplayName(SIGDN_FILESYSPATH, &ptr);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/314750.html
上一篇:您能否從基本Win32控制臺模板應用程式中的C#/Winrt組件呼叫(不是WinForm/抽象/包裝器或使用C /Winrt模板)?)
