// Windows/PropVariant.cpp
#include "StdAfx.h"
#include "../Common/Defs.h"
#include "PropVariant.h"
namespace NWindows {
namespace NCOM {
BSTR AllocBstrFromAscii(const char *s) throw()
{
if (!s)
return NULL;
UINT len = (UINT)strlen(s);
BSTR p = ::SysAllocStringLen(NULL, len);
if (p)
{
for (UINT i = 0; i <= len; i++)
p[i] = (Byte)s[i];
}
return p;
}
HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw()
{
p->bstrVal = ::SysAllocStringLen(NULL, numChars);
if (!p->bstrVal)
{
p->vt = VT_ERROR;
p->scode = E_OUTOFMEMORY;
return E_OUTOFMEMORY;
}
p->vt = VT_BSTR;
return S_OK;
}
HRESULT PropVarEm_Set_Str(PROPVARIANT *p, const char *s) throw()
{
p->bstrVal = AllocBstrFromAscii(s);
if (p->bstrVal)
{
p->vt = VT_BSTR;
return S_OK;
}
p->vt = VT_ERROR;
p->scode = E_OUTOFMEMORY;
return E_OUTOFMEMORY;
}
CPropVariant::CPropVariant(const PROPVARIANT &varSrc)
{
vt = VT_EMPTY;
InternalCopy(&varSrc);
}
CPropVariant::CPropVariant(const CPropVariant &varSrc)
{
vt = VT_EMPTY;
InternalCopy(&varSrc);
}
CPropVariant::CPropVariant(BSTR bstrSrc)
{
vt = VT_EMPTY;
*this = bstrSrc;
}
CPropVariant::CPropVariant(LPCOLESTR lpszSrc)
{
vt = VT_EMPTY;
*this = lpszSrc;
}
CPropVariant& CPropVariant::operator=(const CPropVariant &varSrc)
{
InternalCopy(&varSrc);
return *this;
}
CPropVariant& CPropVariant::operator=(const PROPVARIANT &varSrc)
{
InternalCopy(&varSrc);
return *this;
}
CPropVariant& CPropVariant::operator=(BSTR bstrSrc)
{
*this = (LPCOLESTR)bstrSrc;
return *this;
}
static const char * const kMemException = "out of memory";
CPropVariant& CPropVariant::operator=(LPCOLESTR lpszSrc)
{
InternalClear();
vt = VT_BSTR;
wReserved1 = 0;
bstrVal = ::SysAllocString(lpszSrc);
if (!bstrVal && lpszSrc)
{
throw kMemException;
// vt = VT_ERROR;
// scode = E_OUTOFMEMORY;
}
return *this;
}
CPropVariant& CPropVariant::operator=(const UString &s)
{
InternalClear();
vt = VT_BSTR;
wReserved1 = 0;
bstrVal = ::SysAllocStringLen(s, s.Len());
if (!bstrVal)
throw kMemException;
return *this;
}
CPropVariant& CPropVariant::operator=(const UString2 &s)
{
/*
if (s.IsEmpty())
*this = L"";
else
*/
{
InternalClear();
vt = VT_BSTR;
wReserved1 = 0;
bstrVal = ::SysAllocStringLen(s.GetRawPtr(), s.Len());
if (!bstrVal)
throw kMemException;
/* SysAllocStringLen probably appends a null-terminating character for NULL string.
But it doesn't specified in MSDN.
But we suppose that it works
if (!s.GetRawPtr())
{
*bstrVal = 0;
}
*/
/* MSDN: Windows CE: SysAllocStringLen() : Passing invalid (and under some circumstances NULL)
pointers to this function causes an unexpected termination of the application.
Is it safe? Maybe we must chamnge the code for that case ? */
}
return *this;
}
CPropVariant& CPropVariant::operator=(const char *s)
{
InternalClear();
vt = VT_BSTR;
wReserved1 = 0;
bstrVal = AllocBstrFromAscii(s);
if (!bstrVal)
{
throw kMemException;
// vt = VT_ERROR;
// scode = E_OUTOFMEMORY;
}
return *this;
}
CPropVariant& CPropVariant::operator=(bool bSrc) throw()
{
if (vt != VT_BOOL)
{
InternalClear();
vt = VT_BOOL;
}
boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE;
return *this;
}
BSTR CPropVariant::AllocBstr(unsigned numChars)
{
if (vt != VT_EMPTY)
InternalClear();
vt = VT_BSTR;
wReserved1 = 0;
bstrVal = ::SysAllocStringLen(NULL, numChars);
if (!bstrVal)
{
throw kMemException;
// vt = VT_ERROR;
// scode = E_OUTOFMEMORY;
}
return bstrVal;
}
#define SET_PROP_FUNC(type, id, dest) \
CPropVariant& CPropVariant::operator=(type value) throw() \
{ if (vt != id) { InternalClear(); vt = id; } \
dest = value; return *this; }
SET_PROP_FUNC(Byte, VT_UI1, bVal)
// SET_PROP_FUNC(Int16, VT_I2, iVal)
SET_PROP_FUNC(Int32, VT_I4, lVal)
SET_PROP_FUNC(UInt32, VT_UI4, ulVal)
SET_PROP_FUNC(UInt64, VT_UI8, uhVal.QuadPart)
SET_PROP_FUNC(Int64, VT_I8, hVal.QuadPart)
SET_PROP_FUNC(const FILETIME &, VT_FILETIME, filetime)
HRESULT PropVariant_Clear(PROPVARIANT *prop) throw()
{
switch (prop->vt)
{
case VT_EMPTY:
case VT_UI1:
case VT_I1:
case VT_I2:
case VT_UI2:
case VT_BOOL:
case VT_I4:
case VT_UI4:
case VT_R4:
case VT_INT:
case VT_UINT:
case VT_ERROR:
case VT_FILETIME:
case VT_UI8:
case VT_R8:
case VT_CY:
case VT_DATE:
prop->vt = VT_EMPTY;
prop->wReserved1 = 0;
prop->wReserved2 = 0;
prop->wReserved3 = 0;
prop->uhVal.QuadPart = 0;
return S_OK;
}
return ::VariantClear((VARIANTARG *)prop);
// return ::PropVariantClear(prop);
// PropVariantClear can clear VT_BLOB.
}
HRESULT CPropVariant::Clear() throw()
{
if (vt == VT_EMPTY)
return S_OK;
return PropVariant_Clear(this);
}
HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw()
{
::VariantClear((tagVARIANT *)this);
switch (pSrc->vt)
{
case VT_UI1:
case VT_I1:
case VT_I2:
case VT_UI2:
case VT_BOOL:
case VT_I4:
case VT_UI4:
case VT_R4:
case VT_INT:
case VT_UINT:
case VT_ERROR:
case VT_FILETIME:
case VT_UI8:
case VT_R8:
case VT_CY:
case VT_DATE:
memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT));
return S_OK;
}
return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)const_cast<PROPVARIANT *>(pSrc));
}
HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw()
{
HRESULT hr = Clear();
if (FAILED(hr))
return hr;
memcpy(this, pSrc, sizeof(PROPVARIANT));
pSrc->vt = VT_EMPTY;
return S_OK;
}
HRESULT CPropVariant::Detach(PROPVARIANT *pDest) throw()
{
if (pDest->vt != VT_EMPTY)
{
HRESULT hr = PropVariant_Clear(pDest);
if (FAILED(hr))
return hr;
}
memcpy(pDest, this, sizeof(PROPVARIANT));
vt = VT_EMPTY;
return S_OK;
}
HRESULT CPropVariant::InternalClear() throw()
{
if (vt == VT_EMPTY)
return S_OK;
HRESULT hr = Clear();
if (FAILED(hr))
{
vt = VT_ERROR;
scode = hr;
}
return hr;
}
void CPropVariant::InternalCopy(const PROPVARIANT *pSrc)
{
HRESULT hr = Copy(pSrc);
if (FAILED(hr))
{
if (hr == E_OUTOFMEMORY)
throw kMemException;
vt = VT_ERROR;
scode = hr;
}
}
int CPropVariant::Compare(const CPropVariant &a) throw()
{
if (vt != a.vt)
return MyCompare(vt, a.vt);
switch (vt)
{
case VT_EMPTY: return 0;
// case VT_I1: return MyCompare(cVal, a.cVal);
case VT_UI1: return MyCompare(bVal, a.bVal);
case VT_I2: return MyCompare(iVal, a.iVal);
case VT_UI2: return MyCompare(uiVal, a.uiVal);
case VT_I4: return MyCompare(lVal, a.lVal);
case VT_UI4: return MyCompare(ulVal, a.ulVal);
// case VT_UINT: return MyCompare(uintVal, a.uintVal);
case VT_I8: return MyCompare(hVal.QuadPart, a.hVal.QuadPart);
case VT_UI8: return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart);
case VT_BOOL: return -MyCompare(boolVal, a.boolVal);
case VT_FILETIME: return ::CompareFileTime(&filetime, &a.filetime);
case VT_BSTR: return 0; // Not implemented
default: return 0;
}
}
}}