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