1// Windows/PropVariant.cpp 2 3#include "StdAfx.h" 4 5#include "../Common/Defs.h" 6 7#include "PropVariant.h" 8 9namespace NWindows { 10namespace NCOM { 11 12BSTR AllocBstrFromAscii(const char *s) throw() 13{ 14 if (!s) 15 return NULL; 16 UINT len = (UINT)strlen(s); 17 BSTR p = ::SysAllocStringLen(NULL, len); 18 if (p) 19 { 20 for (UINT i = 0; i <= len; i++) 21 p[i] = (Byte)s[i]; 22 } 23 return p; 24} 25 26HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw() 27{ 28 p->bstrVal = ::SysAllocStringLen(NULL, numChars); 29 if (!p->bstrVal) 30 { 31 p->vt = VT_ERROR; 32 p->scode = E_OUTOFMEMORY; 33 return E_OUTOFMEMORY; 34 } 35 p->vt = VT_BSTR; 36 return S_OK; 37} 38 39HRESULT PropVarEm_Set_Str(PROPVARIANT *p, const char *s) throw() 40{ 41 p->bstrVal = AllocBstrFromAscii(s); 42 if (p->bstrVal) 43 { 44 p->vt = VT_BSTR; 45 return S_OK; 46 } 47 p->vt = VT_ERROR; 48 p->scode = E_OUTOFMEMORY; 49 return E_OUTOFMEMORY; 50} 51 52CPropVariant::CPropVariant(const PROPVARIANT &varSrc) 53{ 54 vt = VT_EMPTY; 55 InternalCopy(&varSrc); 56} 57 58CPropVariant::CPropVariant(const CPropVariant &varSrc) 59{ 60 vt = VT_EMPTY; 61 InternalCopy(&varSrc); 62} 63 64CPropVariant::CPropVariant(BSTR bstrSrc) 65{ 66 vt = VT_EMPTY; 67 *this = bstrSrc; 68} 69 70CPropVariant::CPropVariant(LPCOLESTR lpszSrc) 71{ 72 vt = VT_EMPTY; 73 *this = lpszSrc; 74} 75 76CPropVariant& CPropVariant::operator=(const CPropVariant &varSrc) 77{ 78 InternalCopy(&varSrc); 79 return *this; 80} 81 82CPropVariant& CPropVariant::operator=(const PROPVARIANT &varSrc) 83{ 84 InternalCopy(&varSrc); 85 return *this; 86} 87 88CPropVariant& CPropVariant::operator=(BSTR bstrSrc) 89{ 90 *this = (LPCOLESTR)bstrSrc; 91 return *this; 92} 93 94static const char * const kMemException = "out of memory"; 95 96CPropVariant& CPropVariant::operator=(LPCOLESTR lpszSrc) 97{ 98 InternalClear(); 99 vt = VT_BSTR; 100 wReserved1 = 0; 101 bstrVal = ::SysAllocString(lpszSrc); 102 if (!bstrVal && lpszSrc) 103 { 104 throw kMemException; 105 // vt = VT_ERROR; 106 // scode = E_OUTOFMEMORY; 107 } 108 return *this; 109} 110 111CPropVariant& CPropVariant::operator=(const UString &s) 112{ 113 InternalClear(); 114 vt = VT_BSTR; 115 wReserved1 = 0; 116 bstrVal = ::SysAllocStringLen(s, s.Len()); 117 if (!bstrVal) 118 throw kMemException; 119 return *this; 120} 121 122CPropVariant& CPropVariant::operator=(const UString2 &s) 123{ 124 /* 125 if (s.IsEmpty()) 126 *this = L""; 127 else 128 */ 129 { 130 InternalClear(); 131 vt = VT_BSTR; 132 wReserved1 = 0; 133 bstrVal = ::SysAllocStringLen(s.GetRawPtr(), s.Len()); 134 if (!bstrVal) 135 throw kMemException; 136 /* SysAllocStringLen probably appends a null-terminating character for NULL string. 137 But it doesn't specified in MSDN. 138 But we suppose that it works 139 140 if (!s.GetRawPtr()) 141 { 142 *bstrVal = 0; 143 } 144 */ 145 146 /* MSDN: Windows CE: SysAllocStringLen() : Passing invalid (and under some circumstances NULL) 147 pointers to this function causes an unexpected termination of the application. 148 Is it safe? Maybe we must chamnge the code for that case ? */ 149 } 150 return *this; 151} 152 153CPropVariant& CPropVariant::operator=(const char *s) 154{ 155 InternalClear(); 156 vt = VT_BSTR; 157 wReserved1 = 0; 158 bstrVal = AllocBstrFromAscii(s); 159 if (!bstrVal) 160 { 161 throw kMemException; 162 // vt = VT_ERROR; 163 // scode = E_OUTOFMEMORY; 164 } 165 return *this; 166} 167 168CPropVariant& CPropVariant::operator=(bool bSrc) throw() 169{ 170 if (vt != VT_BOOL) 171 { 172 InternalClear(); 173 vt = VT_BOOL; 174 } 175 boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE; 176 return *this; 177} 178 179BSTR CPropVariant::AllocBstr(unsigned numChars) 180{ 181 if (vt != VT_EMPTY) 182 InternalClear(); 183 vt = VT_BSTR; 184 wReserved1 = 0; 185 bstrVal = ::SysAllocStringLen(NULL, numChars); 186 if (!bstrVal) 187 { 188 throw kMemException; 189 // vt = VT_ERROR; 190 // scode = E_OUTOFMEMORY; 191 } 192 return bstrVal; 193} 194 195#define SET_PROP_id_dest(id, dest) \ 196 if (vt != id) { InternalClear(); vt = id; } dest = value; wReserved1 = 0; 197 198void CPropVariant::Set_Int32(Int32 value) throw() 199{ 200 SET_PROP_id_dest(VT_I4, lVal) 201} 202 203void CPropVariant::Set_Int64(Int64 value) throw() 204{ 205 SET_PROP_id_dest(VT_I8, hVal.QuadPart) 206} 207 208#define SET_PROP_FUNC(type, id, dest) \ 209 CPropVariant& CPropVariant::operator=(type value) throw() \ 210 { SET_PROP_id_dest(id, dest) return *this; } 211 212SET_PROP_FUNC(Byte, VT_UI1, bVal) 213// SET_PROP_FUNC(Int16, VT_I2, iVal) 214// SET_PROP_FUNC(Int32, VT_I4, lVal) 215SET_PROP_FUNC(UInt32, VT_UI4, ulVal) 216SET_PROP_FUNC(UInt64, VT_UI8, uhVal.QuadPart) 217// SET_PROP_FUNC(Int64, VT_I8, hVal.QuadPart) 218SET_PROP_FUNC(const FILETIME &, VT_FILETIME, filetime) 219 220#define CASE_SIMPLE_VT_VALUES \ 221 case VT_EMPTY: \ 222 case VT_BOOL: \ 223 case VT_FILETIME: \ 224 case VT_UI8: \ 225 case VT_UI4: \ 226 case VT_UI2: \ 227 case VT_UI1: \ 228 case VT_I8: \ 229 case VT_I4: \ 230 case VT_I2: \ 231 case VT_I1: \ 232 case VT_UINT: \ 233 case VT_INT: \ 234 case VT_NULL: \ 235 case VT_ERROR: \ 236 case VT_R4: \ 237 case VT_R8: \ 238 case VT_CY: \ 239 case VT_DATE: \ 240 241 242/* 243 ::VariantClear() and ::VariantCopy() don't work, if (vt == VT_FILETIME) 244 So we handle VT_FILETIME and another simple types directly 245 we call system functions for VT_BSTR and for unknown typed 246*/ 247 248CPropVariant::~CPropVariant() throw() 249{ 250 switch ((unsigned)vt) 251 { 252 CASE_SIMPLE_VT_VALUES 253 // vt = VT_EMPTY; // it's optional 254 return; 255 } 256 ::VariantClear((tagVARIANT *)this); 257} 258 259HRESULT PropVariant_Clear(PROPVARIANT *prop) throw() 260{ 261 switch ((unsigned)prop->vt) 262 { 263 CASE_SIMPLE_VT_VALUES 264 prop->vt = VT_EMPTY; 265 break; 266 default: 267 { 268 const HRESULT res = ::VariantClear((VARIANTARG *)prop); 269 if (res != S_OK || prop->vt != VT_EMPTY) 270 return res; 271 break; 272 } 273 } 274 prop->wReserved1 = 0; 275 prop->wReserved2 = 0; 276 prop->wReserved3 = 0; 277 prop->uhVal.QuadPart = 0; 278 return S_OK; 279} 280 281HRESULT CPropVariant::Clear() throw() 282{ 283 if (vt == VT_EMPTY) 284 { 285 wReserved1 = 0; 286 return S_OK; 287 } 288 return PropVariant_Clear(this); 289} 290 291HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw() 292{ 293 Clear(); 294 switch ((unsigned)pSrc->vt) 295 { 296 CASE_SIMPLE_VT_VALUES 297 memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT)); 298 return S_OK; 299 } 300 return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)const_cast<PROPVARIANT *>(pSrc)); 301} 302 303 304HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw() 305{ 306 const HRESULT hr = Clear(); 307 if (FAILED(hr)) 308 return hr; 309 // memcpy((PROPVARIANT *)this, pSrc, sizeof(PROPVARIANT)); 310 *(PROPVARIANT *)this = *pSrc; 311 pSrc->vt = VT_EMPTY; 312 pSrc->wReserved1 = 0; 313 return S_OK; 314} 315 316HRESULT CPropVariant::Detach(PROPVARIANT *pDest) throw() 317{ 318 if (pDest->vt != VT_EMPTY) 319 { 320 const HRESULT hr = PropVariant_Clear(pDest); 321 if (FAILED(hr)) 322 return hr; 323 } 324 // memcpy(pDest, this, sizeof(PROPVARIANT)); 325 *pDest = *(PROPVARIANT *)this; 326 vt = VT_EMPTY; 327 wReserved1 = 0; 328 return S_OK; 329} 330 331HRESULT CPropVariant::InternalClear() throw() 332{ 333 if (vt == VT_EMPTY) 334 { 335 wReserved1 = 0; 336 return S_OK; 337 } 338 const HRESULT hr = Clear(); 339 if (FAILED(hr)) 340 { 341 vt = VT_ERROR; 342 scode = hr; 343 } 344 return hr; 345} 346 347void CPropVariant::InternalCopy(const PROPVARIANT *pSrc) 348{ 349 const HRESULT hr = Copy(pSrc); 350 if (FAILED(hr)) 351 { 352 if (hr == E_OUTOFMEMORY) 353 throw kMemException; 354 vt = VT_ERROR; 355 scode = hr; 356 } 357} 358 359 360int CPropVariant::Compare(const CPropVariant &a) throw() 361{ 362 if (vt != a.vt) 363 return MyCompare(vt, a.vt); 364 switch ((unsigned)vt) 365 { 366 case VT_EMPTY: return 0; 367 // case VT_I1: return MyCompare(cVal, a.cVal); 368 case VT_UI1: return MyCompare(bVal, a.bVal); 369 case VT_I2: return MyCompare(iVal, a.iVal); 370 case VT_UI2: return MyCompare(uiVal, a.uiVal); 371 case VT_I4: return MyCompare(lVal, a.lVal); 372 case VT_UI4: return MyCompare(ulVal, a.ulVal); 373 // case VT_UINT: return MyCompare(uintVal, a.uintVal); 374 case VT_I8: return MyCompare(hVal.QuadPart, a.hVal.QuadPart); 375 case VT_UI8: return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart); 376 case VT_BOOL: return -MyCompare(boolVal, a.boolVal); 377 case VT_FILETIME: 378 { 379 const int res = CompareFileTime(&filetime, &a.filetime); 380 if (res != 0) 381 return res; 382 const unsigned v1 = Get_Ns100(); 383 const unsigned v2 = a.Get_Ns100(); 384 return MyCompare(v1, v2); 385 } 386 case VT_BSTR: return 0; // Not implemented 387 default: return 0; 388 } 389} 390 391}} 392