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