|
|
////////////////////////////////////////////////
// SAFEARRAY.H - SafeArray wrappers and other COM helpers
////////////////////////////////////////////////
#pragma once
#include <comdef.h>
#pragma warning (disable: 4786) // exceeds 255 chars in browser info
// Macro to make code constantly checking for HRESULTS
// more readable
//
#define CHECK_ERROR(expression) \
{ HRESULT hResultCheck = (expression); \ TCHAR l_buf[1024];\ if (FAILED(hResultCheck)) \ { \ wsprintf(l_buf,\ L"%S(%d) : error %d (0x%X) [%s] while performing this action:\n %s\n====\n", \ __FILE__, __LINE__, hResultCheck, hResultCheck, \ _com_error(hResultCheck).ErrorMessage(), #expression); \ OutputDebugString(l_buf);\ ASSERT (FALSE); \ if (hResultCheck != WBEM_E_ACCESS_DENIED) \ return hResultCheck; \ } \ } // quick class to generate a GUID and a string equivalent
class CGuidString { WCHAR m_szGUID[39]; // enough space to fit a GUID in Unicode
GUID m_guid; // enough space to fit a GUID in Unicode
public: CGuidString() { Regen(); } HRESULT GetBSTR (_bstr_t& str) { try { str = m_szGUID; } catch (_com_error e) { return e.Error(); } return S_OK; } operator LPCWSTR() {return m_szGUID;} HRESULT Regen() { ::ZeroMemory(m_szGUID, sizeof(m_szGUID)); HRESULT hr = CoCreateGuid(&m_guid); StringFromGUID2 (m_guid, m_szGUID, sizeof(m_szGUID) / sizeof (WCHAR)); return hr; } };
//
// template function to suppress exceptions generated from an
// assignment and turn them into HRESULTS. Note that this only works
// with _com_error exceptions!
//
template<class T1, class T2> inline HRESULT SafeAssign(T1& dest, T2& src) { try { dest = src; } catch (_com_error e) { return e.Error(); } catch (...) { ASSERT (FALSE); // invalid type of exception!!!!
return TYPE_E_TYPEMISMATCH; } return S_OK; }
//
// Dependency-free SAFEARRAY wrapper class
// Adapted from MFC's COleSafeArray
// Allows type-safe access to safearrays of any type
//
template <class T, VARTYPE t_vt> class CSafeArrayOneDim : public tagVARIANT { public: enum {INITIAL_ALLOC = 200}; CSafeArrayOneDim() { // Validate the VARTYPE for SafeArrayCreate call
ASSERT(!(t_vt & VT_ARRAY)); ASSERT(!(t_vt & VT_BYREF)); ASSERT(!(t_vt & VT_VECTOR)); ASSERT(t_vt != VT_EMPTY); ASSERT(t_vt != VT_NULL);
::ZeroMemory(this, sizeof(*this)); vt = VT_EMPTY; } ~CSafeArrayOneDim() { Clear(); } operator VARIANT*() { return this; } operator const VARIANT*() const { return this; }
// operations
HRESULT Create( DWORD nElements = INITIAL_ALLOC, T* pvSrcData = NULL) { ASSERT(nElements > 0);
// Free up old safe array if necessary
Clear();
// Allocate and fill proxy array of bounds (with lower bound of zero)
SAFEARRAYBOUND saBounds; saBounds.lLbound = 0; saBounds.cElements = nElements;
parray = ::SafeArrayCreate(t_vt, 1, &saBounds); if (parray == NULL) return E_OUTOFMEMORY;
// set the correct variant type for us
vt = unsigned short(t_vt | VT_ARRAY);
// Copy over the data if neccessary
if (pvSrcData != NULL) { T* pvDestData; CHECK_ERROR(AccessData(&pvDestData)); memcpy(pvDestData, pvSrcData, ::SafeArrayGetElemsize(parray) * nElements); CHECK_ERROR(UnaccessData()); } return S_OK; }
DWORD GetSize() { long nUBound; GetUBound(&nUBound); return nUBound + 1; }
HRESULT Resize(DWORD dwElements) { SAFEARRAYBOUND rgsabound; rgsabound.cElements = dwElements; rgsabound.lLbound = 0;
CHECK_ERROR(::SafeArrayRedim(parray, &rgsabound)); return S_OK; }
HRESULT Copy(LPSAFEARRAY* ppsa) { ASSERT (::SafeArrayGetDim(ppsa) == 1); CHECK_ERROR(::SafeArrayCopy(parray, ppsa)); return S_OK; }
// store an entry in the array-- resize if needed
HRESULT SafePutElement(long nIndex, const T& pvData) { long nUBound; CHECK_ERROR (GetUBound(&nUBound)); if (nUBound < 1) { ASSERT (FALSE); return E_INVALIDARG; } // do we need to expand?
if (nUBound < nIndex) { // figure out the right new size
while (nUBound < nIndex) { nUBound = nUBound * 2; } CHECK_ERROR (Resize(nUBound)); } CHECK_ERROR(::SafeArrayPutElement(parray, &nIndex, pvData)); return S_OK; }
// Operations
HRESULT Attach(VARIANT& varSrc) { if (!IsValid()) CHECK_ERROR (E_INVALIDARG);
// Free up previous safe array if necessary
CHECK_ERROR(Clear());
// give control of data to CSafeArrayOneDim
memcpy(this, &varSrc, sizeof(varSrc)); varSrc.vt = VT_EMPTY; // take it from the source variant
return S_OK; }
static bool IsValid(const VARIANT& Other) { if ((Other.vt & VT_ARRAY) == 0) return false; // must be an array
if (Other.vt != unsigned short(t_vt | VT_ARRAY)) return false; // must be same type as us
if (::SafeArrayGetDim(Other.parray) != 1) return false; // make sure no multi-dim arrays
long nLBound = -1; ::SafeArrayGetLBound(Other.parray, 1, &nLBound); if (nLBound != 0) return false; // lower bound must be zero
// all looks good
return true; }
VARIANT Detach() { VARIANT varResult = *this; vt = VT_EMPTY; return varResult; }
// trivial COM API wrappers
HRESULT Clear() { return ::VariantClear(this); } HRESULT AccessData(T** ppvData) { CHECK_ERROR(::SafeArrayAccessData(parray, (void**) ppvData)); return S_OK; } HRESULT UnaccessData() { CHECK_ERROR(::SafeArrayUnaccessData(parray)); return S_OK; } HRESULT AllocData() { CHECK_ERROR(::SafeArrayAllocData(parray)); return S_OK; } HRESULT AllocDescriptor() { CHECK_ERROR(::SafeArrayAllocDescriptor(1, &parray)); return S_OK; } HRESULT GetUBound(long* pUbound) { CHECK_ERROR(::SafeArrayGetUBound(parray, 1, pUbound)); return S_OK; } HRESULT Lock() { CHECK_ERROR(::SafeArrayLock(parray)); return S_OK; } HRESULT Unlock() { CHECK_ERROR(::SafeArrayUnlock(parray)); return S_OK;} HRESULT Destroy() { CHECK_ERROR(::SafeArrayDestroy(parray)); return S_OK; } HRESULT DestroyData() { CHECK_ERROR(::SafeArrayDestroyData(parray)); return S_OK; } HRESULT DestroyDescriptor() { CHECK_ERROR(::SafeArrayDestroyDescriptor(parray)); return S_OK; } HRESULT GetElement(long nIndex, T* pvData) { CHECK_ERROR(::SafeArrayGetElement(parray, &nIndex, pvData)); return S_OK; } HRESULT PtrOfIndex(long* rgIndices, T** ppvData) { CHECK_ERROR(::SafeArrayPtrOfIndex(parray, rgIndices, ppvData)); return S_OK; } HRESULT PutElement(long* rgIndices, T* pvData) { CHECK_ERROR(::SafeArrayPutElement(parray, rgIndices, pvData)); return S_OK; } };
// typdefs for common classes
typedef CSafeArrayOneDim<VARIANT, VT_VARIANT> SafeArrayOneDimVariant; typedef CSafeArrayOneDim<IWbemClassObject*, VT_UNKNOWN> SafeArrayOneDimWbemClassObject; typedef CSafeArrayOneDim<BSTR, VT_BSTR> SafeArrayOneDimBSTR;
|