Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

265 lines
6.6 KiB

////////////////////////////////////////////////
// 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;