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
AllocBstrFromAscii(const char * s)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
PropVarEm_Alloc_Bstr(PROPVARIANT * p,unsigned numChars)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
PropVarEm_Set_Str(PROPVARIANT * p,const char * s)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
CPropVariant(const PROPVARIANT & varSrc)52 CPropVariant::CPropVariant(const PROPVARIANT &varSrc)
53 {
54 vt = VT_EMPTY;
55 InternalCopy(&varSrc);
56 }
57
CPropVariant(const CPropVariant & varSrc)58 CPropVariant::CPropVariant(const CPropVariant &varSrc)
59 {
60 vt = VT_EMPTY;
61 InternalCopy(&varSrc);
62 }
63
CPropVariant(BSTR bstrSrc)64 CPropVariant::CPropVariant(BSTR bstrSrc)
65 {
66 vt = VT_EMPTY;
67 *this = bstrSrc;
68 }
69
CPropVariant(LPCOLESTR lpszSrc)70 CPropVariant::CPropVariant(LPCOLESTR lpszSrc)
71 {
72 vt = VT_EMPTY;
73 *this = lpszSrc;
74 }
75
operator =(const CPropVariant & varSrc)76 CPropVariant& CPropVariant::operator=(const CPropVariant &varSrc)
77 {
78 InternalCopy(&varSrc);
79 return *this;
80 }
81
operator =(const PROPVARIANT & varSrc)82 CPropVariant& CPropVariant::operator=(const PROPVARIANT &varSrc)
83 {
84 InternalCopy(&varSrc);
85 return *this;
86 }
87
operator =(BSTR bstrSrc)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
operator =(LPCOLESTR lpszSrc)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
operator =(const UString & s)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
operator =(const UString2 & s)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
operator =(const char * s)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
operator =(bool bSrc)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
AllocBstr(unsigned numChars)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_id_dest(id, dest) \
196 if (vt != id) { InternalClear(); vt = id; } dest = value; wReserved1 = 0;
197
Set_Int32(Int32 value)198 void CPropVariant::Set_Int32(Int32 value) throw()
199 {
200 SET_PROP_id_dest(VT_I4, lVal)
201 }
202
Set_Int64(Int64 value)203 void 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
SET_PROP_FUNC(Byte,VT_UI1,bVal)212 SET_PROP_FUNC(Byte, VT_UI1, bVal)
213 // SET_PROP_FUNC(Int16, VT_I2, iVal)
214 // SET_PROP_FUNC(Int32, VT_I4, lVal)
215 SET_PROP_FUNC(UInt32, VT_UI4, ulVal)
216 SET_PROP_FUNC(UInt64, VT_UI8, uhVal.QuadPart)
217 // SET_PROP_FUNC(Int64, VT_I8, hVal.QuadPart)
218 SET_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
248 CPropVariant::~CPropVariant() throw()
249 {
250 switch ((unsigned)vt)
251 {
252 CASE_SIMPLE_VT_VALUES
253 // vt = VT_EMPTY; // it's optional
254 return;
255 default: break;
256 }
257 ::VariantClear((tagVARIANT *)this);
258 }
259
PropVariant_Clear(PROPVARIANT * prop)260 HRESULT PropVariant_Clear(PROPVARIANT *prop) throw()
261 {
262 switch ((unsigned)prop->vt)
263 {
264 CASE_SIMPLE_VT_VALUES
265 prop->vt = VT_EMPTY;
266 break;
267 default:
268 {
269 const HRESULT res = ::VariantClear((VARIANTARG *)prop);
270 if (res != S_OK || prop->vt != VT_EMPTY)
271 return res;
272 break;
273 }
274 }
275 prop->wReserved1 = 0;
276 prop->wReserved2 = 0;
277 prop->wReserved3 = 0;
278 prop->uhVal.QuadPart = 0;
279 return S_OK;
280 }
281
Clear()282 HRESULT CPropVariant::Clear() throw()
283 {
284 if (vt == VT_EMPTY)
285 {
286 wReserved1 = 0;
287 return S_OK;
288 }
289 return PropVariant_Clear(this);
290 }
291
Copy(const PROPVARIANT * pSrc)292 HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw()
293 {
294 Clear();
295 switch ((unsigned)pSrc->vt)
296 {
297 CASE_SIMPLE_VT_VALUES
298 memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT));
299 return S_OK;
300 default: break;
301 }
302 return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)const_cast<PROPVARIANT *>(pSrc));
303 }
304
305
Attach(PROPVARIANT * pSrc)306 HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw()
307 {
308 const HRESULT hr = Clear();
309 if (FAILED(hr))
310 return hr;
311 // memcpy((PROPVARIANT *)this, pSrc, sizeof(PROPVARIANT));
312 *(PROPVARIANT *)this = *pSrc;
313 pSrc->vt = VT_EMPTY;
314 pSrc->wReserved1 = 0;
315 return S_OK;
316 }
317
Detach(PROPVARIANT * pDest)318 HRESULT CPropVariant::Detach(PROPVARIANT *pDest) throw()
319 {
320 if (pDest->vt != VT_EMPTY)
321 {
322 const HRESULT hr = PropVariant_Clear(pDest);
323 if (FAILED(hr))
324 return hr;
325 }
326 // memcpy(pDest, this, sizeof(PROPVARIANT));
327 *pDest = *(PROPVARIANT *)this;
328 vt = VT_EMPTY;
329 wReserved1 = 0;
330 return S_OK;
331 }
332
InternalClear()333 HRESULT CPropVariant::InternalClear() throw()
334 {
335 if (vt == VT_EMPTY)
336 {
337 wReserved1 = 0;
338 return S_OK;
339 }
340 const HRESULT hr = Clear();
341 if (FAILED(hr))
342 {
343 vt = VT_ERROR;
344 scode = hr;
345 }
346 return hr;
347 }
348
InternalCopy(const PROPVARIANT * pSrc)349 void CPropVariant::InternalCopy(const PROPVARIANT *pSrc)
350 {
351 const HRESULT hr = Copy(pSrc);
352 if (FAILED(hr))
353 {
354 if (hr == E_OUTOFMEMORY)
355 throw kMemException;
356 vt = VT_ERROR;
357 scode = hr;
358 }
359 }
360
361
Compare(const CPropVariant & a)362 int CPropVariant::Compare(const CPropVariant &a) throw()
363 {
364 if (vt != a.vt)
365 return MyCompare(vt, a.vt);
366 switch ((unsigned)vt)
367 {
368 case VT_EMPTY: return 0;
369 // case VT_I1: return MyCompare(cVal, a.cVal);
370 case VT_UI1: return MyCompare(bVal, a.bVal);
371 case VT_I2: return MyCompare(iVal, a.iVal);
372 case VT_UI2: return MyCompare(uiVal, a.uiVal);
373 case VT_I4: return MyCompare(lVal, a.lVal);
374 case VT_UI4: return MyCompare(ulVal, a.ulVal);
375 // case VT_UINT: return MyCompare(uintVal, a.uintVal);
376 case VT_I8: return MyCompare(hVal.QuadPart, a.hVal.QuadPart);
377 case VT_UI8: return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart);
378 case VT_BOOL: return -MyCompare(boolVal, a.boolVal);
379 case VT_FILETIME:
380 {
381 const int res = CompareFileTime(&filetime, &a.filetime);
382 if (res != 0)
383 return res;
384 const unsigned v1 = Get_Ns100();
385 const unsigned v2 = a.Get_Ns100();
386 return MyCompare(v1, v2);
387 }
388 case VT_BSTR: return 0; // Not implemented
389 default: return 0;
390 }
391 }
392
393 }}
394