Home | History | Annotate | Download | only in win
      1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/win/scoped_variant.h"
      6 #include "base/logging.h"
      7 
      8 namespace base {
      9 namespace win {
     10 
     11 // Global, const instance of an empty variant.
     12 const VARIANT ScopedVariant::kEmptyVariant = { VT_EMPTY };
     13 
     14 ScopedVariant::~ScopedVariant() {
     15   COMPILE_ASSERT(sizeof(ScopedVariant) == sizeof(VARIANT), ScopedVariantSize);
     16   ::VariantClear(&var_);
     17 }
     18 
     19 ScopedVariant::ScopedVariant(const wchar_t* str) {
     20   var_.vt = VT_EMPTY;
     21   Set(str);
     22 }
     23 
     24 ScopedVariant::ScopedVariant(const wchar_t* str, UINT length) {
     25   var_.vt = VT_BSTR;
     26   var_.bstrVal = ::SysAllocStringLen(str, length);
     27 }
     28 
     29 ScopedVariant::ScopedVariant(int value, VARTYPE vt) {
     30   var_.vt = vt;
     31   var_.lVal = value;
     32 }
     33 
     34 ScopedVariant::ScopedVariant(double value, VARTYPE vt) {
     35   DCHECK(vt == VT_R8 || vt == VT_DATE);
     36   var_.vt = vt;
     37   var_.dblVal = value;
     38 }
     39 
     40 ScopedVariant::ScopedVariant(IDispatch* dispatch) {
     41   var_.vt = VT_EMPTY;
     42   Set(dispatch);
     43 }
     44 
     45 ScopedVariant::ScopedVariant(IUnknown* unknown) {
     46   var_.vt = VT_EMPTY;
     47   Set(unknown);
     48 }
     49 
     50 ScopedVariant::ScopedVariant(SAFEARRAY* safearray) {
     51   var_.vt = VT_EMPTY;
     52   Set(safearray);
     53 }
     54 
     55 ScopedVariant::ScopedVariant(const VARIANT& var) {
     56   var_.vt = VT_EMPTY;
     57   Set(var);
     58 }
     59 
     60 void ScopedVariant::Reset(const VARIANT& var) {
     61   if (&var != &var_) {
     62     ::VariantClear(&var_);
     63     var_ = var;
     64   }
     65 }
     66 
     67 VARIANT ScopedVariant::Release() {
     68   VARIANT var = var_;
     69   var_.vt = VT_EMPTY;
     70   return var;
     71 }
     72 
     73 void ScopedVariant::Swap(ScopedVariant& var) {
     74   VARIANT tmp = var_;
     75   var_ = var.var_;
     76   var.var_ = tmp;
     77 }
     78 
     79 VARIANT* ScopedVariant::Receive() {
     80   DCHECK(!IsLeakableVarType(var_.vt)) << "variant leak. type: " << var_.vt;
     81   return &var_;
     82 }
     83 
     84 VARIANT ScopedVariant::Copy() const {
     85   VARIANT ret = { VT_EMPTY };
     86   ::VariantCopy(&ret, &var_);
     87   return ret;
     88 }
     89 
     90 int ScopedVariant::Compare(const VARIANT& var, bool ignore_case) const {
     91   ULONG flags = ignore_case ? NORM_IGNORECASE : 0;
     92   HRESULT hr = ::VarCmp(const_cast<VARIANT*>(&var_), const_cast<VARIANT*>(&var),
     93                         LOCALE_USER_DEFAULT, flags);
     94   int ret = 0;
     95 
     96   switch (hr) {
     97     case VARCMP_LT:
     98       ret = -1;
     99       break;
    100 
    101     case VARCMP_GT:
    102     case VARCMP_NULL:
    103       ret = 1;
    104       break;
    105 
    106     default:
    107       // Equal.
    108       break;
    109   }
    110 
    111   return ret;
    112 }
    113 
    114 void ScopedVariant::Set(const wchar_t* str) {
    115   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
    116   var_.vt = VT_BSTR;
    117   var_.bstrVal = ::SysAllocString(str);
    118 }
    119 
    120 void ScopedVariant::Set(int8 i8) {
    121   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
    122   var_.vt = VT_I1;
    123   var_.cVal = i8;
    124 }
    125 
    126 void ScopedVariant::Set(uint8 ui8) {
    127   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
    128   var_.vt = VT_UI1;
    129   var_.bVal = ui8;
    130 }
    131 
    132 void ScopedVariant::Set(int16 i16) {
    133   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
    134   var_.vt = VT_I2;
    135   var_.iVal = i16;
    136 }
    137 
    138 void ScopedVariant::Set(uint16 ui16) {
    139   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
    140   var_.vt = VT_UI2;
    141   var_.uiVal = ui16;
    142 }
    143 
    144 void ScopedVariant::Set(int32 i32) {
    145   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
    146   var_.vt = VT_I4;
    147   var_.lVal = i32;
    148 }
    149 
    150 void ScopedVariant::Set(uint32 ui32) {
    151   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
    152   var_.vt = VT_UI4;
    153   var_.ulVal = ui32;
    154 }
    155 
    156 void ScopedVariant::Set(int64 i64) {
    157   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
    158   var_.vt = VT_I8;
    159   var_.llVal = i64;
    160 }
    161 
    162 void ScopedVariant::Set(uint64 ui64) {
    163   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
    164   var_.vt = VT_UI8;
    165   var_.ullVal = ui64;
    166 }
    167 
    168 void ScopedVariant::Set(float r32) {
    169   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
    170   var_.vt = VT_R4;
    171   var_.fltVal = r32;
    172 }
    173 
    174 void ScopedVariant::Set(double r64) {
    175   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
    176   var_.vt = VT_R8;
    177   var_.dblVal = r64;
    178 }
    179 
    180 void ScopedVariant::SetDate(DATE date) {
    181   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
    182   var_.vt = VT_DATE;
    183   var_.date = date;
    184 }
    185 
    186 void ScopedVariant::Set(IDispatch* disp) {
    187   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
    188   var_.vt = VT_DISPATCH;
    189   var_.pdispVal = disp;
    190   if (disp)
    191     disp->AddRef();
    192 }
    193 
    194 void ScopedVariant::Set(bool b) {
    195   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
    196   var_.vt = VT_BOOL;
    197   var_.boolVal = b ? VARIANT_TRUE : VARIANT_FALSE;
    198 }
    199 
    200 void ScopedVariant::Set(IUnknown* unk) {
    201   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
    202   var_.vt = VT_UNKNOWN;
    203   var_.punkVal = unk;
    204   if (unk)
    205     unk->AddRef();
    206 }
    207 
    208 void ScopedVariant::Set(SAFEARRAY* array) {
    209   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
    210   if (SUCCEEDED(::SafeArrayGetVartype(array, &var_.vt))) {
    211     var_.vt |= VT_ARRAY;
    212     var_.parray = array;
    213   } else {
    214     DCHECK(!array) << "Unable to determine safearray vartype";
    215     var_.vt = VT_EMPTY;
    216   }
    217 }
    218 
    219 void ScopedVariant::Set(const VARIANT& var) {
    220   DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
    221   if (FAILED(::VariantCopy(&var_, &var))) {
    222     DLOG(ERROR) << "VariantCopy failed";
    223     var_.vt = VT_EMPTY;
    224   }
    225 }
    226 
    227 ScopedVariant& ScopedVariant::operator=(const VARIANT& var) {
    228   if (&var != &var_) {
    229     VariantClear(&var_);
    230     Set(var);
    231   }
    232   return *this;
    233 }
    234 
    235 bool ScopedVariant::IsLeakableVarType(VARTYPE vt) {
    236   bool leakable = false;
    237   switch (vt & VT_TYPEMASK) {
    238     case VT_BSTR:
    239     case VT_DISPATCH:
    240     // we treat VT_VARIANT as leakable to err on the safe side.
    241     case VT_VARIANT:
    242     case VT_UNKNOWN:
    243     case VT_SAFEARRAY:
    244 
    245     // very rarely used stuff (if ever):
    246     case VT_VOID:
    247     case VT_PTR:
    248     case VT_CARRAY:
    249     case VT_USERDEFINED:
    250     case VT_LPSTR:
    251     case VT_LPWSTR:
    252     case VT_RECORD:
    253     case VT_INT_PTR:
    254     case VT_UINT_PTR:
    255     case VT_FILETIME:
    256     case VT_BLOB:
    257     case VT_STREAM:
    258     case VT_STORAGE:
    259     case VT_STREAMED_OBJECT:
    260     case VT_STORED_OBJECT:
    261     case VT_BLOB_OBJECT:
    262     case VT_VERSIONED_STREAM:
    263     case VT_BSTR_BLOB:
    264       leakable = true;
    265       break;
    266   }
    267 
    268   if (!leakable && (vt & VT_ARRAY) != 0) {
    269     leakable = true;
    270   }
    271 
    272   return leakable;
    273 }
    274 
    275 }  // namespace win
    276 }  // namespace base
    277