• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   }
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