| // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/win/scoped_variant.h" |
| |
| #include "base/logging.h" |
| |
| namespace base { |
| namespace win { |
| |
| // Global, const instance of an empty variant. |
| const VARIANT ScopedVariant::kEmptyVariant = {{{VT_EMPTY}}}; |
| |
| ScopedVariant::~ScopedVariant() { |
| static_assert(sizeof(ScopedVariant) == sizeof(VARIANT), "ScopedVariantSize"); |
| ::VariantClear(&var_); |
| } |
| |
| ScopedVariant::ScopedVariant(const wchar_t* str) { |
| var_.vt = VT_EMPTY; |
| Set(str); |
| } |
| |
| ScopedVariant::ScopedVariant(const wchar_t* str, UINT length) { |
| var_.vt = VT_BSTR; |
| var_.bstrVal = ::SysAllocStringLen(str, length); |
| } |
| |
| ScopedVariant::ScopedVariant(int value, VARTYPE vt) { |
| var_.vt = vt; |
| var_.lVal = value; |
| } |
| |
| ScopedVariant::ScopedVariant(double value, VARTYPE vt) { |
| DCHECK(vt == VT_R8 || vt == VT_DATE); |
| var_.vt = vt; |
| var_.dblVal = value; |
| } |
| |
| ScopedVariant::ScopedVariant(IDispatch* dispatch) { |
| var_.vt = VT_EMPTY; |
| Set(dispatch); |
| } |
| |
| ScopedVariant::ScopedVariant(IUnknown* unknown) { |
| var_.vt = VT_EMPTY; |
| Set(unknown); |
| } |
| |
| ScopedVariant::ScopedVariant(SAFEARRAY* safearray) { |
| var_.vt = VT_EMPTY; |
| Set(safearray); |
| } |
| |
| ScopedVariant::ScopedVariant(const VARIANT& var) { |
| var_.vt = VT_EMPTY; |
| Set(var); |
| } |
| |
| void ScopedVariant::Reset(const VARIANT& var) { |
| if (&var != &var_) { |
| ::VariantClear(&var_); |
| var_ = var; |
| } |
| } |
| |
| VARIANT ScopedVariant::Release() { |
| VARIANT var = var_; |
| var_.vt = VT_EMPTY; |
| return var; |
| } |
| |
| void ScopedVariant::Swap(ScopedVariant& var) { |
| VARIANT tmp = var_; |
| var_ = var.var_; |
| var.var_ = tmp; |
| } |
| |
| VARIANT* ScopedVariant::Receive() { |
| DCHECK(!IsLeakableVarType(var_.vt)) << "variant leak. type: " << var_.vt; |
| return &var_; |
| } |
| |
| VARIANT ScopedVariant::Copy() const { |
| VARIANT ret = {{{VT_EMPTY}}}; |
| ::VariantCopy(&ret, &var_); |
| return ret; |
| } |
| |
| int ScopedVariant::Compare(const VARIANT& var, bool ignore_case) const { |
| ULONG flags = ignore_case ? NORM_IGNORECASE : 0; |
| HRESULT hr = ::VarCmp(const_cast<VARIANT*>(&var_), const_cast<VARIANT*>(&var), |
| LOCALE_USER_DEFAULT, flags); |
| int ret = 0; |
| |
| switch (hr) { |
| case VARCMP_LT: |
| ret = -1; |
| break; |
| |
| case VARCMP_GT: |
| case VARCMP_NULL: |
| ret = 1; |
| break; |
| |
| default: |
| // Equal. |
| break; |
| } |
| |
| return ret; |
| } |
| |
| void ScopedVariant::Set(const wchar_t* str) { |
| DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; |
| var_.vt = VT_BSTR; |
| var_.bstrVal = ::SysAllocString(str); |
| } |
| |
| void ScopedVariant::Set(int8_t i8) { |
| DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; |
| var_.vt = VT_I1; |
| var_.cVal = i8; |
| } |
| |
| void ScopedVariant::Set(uint8_t ui8) { |
| DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; |
| var_.vt = VT_UI1; |
| var_.bVal = ui8; |
| } |
| |
| void ScopedVariant::Set(int16_t i16) { |
| DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; |
| var_.vt = VT_I2; |
| var_.iVal = i16; |
| } |
| |
| void ScopedVariant::Set(uint16_t ui16) { |
| DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; |
| var_.vt = VT_UI2; |
| var_.uiVal = ui16; |
| } |
| |
| void ScopedVariant::Set(int32_t i32) { |
| DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; |
| var_.vt = VT_I4; |
| var_.lVal = i32; |
| } |
| |
| void ScopedVariant::Set(uint32_t ui32) { |
| DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; |
| var_.vt = VT_UI4; |
| var_.ulVal = ui32; |
| } |
| |
| void ScopedVariant::Set(int64_t i64) { |
| DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; |
| var_.vt = VT_I8; |
| var_.llVal = i64; |
| } |
| |
| void ScopedVariant::Set(uint64_t ui64) { |
| DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; |
| var_.vt = VT_UI8; |
| var_.ullVal = ui64; |
| } |
| |
| void ScopedVariant::Set(float r32) { |
| DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; |
| var_.vt = VT_R4; |
| var_.fltVal = r32; |
| } |
| |
| void ScopedVariant::Set(double r64) { |
| DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; |
| var_.vt = VT_R8; |
| var_.dblVal = r64; |
| } |
| |
| void ScopedVariant::SetDate(DATE date) { |
| DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; |
| var_.vt = VT_DATE; |
| var_.date = date; |
| } |
| |
| void ScopedVariant::Set(IDispatch* disp) { |
| DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; |
| var_.vt = VT_DISPATCH; |
| var_.pdispVal = disp; |
| if (disp) |
| disp->AddRef(); |
| } |
| |
| void ScopedVariant::Set(bool b) { |
| DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; |
| var_.vt = VT_BOOL; |
| var_.boolVal = b ? VARIANT_TRUE : VARIANT_FALSE; |
| } |
| |
| void ScopedVariant::Set(IUnknown* unk) { |
| DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; |
| var_.vt = VT_UNKNOWN; |
| var_.punkVal = unk; |
| if (unk) |
| unk->AddRef(); |
| } |
| |
| void ScopedVariant::Set(SAFEARRAY* array) { |
| DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; |
| if (SUCCEEDED(::SafeArrayGetVartype(array, &var_.vt))) { |
| var_.vt |= VT_ARRAY; |
| var_.parray = array; |
| } else { |
| DCHECK(!array) << "Unable to determine safearray vartype"; |
| var_.vt = VT_EMPTY; |
| } |
| } |
| |
| void ScopedVariant::Set(const VARIANT& var) { |
| DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; |
| if (FAILED(::VariantCopy(&var_, &var))) { |
| DLOG(ERROR) << "VariantCopy failed"; |
| var_.vt = VT_EMPTY; |
| } |
| } |
| |
| ScopedVariant& ScopedVariant::operator=(const VARIANT& var) { |
| if (&var != &var_) { |
| VariantClear(&var_); |
| Set(var); |
| } |
| return *this; |
| } |
| |
| bool ScopedVariant::IsLeakableVarType(VARTYPE vt) { |
| bool leakable = false; |
| switch (vt & VT_TYPEMASK) { |
| case VT_BSTR: |
| case VT_DISPATCH: |
| // we treat VT_VARIANT as leakable to err on the safe side. |
| case VT_VARIANT: |
| case VT_UNKNOWN: |
| case VT_SAFEARRAY: |
| |
| // very rarely used stuff (if ever): |
| case VT_VOID: |
| case VT_PTR: |
| case VT_CARRAY: |
| case VT_USERDEFINED: |
| case VT_LPSTR: |
| case VT_LPWSTR: |
| case VT_RECORD: |
| case VT_INT_PTR: |
| case VT_UINT_PTR: |
| case VT_FILETIME: |
| case VT_BLOB: |
| case VT_STREAM: |
| case VT_STORAGE: |
| case VT_STREAMED_OBJECT: |
| case VT_STORED_OBJECT: |
| case VT_BLOB_OBJECT: |
| case VT_VERSIONED_STREAM: |
| case VT_BSTR_BLOB: |
| leakable = true; |
| break; |
| } |
| |
| if (!leakable && (vt & VT_ARRAY) != 0) { |
| leakable = true; |
| } |
| |
| return leakable; |
| } |
| |
| } // namespace win |
| } // namespace base |