//////////////////////////////////////////////// // SAFEARRAY.H - SafeArray wrappers and other COM helpers //////////////////////////////////////////////// #pragma once #include #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 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 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 SafeArrayOneDimVariant; typedef CSafeArrayOneDim SafeArrayOneDimWbemClassObject; typedef CSafeArrayOneDim SafeArrayOneDimBSTR;