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_FUNC(type, id, dest) \
196   CPropVariant& CPropVariant::operator=(type value) throw() \
197   { if (vt != id) { InternalClear(); vt = id; } \
198     dest = value; return *this; }
199 
SET_PROP_FUNC(Byte,VT_UI1,bVal)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 
Clear()241 HRESULT CPropVariant::Clear() throw()
242 {
243   if (vt == VT_EMPTY)
244     return S_OK;
245   return PropVariant_Clear(this);
246 }
247 
Copy(const PROPVARIANT * pSrc)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 
Attach(PROPVARIANT * pSrc)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 
Detach(PROPVARIANT * pDest)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 
InternalClear()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 
InternalCopy(const PROPVARIANT * pSrc)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 
Compare(const CPropVariant & a)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