1 // Windows/PropVariant.cpp 2 3 #include "StdAfx.h" 4 5 #include "../Common/Defs.h" 6 7 #include "PropVariant.h" 8 9 namespace NWindows { 10 namespace NCOM { 11 12 BSTR 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 26 HRESULT 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 39 HRESULT 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 52 CPropVariant::CPropVariant(const PROPVARIANT &varSrc) 53 { 54 vt = VT_EMPTY; 55 InternalCopy(&varSrc); 56 } 57 58 CPropVariant::CPropVariant(const CPropVariant &varSrc) 59 { 60 vt = VT_EMPTY; 61 InternalCopy(&varSrc); 62 } 63 64 CPropVariant::CPropVariant(BSTR bstrSrc) 65 { 66 vt = VT_EMPTY; 67 *this = bstrSrc; 68 } 69 70 CPropVariant::CPropVariant(LPCOLESTR lpszSrc) 71 { 72 vt = VT_EMPTY; 73 *this = lpszSrc; 74 } 75 76 CPropVariant& CPropVariant::operator=(const CPropVariant &varSrc) 77 { 78 InternalCopy(&varSrc); 79 return *this; 80 } 81 82 CPropVariant& CPropVariant::operator=(const PROPVARIANT &varSrc) 83 { 84 InternalCopy(&varSrc); 85 return *this; 86 } 87 88 CPropVariant& CPropVariant::operator=(BSTR bstrSrc) 89 { 90 *this = (LPCOLESTR)bstrSrc; 91 return *this; 92 } 93 94 static const char * const kMemException = "out of memory"; 95 96 CPropVariant& 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 111 CPropVariant& 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 122 CPropVariant& 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 153 CPropVariant& 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 168 CPropVariant& 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 179 BSTR 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_FUNC(type, id, dest) \ 196 CPropVariant& CPropVariant::operator=(type value) throw() \ 197 { if (vt != id) { InternalClear(); vt = id; } \ 198 dest = value; return *this; } 199 200 SET_PROP_FUNC(Byte, VT_UI1, bVal) 201 // SET_PROP_FUNC(Int16, VT_I2, iVal) 202 SET_PROP_FUNC(Int32, VT_I4, lVal) 203 SET_PROP_FUNC(UInt32, VT_UI4, ulVal) 204 SET_PROP_FUNC(UInt64, VT_UI8, uhVal.QuadPart) 205 SET_PROP_FUNC(Int64, VT_I8, hVal.QuadPart) 206 SET_PROP_FUNC(const FILETIME &, VT_FILETIME, filetime) 207 208 HRESULT PropVariant_Clear(PROPVARIANT *prop) throw() 209 { 210 switch (prop->vt) 211 { 212 case VT_EMPTY: 213 case VT_UI1: 214 case VT_I1: 215 case VT_I2: 216 case VT_UI2: 217 case VT_BOOL: 218 case VT_I4: 219 case VT_UI4: 220 case VT_R4: 221 case VT_INT: 222 case VT_UINT: 223 case VT_ERROR: 224 case VT_FILETIME: 225 case VT_UI8: 226 case VT_R8: 227 case VT_CY: 228 case VT_DATE: 229 prop->vt = VT_EMPTY; 230 prop->wReserved1 = 0; 231 prop->wReserved2 = 0; 232 prop->wReserved3 = 0; 233 prop->uhVal.QuadPart = 0; 234 return S_OK; 235 } 236 return ::VariantClear((VARIANTARG *)prop); 237 // return ::PropVariantClear(prop); 238 // PropVariantClear can clear VT_BLOB. 239 } 240 241 HRESULT CPropVariant::Clear() throw() 242 { 243 if (vt == VT_EMPTY) 244 return S_OK; 245 return PropVariant_Clear(this); 246 } 247 248 HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw() 249 { 250 ::VariantClear((tagVARIANT *)this); 251 switch (pSrc->vt) 252 { 253 case VT_UI1: 254 case VT_I1: 255 case VT_I2: 256 case VT_UI2: 257 case VT_BOOL: 258 case VT_I4: 259 case VT_UI4: 260 case VT_R4: 261 case VT_INT: 262 case VT_UINT: 263 case VT_ERROR: 264 case VT_FILETIME: 265 case VT_UI8: 266 case VT_R8: 267 case VT_CY: 268 case VT_DATE: 269 memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT)); 270 return S_OK; 271 } 272 return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)const_cast<PROPVARIANT *>(pSrc)); 273 } 274 275 276 HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw() 277 { 278 HRESULT hr = Clear(); 279 if (FAILED(hr)) 280 return hr; 281 memcpy(this, pSrc, sizeof(PROPVARIANT)); 282 pSrc->vt = VT_EMPTY; 283 return S_OK; 284 } 285 286 HRESULT CPropVariant::Detach(PROPVARIANT *pDest) throw() 287 { 288 if (pDest->vt != VT_EMPTY) 289 { 290 HRESULT hr = PropVariant_Clear(pDest); 291 if (FAILED(hr)) 292 return hr; 293 } 294 memcpy(pDest, this, sizeof(PROPVARIANT)); 295 vt = VT_EMPTY; 296 return S_OK; 297 } 298 299 HRESULT CPropVariant::InternalClear() throw() 300 { 301 if (vt == VT_EMPTY) 302 return S_OK; 303 HRESULT hr = Clear(); 304 if (FAILED(hr)) 305 { 306 vt = VT_ERROR; 307 scode = hr; 308 } 309 return hr; 310 } 311 312 void CPropVariant::InternalCopy(const PROPVARIANT *pSrc) 313 { 314 HRESULT hr = Copy(pSrc); 315 if (FAILED(hr)) 316 { 317 if (hr == E_OUTOFMEMORY) 318 throw kMemException; 319 vt = VT_ERROR; 320 scode = hr; 321 } 322 } 323 324 int CPropVariant::Compare(const CPropVariant &a) throw() 325 { 326 if (vt != a.vt) 327 return MyCompare(vt, a.vt); 328 switch (vt) 329 { 330 case VT_EMPTY: return 0; 331 // case VT_I1: return MyCompare(cVal, a.cVal); 332 case VT_UI1: return MyCompare(bVal, a.bVal); 333 case VT_I2: return MyCompare(iVal, a.iVal); 334 case VT_UI2: return MyCompare(uiVal, a.uiVal); 335 case VT_I4: return MyCompare(lVal, a.lVal); 336 case VT_UI4: return MyCompare(ulVal, a.ulVal); 337 // case VT_UINT: return MyCompare(uintVal, a.uintVal); 338 case VT_I8: return MyCompare(hVal.QuadPart, a.hVal.QuadPart); 339 case VT_UI8: return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart); 340 case VT_BOOL: return -MyCompare(boolVal, a.boolVal); 341 case VT_FILETIME: return ::CompareFileTime(&filetime, &a.filetime); 342 case VT_BSTR: return 0; // Not implemented 343 default: return 0; 344 } 345 } 346 347 }} 348