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 8namespace base { 9namespace win { 10 11// Global, const instance of an empty variant. 12const VARIANT ScopedVariant::kEmptyVariant = { VT_EMPTY }; 13 14ScopedVariant::~ScopedVariant() { 15 COMPILE_ASSERT(sizeof(ScopedVariant) == sizeof(VARIANT), ScopedVariantSize); 16 ::VariantClear(&var_); 17} 18 19ScopedVariant::ScopedVariant(const wchar_t* str) { 20 var_.vt = VT_EMPTY; 21 Set(str); 22} 23 24ScopedVariant::ScopedVariant(const wchar_t* str, UINT length) { 25 var_.vt = VT_BSTR; 26 var_.bstrVal = ::SysAllocStringLen(str, length); 27} 28 29ScopedVariant::ScopedVariant(int value, VARTYPE vt) { 30 var_.vt = vt; 31 var_.lVal = value; 32} 33 34ScopedVariant::ScopedVariant(double value, VARTYPE vt) { 35 DCHECK(vt == VT_R8 || vt == VT_DATE); 36 var_.vt = vt; 37 var_.dblVal = value; 38} 39 40ScopedVariant::ScopedVariant(IDispatch* dispatch) { 41 var_.vt = VT_EMPTY; 42 Set(dispatch); 43} 44 45ScopedVariant::ScopedVariant(IUnknown* unknown) { 46 var_.vt = VT_EMPTY; 47 Set(unknown); 48} 49 50ScopedVariant::ScopedVariant(SAFEARRAY* safearray) { 51 var_.vt = VT_EMPTY; 52 Set(safearray); 53} 54 55ScopedVariant::ScopedVariant(const VARIANT& var) { 56 var_.vt = VT_EMPTY; 57 Set(var); 58} 59 60void ScopedVariant::Reset(const VARIANT& var) { 61 if (&var != &var_) { 62 ::VariantClear(&var_); 63 var_ = var; 64 } 65} 66 67VARIANT ScopedVariant::Release() { 68 VARIANT var = var_; 69 var_.vt = VT_EMPTY; 70 return var; 71} 72 73void ScopedVariant::Swap(ScopedVariant& var) { 74 VARIANT tmp = var_; 75 var_ = var.var_; 76 var.var_ = tmp; 77} 78 79VARIANT* ScopedVariant::Receive() { 80 DCHECK(!IsLeakableVarType(var_.vt)) << "variant leak. type: " << var_.vt; 81 return &var_; 82} 83 84VARIANT ScopedVariant::Copy() const { 85 VARIANT ret = { VT_EMPTY }; 86 ::VariantCopy(&ret, &var_); 87 return ret; 88} 89 90int 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 114void 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 120void ScopedVariant::Set(int8 i8) { 121 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; 122 var_.vt = VT_I1; 123 var_.cVal = i8; 124} 125 126void ScopedVariant::Set(uint8 ui8) { 127 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; 128 var_.vt = VT_UI1; 129 var_.bVal = ui8; 130} 131 132void ScopedVariant::Set(int16 i16) { 133 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; 134 var_.vt = VT_I2; 135 var_.iVal = i16; 136} 137 138void ScopedVariant::Set(uint16 ui16) { 139 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; 140 var_.vt = VT_UI2; 141 var_.uiVal = ui16; 142} 143 144void ScopedVariant::Set(int32 i32) { 145 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; 146 var_.vt = VT_I4; 147 var_.lVal = i32; 148} 149 150void ScopedVariant::Set(uint32 ui32) { 151 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; 152 var_.vt = VT_UI4; 153 var_.ulVal = ui32; 154} 155 156void ScopedVariant::Set(int64 i64) { 157 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; 158 var_.vt = VT_I8; 159 var_.llVal = i64; 160} 161 162void ScopedVariant::Set(uint64 ui64) { 163 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; 164 var_.vt = VT_UI8; 165 var_.ullVal = ui64; 166} 167 168void ScopedVariant::Set(float r32) { 169 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; 170 var_.vt = VT_R4; 171 var_.fltVal = r32; 172} 173 174void ScopedVariant::Set(double r64) { 175 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; 176 var_.vt = VT_R8; 177 var_.dblVal = r64; 178} 179 180void ScopedVariant::SetDate(DATE date) { 181 DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; 182 var_.vt = VT_DATE; 183 var_.date = date; 184} 185 186void 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 194void 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 200void 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 208void 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 219void 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 227ScopedVariant& ScopedVariant::operator=(const VARIANT& var) { 228 if (&var != &var_) { 229 VariantClear(&var_); 230 Set(var); 231 } 232 return *this; 233} 234 235bool 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