summaryrefslogtreecommitdiffstats
path: root/base/scoped_variant_win.cc
diff options
context:
space:
mode:
authortommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-19 04:22:28 +0000
committertommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-19 04:22:28 +0000
commite00d39192ccc3713059caef9bdb7cf74d902f7df (patch)
tree946a5d20463ca2614f4e3d778e31940f32ce609f /base/scoped_variant_win.cc
parent6c56c9962a3eae73f46297c7c220264d23a5004d (diff)
downloadchromium_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.cc230
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