1// Windows/PropVariant.cpp
2
3#include "StdAfx.h"
4
5#include "../Common/Defs.h"
6
7#include "PropVariant.h"
8
9namespace NWindows {
10namespace NCOM {
11
12BSTR 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
26HRESULT 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
39HRESULT 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
52CPropVariant::CPropVariant(const PROPVARIANT &varSrc)
53{
54  vt = VT_EMPTY;
55  InternalCopy(&varSrc);
56}
57
58CPropVariant::CPropVariant(const CPropVariant &varSrc)
59{
60  vt = VT_EMPTY;
61  InternalCopy(&varSrc);
62}
63
64CPropVariant::CPropVariant(BSTR bstrSrc)
65{
66  vt = VT_EMPTY;
67  *this = bstrSrc;
68}
69
70CPropVariant::CPropVariant(LPCOLESTR lpszSrc)
71{
72  vt = VT_EMPTY;
73  *this = lpszSrc;
74}
75
76CPropVariant& CPropVariant::operator=(const CPropVariant &varSrc)
77{
78  InternalCopy(&varSrc);
79  return *this;
80}
81
82CPropVariant& CPropVariant::operator=(const PROPVARIANT &varSrc)
83{
84  InternalCopy(&varSrc);
85  return *this;
86}
87
88CPropVariant& CPropVariant::operator=(BSTR bstrSrc)
89{
90  *this = (LPCOLESTR)bstrSrc;
91  return *this;
92}
93
94static const char * const kMemException = "out of memory";
95
96CPropVariant& 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
111CPropVariant& 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
122CPropVariant& 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
153CPropVariant& 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
168CPropVariant& 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
179BSTR 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
198void CPropVariant::Set_Int32(Int32 value) throw()
199{
200  SET_PROP_id_dest(VT_I4, lVal)
201}
202
203void 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
212SET_PROP_FUNC(Byte, VT_UI1, bVal)
213// SET_PROP_FUNC(Int16, VT_I2, iVal)
214// SET_PROP_FUNC(Int32, VT_I4, lVal)
215SET_PROP_FUNC(UInt32, VT_UI4, ulVal)
216SET_PROP_FUNC(UInt64, VT_UI8, uhVal.QuadPart)
217// SET_PROP_FUNC(Int64, VT_I8, hVal.QuadPart)
218SET_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
248CPropVariant::~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
259HRESULT 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
281HRESULT 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
291HRESULT 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
304HRESULT 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
316HRESULT 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
331HRESULT 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
347void 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
360int 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