📄 comvector.h
字号:
// comvector.h: Wrapper around a single-dim SAFEARRAY and a lock on a SAFEARRAY/////////////////////////////////////////////////////////////////////////////// Copyright (c) 1999-2001, Chris Sells. All rights reserved. No warranties extended.// Comments to csells@sellsbrothers.com./////////////////////////////////////////////////////////////////////////////// CComVector is a wrapper around a single-dim SAFEARRAY.// CComVectorData is a wrapper around a lock on a SAFEARRAY, acquired via// SafeArrayAccessData.//// By splitting the two concepts into two classes, each can be managed// separately, therefore avoiding the overhead and inconvenience of// SafeArrayGetElement and SafeArrayPutElement.//// By specializing on one dimension, the language mapping is easy.//// Also added CComVectorItf, a SAFEARRAY of VARIANTs holding some interface./////////////////////////////////////////////////////////////////////////////// History:// 1/10/01: Fixed an ASSERT bug in CComVector::Create. Thanks to// Phil Atkin [phil.atkin@synoptics.co.uk].// 1/3/01: Fixed a compile bug with the suggested usage pointed// out by Claus Michelsen [clausmic@btinternet.com].// Also removed the restriction on operator&, because SAs are// passed [in, out] all the time.// 10/25/00: Added support for VARIANTs holding SAFEARRAYs and// auto-coercing SAFEARRAYs of VARIANTS to a specific itf.// 9/26/00: Assert on VT_BYREF, VT_ARRAY, VT_NULL and VT_EMPTY in Create,// as per the docs (as pointed out by Brian Moelk// [bmoelk@answerlogic.com]).// 7/29/00: Added RawData method to get access to raw SA data.// 5/13/99: Initial release./////////////////////////////////////////////////////////////////////////////// Usage:/*STDMETHODIMP CFoo::UseSafeArray(SAFEARRAY** ppsa) // [in]{ CComVectorData<BSTR> rg(*ppsa); if( !rg ) return E_UNEXPECTED; for( int i = 0; i < rg.Length(); ++i ) { TCHAR sz[32]; wsprintf(sz, __T("rg[%d]= %S\n"), i, (rg[i] ? rg[i] : OLESTR(""))); OutputDebugString(sz); } // Assume data member: 'CComVector<BSTR> m_rg;' m_rg = *ppsa; // Cache a copy return S_OK;}STDMETHODIMP CFoo::GetSafeArray(SAFEARRAY** ppsa) // [in, out]{ CComVector<BSTR> v(100); if( !v ) return E_OUTOFMEMORY; CComVectorData<BSTR> rg(v); if( !rg ) return E_UNEXPECTED; for( int i = 0; i < 100; ++i ) { char sz[16]; rg[i] = A2BSTR(itoa(i, sz, 10)); } return v.DetachTo(ppsa);}*/#pragma once#ifndef INC_COMVECTOR#define INC_COMVECTOR#include <crtdbg.h>#ifndef HR#define HR(_ex) { HRESULT _hr = _ex; if( FAILED(_hr) ) return _hr; }#endif/////////////////////////////////////////////////////////////////////////////// CComVector wraps a SAFEARRAY*class CComVectorBase{public: CComVectorBase(const SAFEARRAY* psa) : m_psa(0) { if( psa ) Copy(psa); } CComVectorBase(const VARIANT& var) : m_psa(0) { if( var.vt | VT_ARRAY ) Copy(var.parray); } CComVectorBase(const CComVectorBase& v) : m_psa(0) { if( v.m_psa ) Copy(v.m_psa); } ~CComVectorBase() { Destroy(); } HRESULT Copy(const SAFEARRAY* psa) { Destroy(); if( psa ) { _ASSERTE(SafeArrayGetDim(const_cast<SAFEARRAY*>(psa)) == 1); HR(SafeArrayCopy(const_cast<SAFEARRAY*>(psa), &m_psa)); } return S_OK; } HRESULT Destroy() { if( !m_psa ) return S_OK; HRESULT hr = SafeArrayDestroy(m_psa); m_psa = 0; return hr; } void Attach(SAFEARRAY* psa) { Destroy(); m_psa = psa; } SAFEARRAY* Detach() { SAFEARRAY* psa = m_psa; m_psa = 0; return psa; } HRESULT DetachTo(/*[in, out]*/ SAFEARRAY** ppsa) { if( !ppsa ) HR(E_POINTER); // If the [in] array is already created, destroy it if( *ppsa ) HR(SafeArrayDestroy(*ppsa)); *ppsa = m_psa; m_psa = 0; return S_OK; } HRESULT CopyTo(/*[in, out]*/ SAFEARRAY** ppsa) { if( !ppsa ) HR(E_POINTER); // If the [in] array is already created, destroy it if( *ppsa ) HR(SafeArrayDestroy(*ppsa)); HR(SafeArrayCopy(m_psa, ppsa)); return S_OK; } operator SAFEARRAY*() { return m_psa; } SAFEARRAY** operator&() { // NOTE: This isn't reasonable, as SAs are passed [in, out] all the time //_ASSERTE(!m_psa); return &m_psa; } long Length() { return Length(m_psa); }public: static long Length(const SAFEARRAY* psa) { if( !psa ) return 0; _ASSERTE(SafeArrayGetDim(const_cast<SAFEARRAY*>(psa)) == 1); long ub; SafeArrayGetUBound(const_cast<SAFEARRAY*>(psa), 1, &ub); long lb; SafeArrayGetLBound(const_cast<SAFEARRAY*>(psa), 1, &lb); return ub - lb + 1; }protected: template <typename T> VARTYPE VarType(T*); template<> VARTYPE VarType(LONG*) { return VT_I4; } template<> VARTYPE VarType(BYTE*) { return VT_UI1; } template<> VARTYPE VarType(SHORT*) { return VT_I2; } template<> VARTYPE VarType(FLOAT*) { return VT_R4; } template<> VARTYPE VarType(DOUBLE*) { return VT_R8; } template<> VARTYPE VarType(VARIANT_BOOL*) { return VT_BOOL; } template<> VARTYPE VarType(SCODE*) { return VT_ERROR; } template<> VARTYPE VarType(CY*) { return VT_CY; } template<> VARTYPE VarType(DATE*) { return VT_DATE; } template<> VARTYPE VarType(BSTR*) { return VT_BSTR; } template<> VARTYPE VarType(IUnknown **) { return VT_UNKNOWN; } template<> VARTYPE VarType(IDispatch **) { return VT_DISPATCH; } template<> VARTYPE VarType(SAFEARRAY **) { return VT_ARRAY; } template<> VARTYPE VarType(CHAR*) { return VT_I1; } template<> VARTYPE VarType(USHORT*) { return VT_UI2; } template<> VARTYPE VarType(ULONG*) { return VT_UI4; } template<> VARTYPE VarType(INT*) { return VT_INT; } template<> VARTYPE VarType(UINT*) { return VT_UINT; } template<> VARTYPE VarType(VARIANT*) { return VT_VARIANT; } template<> VARTYPE VarType(BYTE **) { return VT_BYREF|VT_UI1; } template<> VARTYPE VarType(SHORT **) { return VT_BYREF|VT_I2; } template<> VARTYPE VarType(LONG **) { return VT_BYREF|VT_I4; } template<> VARTYPE VarType(FLOAT **) { return VT_BYREF|VT_R4; } template<> VARTYPE VarType(DOUBLE **) { return VT_BYREF|VT_R8; } template<> VARTYPE VarType(VARIANT_BOOL **) { return VT_BYREF|VT_BOOL; } template<> VARTYPE VarType(SCODE **) { return VT_BYREF|VT_ERROR; } template<> VARTYPE VarType(CY **) { return VT_BYREF|VT_CY; } template<> VARTYPE VarType(DATE **) { return VT_BYREF|VT_DATE; } template<> VARTYPE VarType(BSTR **) { return VT_BYREF|VT_BSTR; } template<> VARTYPE VarType(IUnknown ***) { return VT_BYREF|VT_UNKNOWN; } template<> VARTYPE VarType(IDispatch ***) { return VT_BYREF|VT_DISPATCH; } template<> VARTYPE VarType(SAFEARRAY ***) { return VT_BYREF|VT_ARRAY; } template<> VARTYPE VarType(VARIANT **) { return VT_BYREF|VT_VARIANT; } template<> VARTYPE VarType(PVOID*) { return VT_BYREF; } template<> VARTYPE VarType(DECIMAL **) { return VT_BYREF|VT_DECIMAL; } template<> VARTYPE VarType(CHAR **) { return VT_BYREF|VT_I1; } template<> VARTYPE VarType(USHORT **) { return VT_BYREF|VT_UI2; } template<> VARTYPE VarType(ULONG **) { return VT_BYREF|VT_UI4; } template<> VARTYPE VarType(INT **) { return VT_BYREF|VT_INT; } template<> VARTYPE VarType(UINT **) { return VT_BYREF|VT_UINT; } template<> VARTYPE VarType(VARIANT **) { return VT_BYREF|VT_VARIANT; }protected: SAFEARRAY* m_psa;};template <typename T>class CComVector : public CComVectorBase{public: CComVector(SAFEARRAY* psa = 0) : CComVectorBase(psa) { } CComVector(const CComVector& v) : CComVectorBase(v) { } CComVector(long celt, long nLowerBound = 0, bool bZeroMemory = true) : CComVectorBase(0) { Create(celt, nLowerBound, bZeroMemory); } // TODO: Hook up Copy policy classes /* CComVector(const T* rg, long celt) : m_psa(0) { Copy(rg, celt); } */ CComVector& operator=(const SAFEARRAY* psa) { if( psa != m_psa ) Copy(psa); return *this; } CComVector& operator=(const CComVector& v) { if( &v != this ) Copy(v.m_psa); return *this; } HRESULT Create(long celt, long nLowerBound = 0, bool bZeroMemory = true) {#ifdef _DEBUG VARTYPE vt = VarType((T*)0); _ASSERTE(((vt & VT_BYREF) == 0) && "Can't create a SA using VT_BYREF"); _ASSERTE(((vt & VT_ARRAY) == 0) && "Can't create a SA using VT_ARRAY"); _ASSERTE(((vt & VT_TYPEMASK) != VT_EMPTY) && "Can't create a SA using VT_EMPTY"); _ASSERTE(((vt & VT_TYPEMASK) != VT_NULL) && "Can't create a SA using VT_NULL");#endif SAFEARRAYBOUND sab = { celt, nLowerBound }; m_psa = SafeArrayCreate(VarType((T*)0), 1, &sab); if( !m_psa ) HR(E_OUTOFMEMORY); if( bZeroMemory ) { T* rg = 0; HR(SafeArrayAccessData(m_psa, (void**)&rg)); ZeroMemory(rg, sizeof(T) * celt); SafeArrayUnaccessData(m_psa); } return S_OK; } T* RawData() { _ASSERTE(m_psa); return reinterpret_cast<T*>(m_psa->pvData); } // For some reason, VC6 won't bind to the base class's // implementation, so we do it ourselves HRESULT DetachTo(/*[in, out]*/ SAFEARRAY** ppsa) { return CComVectorBase::DetachTo(ppsa); } // For some reason, VC6 won't bind to the base class's // implementation, so we do it ourselves HRESULT CopyTo(/*[in, out]*/ SAFEARRAY** ppsa) { return CComVectorBase::CopyTo(ppsa); } HRESULT DetachTo(/*[out, retval]*/ VARIANT* pvar) { if( !pvar ) return E_POINTER; pvar->vt = VT_ARRAY | VarType((T*)0); pvar->parray = 0; return CComVectorBase::DetachTo(&pvar->parray); } HRESULT CopyTo(/*[out, retval]*/ VARIANT* pvar) { if( !pvar ) return E_POINTER; pvar->vt = VT_ARRAY | VarType((T*)0); pvar->parray = 0; return CComVectorBase::CopyTo(&pvar->parray); }};/////////////////////////////////////////////////////////////////////////////// CComVectorData represents a lock on SAFEARRAY dataclass CComVectorDataBase{public: CComVectorDataBase(SAFEARRAY* psa) : m_psa(0), m_pv(0), m_celt(0) { if( psa ) AccessData(psa); } CComVectorDataBase(VARIANT& var) : m_psa(0), m_pv(0), m_celt(0) { AccessData(var); } ~CComVectorDataBase() { UnaccessData(); } HRESULT AccessData(SAFEARRAY* psa) { if( !psa || (SafeArrayGetDim(psa) != 1) ) return E_INVALIDARG; UnaccessData(); HR(SafeArrayAccessData(psa, &m_pv)); m_psa = psa; m_celt = CComVectorBase::Length(m_psa); return S_OK; } HRESULT AccessData(VARIANT& var) { if( !(var.vt & VT_ARRAY) ) return E_INVALIDARG; return AccessData(var.parray); } HRESULT UnaccessData() { if( m_psa && m_pv ) HR(SafeArrayUnaccessData(m_psa)); m_psa = 0; m_pv = 0; m_celt = 0; return S_OK; } long Length() { return m_celt; } operator bool() { return (m_pv ? true : false); }protected: SAFEARRAY* m_psa; void* m_pv; long m_celt;};template <typename T>class CComVectorData : public CComVectorDataBase{public: CComVectorData(SAFEARRAY* psa = 0) : CComVectorDataBase(psa) { } CComVectorData(VARIANT& var) : CComVectorDataBase(var) { } T& operator[](long n) {#ifdef _DEBUG if( n < 0 || n >= m_celt ) { _ASSERTE(false && "Accessing data out of bounds"); }#endif return reinterpret_cast<T*>(m_pv)[n]; } /* This conflicts with operator[] operator T*() { return reinterpret_cast<T*>(m_pv); } */};// A SAFEARRAY of VARIANTs holding some interfacetemplate <typename T>class CComVectorItf : public CComVectorData<VARIANT>{public: CComVectorItf(SAFEARRAY* psa = 0) : CComVectorData<VARIANT>(psa) { } CComVectorItf(VARIANT& var) : CComVectorData<VARIANT>(var) { } HRESULT QueryInterface(long n, T** pp) { VARIANT& var = (*this)[n]; if( !((var.vt & VT_UNKNOWN) || (var.vt & VT_DISPATCH)) ) return E_NOINTERFACE; return var.punkVal->QueryInterface(pp); }};#endif // INC_COMVECTOR
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -