Home | History | Annotate | Download | only in Windows
      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 
     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 
     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 
     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 
     52 CPropVariant::CPropVariant(const PROPVARIANT &varSrc)
     53 {
     54   vt = VT_EMPTY;
     55   InternalCopy(&varSrc);
     56 }
     57 
     58 CPropVariant::CPropVariant(const CPropVariant &varSrc)
     59 {
     60   vt = VT_EMPTY;
     61   InternalCopy(&varSrc);
     62 }
     63 
     64 CPropVariant::CPropVariant(BSTR bstrSrc)
     65 {
     66   vt = VT_EMPTY;
     67   *this = bstrSrc;
     68 }
     69 
     70 CPropVariant::CPropVariant(LPCOLESTR lpszSrc)
     71 {
     72   vt = VT_EMPTY;
     73   *this = lpszSrc;
     74 }
     75 
     76 CPropVariant& CPropVariant::operator=(const CPropVariant &varSrc)
     77 {
     78   InternalCopy(&varSrc);
     79   return *this;
     80 }
     81 
     82 CPropVariant& CPropVariant::operator=(const PROPVARIANT &varSrc)
     83 {
     84   InternalCopy(&varSrc);
     85   return *this;
     86 }
     87 
     88 CPropVariant& CPropVariant::operator=(BSTR bstrSrc)
     89 {
     90   *this = (LPCOLESTR)bstrSrc;
     91   return *this;
     92 }
     93 
     94 static const char *kMemException = "out of memory";
     95 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    241 HRESULT CPropVariant::Clear() throw()
    242 {
    243   if (vt == VT_EMPTY)
    244     return S_OK;
    245   return PropVariant_Clear(this);
    246 }
    247 
    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 
    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 
    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 
    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 
    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 
    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