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()
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
PropVariant_Clear(PROPVARIANT * prop)259 HRESULT 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
Clear()281 HRESULT 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
Copy(const PROPVARIANT * pSrc)291 HRESULT 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
Attach(PROPVARIANT * pSrc)304 HRESULT 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
Detach(PROPVARIANT * pDest)316 HRESULT 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
InternalClear()331 HRESULT 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
InternalCopy(const PROPVARIANT * pSrc)347 void 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
Compare(const CPropVariant & a)360 int 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