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;
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 HRESULT PropVariant_Clear(PROPVARIANT *prop) throw()
221 {
222   switch (prop->vt)
223   {
224     case VT_EMPTY:
225     case VT_UI1:
226     case VT_I1:
227     case VT_I2:
228     case VT_UI2:
229     case VT_BOOL:
230     case VT_I4:
231     case VT_UI4:
232     case VT_R4:
233     case VT_INT:
234     case VT_UINT:
235     case VT_ERROR:
236     case VT_FILETIME:
237     case VT_UI8:
238     case VT_R8:
239     case VT_CY:
240     case VT_DATE:
241       prop->vt = VT_EMPTY;
242       prop->wReserved1 = 0;
243       prop->wReserved2 = 0;
244       prop->wReserved3 = 0;
245       prop->uhVal.QuadPart = 0;
246       return S_OK;
247   }
248   return ::VariantClear((VARIANTARG *)prop);
249   // return ::PropVariantClear(prop);
250   // PropVariantClear can clear VT_BLOB.
251 }
252 
Clear()253 HRESULT CPropVariant::Clear() throw()
254 {
255   if (vt == VT_EMPTY)
256     return S_OK;
257   return PropVariant_Clear(this);
258 }
259 
Copy(const PROPVARIANT * pSrc)260 HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw()
261 {
262   ::VariantClear((tagVARIANT *)this);
263   switch (pSrc->vt)
264   {
265     case VT_UI1:
266     case VT_I1:
267     case VT_I2:
268     case VT_UI2:
269     case VT_BOOL:
270     case VT_I4:
271     case VT_UI4:
272     case VT_R4:
273     case VT_INT:
274     case VT_UINT:
275     case VT_ERROR:
276     case VT_FILETIME:
277     case VT_UI8:
278     case VT_R8:
279     case VT_CY:
280     case VT_DATE:
281       memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT));
282       return S_OK;
283   }
284   return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)const_cast<PROPVARIANT *>(pSrc));
285 }
286 
287 
Attach(PROPVARIANT * pSrc)288 HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw()
289 {
290   HRESULT hr = Clear();
291   if (FAILED(hr))
292     return hr;
293   // memcpy((PROPVARIANT *)this, pSrc, sizeof(PROPVARIANT));
294   *(PROPVARIANT *)this = *pSrc;
295   pSrc->vt = VT_EMPTY;
296   return S_OK;
297 }
298 
Detach(PROPVARIANT * pDest)299 HRESULT CPropVariant::Detach(PROPVARIANT *pDest) throw()
300 {
301   if (pDest->vt != VT_EMPTY)
302   {
303     HRESULT hr = PropVariant_Clear(pDest);
304     if (FAILED(hr))
305       return hr;
306   }
307   // memcpy(pDest, this, sizeof(PROPVARIANT));
308   *pDest = *(PROPVARIANT *)this;
309   vt = VT_EMPTY;
310   return S_OK;
311 }
312 
InternalClear()313 HRESULT CPropVariant::InternalClear() throw()
314 {
315   if (vt == VT_EMPTY)
316     return S_OK;
317   HRESULT hr = Clear();
318   if (FAILED(hr))
319   {
320     vt = VT_ERROR;
321     scode = hr;
322   }
323   return hr;
324 }
325 
InternalCopy(const PROPVARIANT * pSrc)326 void CPropVariant::InternalCopy(const PROPVARIANT *pSrc)
327 {
328   HRESULT hr = Copy(pSrc);
329   if (FAILED(hr))
330   {
331     if (hr == E_OUTOFMEMORY)
332       throw kMemException;
333     vt = VT_ERROR;
334     scode = hr;
335   }
336 }
337 
Compare(const CPropVariant & a)338 int CPropVariant::Compare(const CPropVariant &a) throw()
339 {
340   if (vt != a.vt)
341     return MyCompare(vt, a.vt);
342   switch (vt)
343   {
344     case VT_EMPTY: return 0;
345     // case VT_I1: return MyCompare(cVal, a.cVal);
346     case VT_UI1: return MyCompare(bVal, a.bVal);
347     case VT_I2: return MyCompare(iVal, a.iVal);
348     case VT_UI2: return MyCompare(uiVal, a.uiVal);
349     case VT_I4: return MyCompare(lVal, a.lVal);
350     case VT_UI4: return MyCompare(ulVal, a.ulVal);
351     // case VT_UINT: return MyCompare(uintVal, a.uintVal);
352     case VT_I8: return MyCompare(hVal.QuadPart, a.hVal.QuadPart);
353     case VT_UI8: return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart);
354     case VT_BOOL: return -MyCompare(boolVal, a.boolVal);
355     case VT_FILETIME: return ::CompareFileTime(&filetime, &a.filetime);
356     case VT_BSTR: return 0; // Not implemented
357     default: return 0;
358   }
359 }
360 
361 }}
362