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
12HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw()
13{
14  p->bstrVal = ::SysAllocStringLen(0, numChars);
15  if (!p->bstrVal)
16  {
17    p->vt = VT_ERROR;
18    p->scode = E_OUTOFMEMORY;
19    return E_OUTOFMEMORY;
20  }
21  p->vt = VT_BSTR;
22  return S_OK;
23}
24
25HRESULT PropVarEm_Set_Str(PROPVARIANT *p, const char *s) throw()
26{
27  UINT len = (UINT)strlen(s);
28  p->bstrVal = ::SysAllocStringLen(0, len);
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  BSTR dest = p->bstrVal;
37  for (UINT i = 0; i <= len; i++)
38    dest[i] = s[i];
39  return S_OK;
40}
41
42CPropVariant::CPropVariant(const PROPVARIANT &varSrc)
43{
44  vt = VT_EMPTY;
45  InternalCopy(&varSrc);
46}
47
48CPropVariant::CPropVariant(const CPropVariant &varSrc)
49{
50  vt = VT_EMPTY;
51  InternalCopy(&varSrc);
52}
53
54CPropVariant::CPropVariant(BSTR bstrSrc)
55{
56  vt = VT_EMPTY;
57  *this = bstrSrc;
58}
59
60CPropVariant::CPropVariant(LPCOLESTR lpszSrc)
61{
62  vt = VT_EMPTY;
63  *this = lpszSrc;
64}
65
66CPropVariant& CPropVariant::operator=(const CPropVariant &varSrc)
67{
68  InternalCopy(&varSrc);
69  return *this;
70}
71CPropVariant& CPropVariant::operator=(const PROPVARIANT &varSrc)
72{
73  InternalCopy(&varSrc);
74  return *this;
75}
76
77CPropVariant& CPropVariant::operator=(BSTR bstrSrc)
78{
79  *this = (LPCOLESTR)bstrSrc;
80  return *this;
81}
82
83static const char *kMemException = "out of memory";
84
85CPropVariant& CPropVariant::operator=(LPCOLESTR lpszSrc)
86{
87  InternalClear();
88  vt = VT_BSTR;
89  wReserved1 = 0;
90  bstrVal = ::SysAllocString(lpszSrc);
91  if (!bstrVal && lpszSrc)
92  {
93    throw kMemException;
94    // vt = VT_ERROR;
95    // scode = E_OUTOFMEMORY;
96  }
97  return *this;
98}
99
100CPropVariant& CPropVariant::operator=(const char *s)
101{
102  InternalClear();
103  vt = VT_BSTR;
104  wReserved1 = 0;
105  UINT len = (UINT)strlen(s);
106  bstrVal = ::SysAllocStringLen(0, len);
107  if (!bstrVal)
108  {
109    throw kMemException;
110    // vt = VT_ERROR;
111    // scode = E_OUTOFMEMORY;
112  }
113  else
114  {
115    for (UINT i = 0; i <= len; i++)
116      bstrVal[i] = s[i];
117  }
118  return *this;
119}
120
121CPropVariant& CPropVariant::operator=(bool bSrc) throw()
122{
123  if (vt != VT_BOOL)
124  {
125    InternalClear();
126    vt = VT_BOOL;
127  }
128  boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE;
129  return *this;
130}
131
132BSTR CPropVariant::AllocBstr(unsigned numChars)
133{
134  if (vt != VT_EMPTY)
135    InternalClear();
136  vt = VT_BSTR;
137  wReserved1 = 0;
138  bstrVal = ::SysAllocStringLen(0, numChars);
139  if (!bstrVal)
140  {
141    throw kMemException;
142    // vt = VT_ERROR;
143    // scode = E_OUTOFMEMORY;
144  }
145  return bstrVal;
146}
147
148#define SET_PROP_FUNC(type, id, dest) \
149  CPropVariant& CPropVariant::operator=(type value) throw() \
150  { if (vt != id) { InternalClear(); vt = id; } \
151    dest = value; return *this; }
152
153SET_PROP_FUNC(Byte, VT_UI1, bVal)
154// SET_PROP_FUNC(Int16, VT_I2, iVal)
155SET_PROP_FUNC(Int32, VT_I4, lVal)
156SET_PROP_FUNC(UInt32, VT_UI4, ulVal)
157SET_PROP_FUNC(UInt64, VT_UI8, uhVal.QuadPart)
158SET_PROP_FUNC(Int64, VT_I8, hVal.QuadPart)
159SET_PROP_FUNC(const FILETIME &, VT_FILETIME, filetime)
160
161HRESULT PropVariant_Clear(PROPVARIANT *prop) throw()
162{
163  switch (prop->vt)
164  {
165    case VT_EMPTY:
166    case VT_UI1:
167    case VT_I1:
168    case VT_I2:
169    case VT_UI2:
170    case VT_BOOL:
171    case VT_I4:
172    case VT_UI4:
173    case VT_R4:
174    case VT_INT:
175    case VT_UINT:
176    case VT_ERROR:
177    case VT_FILETIME:
178    case VT_UI8:
179    case VT_R8:
180    case VT_CY:
181    case VT_DATE:
182      prop->vt = VT_EMPTY;
183      prop->wReserved1 = 0;
184      prop->wReserved2 = 0;
185      prop->wReserved3 = 0;
186      prop->uhVal.QuadPart = 0;
187      return S_OK;
188  }
189  return ::VariantClear((VARIANTARG *)prop);
190  // return ::PropVariantClear(prop);
191  // PropVariantClear can clear VT_BLOB.
192}
193
194HRESULT CPropVariant::Clear() throw()
195{
196  if (vt == VT_EMPTY)
197    return S_OK;
198  return PropVariant_Clear(this);
199}
200
201HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw()
202{
203  ::VariantClear((tagVARIANT *)this);
204  switch(pSrc->vt)
205  {
206    case VT_UI1:
207    case VT_I1:
208    case VT_I2:
209    case VT_UI2:
210    case VT_BOOL:
211    case VT_I4:
212    case VT_UI4:
213    case VT_R4:
214    case VT_INT:
215    case VT_UINT:
216    case VT_ERROR:
217    case VT_FILETIME:
218    case VT_UI8:
219    case VT_R8:
220    case VT_CY:
221    case VT_DATE:
222      memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT));
223      return S_OK;
224  }
225  return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)const_cast<PROPVARIANT *>(pSrc));
226}
227
228
229HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw()
230{
231  HRESULT hr = Clear();
232  if (FAILED(hr))
233    return hr;
234  memcpy(this, pSrc, sizeof(PROPVARIANT));
235  pSrc->vt = VT_EMPTY;
236  return S_OK;
237}
238
239HRESULT CPropVariant::Detach(PROPVARIANT *pDest) throw()
240{
241  if (pDest->vt != VT_EMPTY)
242  {
243    HRESULT hr = PropVariant_Clear(pDest);
244    if (FAILED(hr))
245      return hr;
246  }
247  memcpy(pDest, this, sizeof(PROPVARIANT));
248  vt = VT_EMPTY;
249  return S_OK;
250}
251
252HRESULT CPropVariant::InternalClear() throw()
253{
254  if (vt == VT_EMPTY)
255    return S_OK;
256  HRESULT hr = Clear();
257  if (FAILED(hr))
258  {
259    vt = VT_ERROR;
260    scode = hr;
261  }
262  return hr;
263}
264
265void CPropVariant::InternalCopy(const PROPVARIANT *pSrc)
266{
267  HRESULT hr = Copy(pSrc);
268  if (FAILED(hr))
269  {
270    if (hr == E_OUTOFMEMORY)
271      throw kMemException;
272    vt = VT_ERROR;
273    scode = hr;
274  }
275}
276
277int CPropVariant::Compare(const CPropVariant &a) throw()
278{
279  if (vt != a.vt)
280    return MyCompare(vt, a.vt);
281  switch (vt)
282  {
283    case VT_EMPTY: return 0;
284    // case VT_I1: return MyCompare(cVal, a.cVal);
285    case VT_UI1: return MyCompare(bVal, a.bVal);
286    case VT_I2: return MyCompare(iVal, a.iVal);
287    case VT_UI2: return MyCompare(uiVal, a.uiVal);
288    case VT_I4: return MyCompare(lVal, a.lVal);
289    case VT_UI4: return MyCompare(ulVal, a.ulVal);
290    // case VT_UINT: return MyCompare(uintVal, a.uintVal);
291    case VT_I8: return MyCompare(hVal.QuadPart, a.hVal.QuadPart);
292    case VT_UI8: return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart);
293    case VT_BOOL: return -MyCompare(boolVal, a.boolVal);
294    case VT_FILETIME: return ::CompareFileTime(&filetime, &a.filetime);
295    case VT_BSTR: return 0; // Not implemented
296    default: return 0;
297  }
298}
299
300}}
301