diff options
author | tommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-19 04:22:28 +0000 |
---|---|---|
committer | tommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-19 04:22:28 +0000 |
commit | e00d39192ccc3713059caef9bdb7cf74d902f7df (patch) | |
tree | 946a5d20463ca2614f4e3d778e31940f32ce609f /base/scoped_variant_win.cc | |
parent | 6c56c9962a3eae73f46297c7c220264d23a5004d (diff) | |
download | chromium_src-e00d39192ccc3713059caef9bdb7cf74d902f7df.zip chromium_src-e00d39192ccc3713059caef9bdb7cf74d902f7df.tar.gz chromium_src-e00d39192ccc3713059caef9bdb7cf74d902f7df.tar.bz2 |
ScopedVariant implementation.
A class for automatically freeing a COM VARIANT at the
end of a scope. Additionally provides a few functions to
make the encapsulated VARIANT easier to use.
Instead of inheriting from VARIANT, I took the containment
approach in order to have more control over the usage of the
variant and guard against memory leaks.
Review URL: http://codereview.chromium.org/46059
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12081 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/scoped_variant_win.cc')
-rw-r--r-- | base/scoped_variant_win.cc | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/base/scoped_variant_win.cc b/base/scoped_variant_win.cc new file mode 100644 index 0000000..cc66c12 --- /dev/null +++ b/base/scoped_variant_win.cc @@ -0,0 +1,230 @@ +// Copyright (c) 2009 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/scoped_variant_win.h" +#include "base/logging.h" + +// Global, const instance of an empty variant. +const VARIANT ScopedVariant::kEmptyVariant = { VT_EMPTY }; + +ScopedVariant::~ScopedVariant() { + COMPILE_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; +} + +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 i8) { + DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; + var_.vt = VT_I1; + var_.cVal = i8; +} + +void ScopedVariant::Set(uint8 ui8) { + DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; + var_.vt = VT_UI1; + var_.bVal = ui8; +} + +void ScopedVariant::Set(int16 i16) { + DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; + var_.vt = VT_I2; + var_.iVal = i16; +} + +void ScopedVariant::Set(uint16 ui16) { + DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; + var_.vt = VT_UI2; + var_.uiVal = ui16; +} + +void ScopedVariant::Set(int32 i32) { + DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; + var_.vt = VT_I4; + var_.lVal = i32; +} + +void ScopedVariant::Set(uint32 ui32) { + DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; + var_.vt = VT_UI4; + var_.ulVal = ui32; +} + +void ScopedVariant::Set(int64 i64) { + DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt; + var_.vt = VT_I8; + var_.llVal = i64; +} + +void ScopedVariant::Set(uint64 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 == NULL) << "Unable to determine safearray vartype"; + var_.vt = VT_EMPTY; + } +} + +#ifndef OFFICIAL_BUILD +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; +} +#endif |