// 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_id_dest(id, dest) \ if (vt != id) { InternalClear(); vt = id; } dest = value; wReserved1 = 0; void CPropVariant::Set_Int32(Int32 value) throw() { SET_PROP_id_dest(VT_I4, lVal) } void CPropVariant::Set_Int64(Int64 value) throw() { SET_PROP_id_dest(VT_I8, hVal.QuadPart) } #define SET_PROP_FUNC(type, id, dest) \ CPropVariant& CPropVariant::operator=(type value) throw() \ { SET_PROP_id_dest(id, dest) 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) #define CASE_SIMPLE_VT_VALUES \ case VT_EMPTY: \ case VT_BOOL: \ case VT_FILETIME: \ case VT_UI8: \ case VT_UI4: \ case VT_UI2: \ case VT_UI1: \ case VT_I8: \ case VT_I4: \ case VT_I2: \ case VT_I1: \ case VT_UINT: \ case VT_INT: \ case VT_NULL: \ case VT_ERROR: \ case VT_R4: \ case VT_R8: \ case VT_CY: \ case VT_DATE: \ /* ::VariantClear() and ::VariantCopy() don't work, if (vt == VT_FILETIME) So we handle VT_FILETIME and another simple types directly we call system functions for VT_BSTR and for unknown typed */ CPropVariant::~CPropVariant() throw() { switch ((unsigned)vt) { CASE_SIMPLE_VT_VALUES // vt = VT_EMPTY; // it's optional return; } ::VariantClear((tagVARIANT *)this); } HRESULT PropVariant_Clear(PROPVARIANT *prop) throw() { switch ((unsigned)prop->vt) { CASE_SIMPLE_VT_VALUES prop->vt = VT_EMPTY; break; default: { const HRESULT res = ::VariantClear((VARIANTARG *)prop); if (res != S_OK || prop->vt != VT_EMPTY) return res; break; } } prop->wReserved1 = 0; prop->wReserved2 = 0; prop->wReserved3 = 0; prop->uhVal.QuadPart = 0; return S_OK; } HRESULT CPropVariant::Clear() throw() { if (vt == VT_EMPTY) { wReserved1 = 0; return S_OK; } return PropVariant_Clear(this); } HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw() { Clear(); switch ((unsigned)pSrc->vt) { CASE_SIMPLE_VT_VALUES memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT)); return S_OK; } return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)const_cast(pSrc)); } HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw() { const HRESULT hr = Clear(); if (FAILED(hr)) return hr; // memcpy((PROPVARIANT *)this, pSrc, sizeof(PROPVARIANT)); *(PROPVARIANT *)this = *pSrc; pSrc->vt = VT_EMPTY; pSrc->wReserved1 = 0; return S_OK; } HRESULT CPropVariant::Detach(PROPVARIANT *pDest) throw() { if (pDest->vt != VT_EMPTY) { const HRESULT hr = PropVariant_Clear(pDest); if (FAILED(hr)) return hr; } // memcpy(pDest, this, sizeof(PROPVARIANT)); *pDest = *(PROPVARIANT *)this; vt = VT_EMPTY; wReserved1 = 0; return S_OK; } HRESULT CPropVariant::InternalClear() throw() { if (vt == VT_EMPTY) { wReserved1 = 0; return S_OK; } const HRESULT hr = Clear(); if (FAILED(hr)) { vt = VT_ERROR; scode = hr; } return hr; } void CPropVariant::InternalCopy(const PROPVARIANT *pSrc) { const 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 ((unsigned)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: { const int res = CompareFileTime(&filetime, &a.filetime); if (res != 0) return res; const unsigned v1 = Get_Ns100(); const unsigned v2 = a.Get_Ns100(); return MyCompare(v1, v2); } case VT_BSTR: return 0; // Not implemented default: return 0; } } }}