summaryrefslogtreecommitdiffstats
path: root/base/win
diff options
context:
space:
mode:
authorbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-16 03:46:05 +0000
committerbrettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-16 03:46:05 +0000
commitce0e7246e92f2da8e6b865dd51ae626f9867ca4f (patch)
tree8181f26fbe349c35ff37a9ae837603c3f11be7f8 /base/win
parent21e74460f5b7cfe6f622557b20d40eecf3b8e98b (diff)
downloadchromium_src-ce0e7246e92f2da8e6b865dd51ae626f9867ca4f.zip
chromium_src-ce0e7246e92f2da8e6b865dd51ae626f9867ca4f.tar.gz
chromium_src-ce0e7246e92f2da8e6b865dd51ae626f9867ca4f.tar.bz2
Move the windows-specific scoped_* stuff from base to base/win and in the base::win namespace.
This keeps old headers that forward to the new versions and have using declarations that allow the existing code to compile. I fixed all the callers in base to use the new ones, and also the other files I happened to touch. This splits out the stuff from scoped_handle into a few separate files. I just deleted ScopedFindFile since it was only used in one place and it wasn't even really helping there. I removed StackBstr which was a #define and used the "regular" ScopedBstr in the 7 places that used it. This is an optimization to avoid an extra allocation, but none of the callers are remotely performance critical. TEST=it compiles BUG=none Review URL: http://codereview.chromium.org/3781009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@62843 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/win')
-rw-r--r--base/win/scoped_bstr.cc71
-rw-r--r--base/win/scoped_bstr.h97
-rw-r--r--base/win/scoped_bstr_unittest.cc77
-rw-r--r--base/win/scoped_comptr.h165
-rw-r--r--base/win/scoped_comptr_unittest.cc113
-rw-r--r--base/win/scoped_gdi_object.h78
-rw-r--r--base/win/scoped_handle.h90
-rw-r--r--base/win/scoped_hdc.h55
-rw-r--r--base/win/scoped_hglobal.h53
-rw-r--r--base/win/scoped_variant.cc276
-rw-r--r--base/win/scoped_variant.h166
-rw-r--r--base/win/scoped_variant_unittest.cc263
12 files changed, 1504 insertions, 0 deletions
diff --git a/base/win/scoped_bstr.cc b/base/win/scoped_bstr.cc
new file mode 100644
index 0000000..18ffe6a
--- /dev/null
+++ b/base/win/scoped_bstr.cc
@@ -0,0 +1,71 @@
+// 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_bstr.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+ScopedBstr::ScopedBstr(const char16* non_bstr)
+ : bstr_(SysAllocString(non_bstr)) {
+}
+
+ScopedBstr::~ScopedBstr() {
+ COMPILE_ASSERT(sizeof(ScopedBstr) == sizeof(BSTR), ScopedBstrSize);
+ SysFreeString(bstr_);
+}
+
+void ScopedBstr::Reset(BSTR bstr) {
+ if (bstr != bstr_) {
+ // if |bstr_| is NULL, SysFreeString does nothing.
+ SysFreeString(bstr_);
+ bstr_ = bstr;
+ }
+}
+
+BSTR ScopedBstr::Release() {
+ BSTR bstr = bstr_;
+ bstr_ = NULL;
+ return bstr;
+}
+
+void ScopedBstr::Swap(ScopedBstr& bstr2) {
+ BSTR tmp = bstr_;
+ bstr_ = bstr2.bstr_;
+ bstr2.bstr_ = tmp;
+}
+
+BSTR* ScopedBstr::Receive() {
+ DCHECK(bstr_ == NULL) << "BSTR leak.";
+ return &bstr_;
+}
+
+BSTR ScopedBstr::Allocate(const char16* str) {
+ Reset(SysAllocString(str));
+ return bstr_;
+}
+
+BSTR ScopedBstr::AllocateBytes(size_t bytes) {
+ Reset(SysAllocStringByteLen(NULL, static_cast<UINT>(bytes)));
+ return bstr_;
+}
+
+void ScopedBstr::SetByteLen(size_t bytes) {
+ DCHECK(bstr_ != NULL) << "attempting to modify a NULL bstr";
+ uint32* data = reinterpret_cast<uint32*>(bstr_);
+ data[-1] = static_cast<uint32>(bytes);
+}
+
+size_t ScopedBstr::Length() const {
+ return SysStringLen(bstr_);
+}
+
+size_t ScopedBstr::ByteLength() const {
+ return SysStringByteLen(bstr_);
+}
+
+} // namespace win
+} // namespace base
diff --git a/base/win/scoped_bstr.h b/base/win/scoped_bstr.h
new file mode 100644
index 0000000..944562e
--- /dev/null
+++ b/base/win/scoped_bstr.h
@@ -0,0 +1,97 @@
+// 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.
+
+#ifndef BASE_WIN_SCOPED_BSTR_H_
+#define BASE_WIN_SCOPED_BSTR_H_
+#pragma once
+
+#include <windows.h>
+#include <oleauto.h>
+
+#include "base/logging.h"
+#include "base/string16.h"
+
+namespace base {
+namespace win {
+
+// Manages a BSTR string pointer.
+// The class interface is based on scoped_ptr.
+class ScopedBstr {
+ public:
+ ScopedBstr() : bstr_(NULL) {
+ }
+
+ // Constructor to create a new BSTR.
+ //
+ // NOTE: Do not pass a BSTR to this constructor expecting ownership to
+ // be transferred - even though it compiles! ;-)
+ explicit ScopedBstr(const char16* non_bstr);
+ ~ScopedBstr();
+
+ // Give ScopedBstr ownership over an already allocated BSTR or NULL.
+ // If you need to allocate a new BSTR instance, use |allocate| instead.
+ void Reset(BSTR bstr = NULL);
+
+ // Releases ownership of the BSTR to the caller.
+ BSTR Release();
+
+ // Creates a new BSTR from a 16-bit C-style string.
+ //
+ // If you already have a BSTR and want to transfer ownership to the
+ // ScopedBstr instance, call |reset| instead.
+ //
+ // Returns a pointer to the new BSTR, or NULL if allocation failed.
+ BSTR Allocate(const char16* str);
+
+ // Allocates a new BSTR with the specified number of bytes.
+ // Returns a pointer to the new BSTR, or NULL if allocation failed.
+ BSTR AllocateBytes(size_t bytes);
+
+ // Sets the allocated length field of the already-allocated BSTR to be
+ // |bytes|. This is useful when the BSTR was preallocated with e.g.
+ // SysAllocStringLen or SysAllocStringByteLen (call |AllocateBytes|) and then
+ // not all the bytes are being used.
+ //
+ // Note that if you want to set the length to a specific number of
+ // characters, you need to multiply by sizeof(wchar_t). Oddly, there's no
+ // public API to set the length, so we do this ourselves by hand.
+ //
+ // NOTE: The actual allocated size of the BSTR MUST be >= bytes. That
+ // responsibility is with the caller.
+ void SetByteLen(size_t bytes);
+
+ // Swap values of two ScopedBstr's.
+ void Swap(ScopedBstr& bstr2);
+
+ // Retrieves the pointer address.
+ // Used to receive BSTRs as out arguments (and take ownership).
+ // The function DCHECKs on the current value being NULL.
+ // Usage: GetBstr(bstr.Receive());
+ BSTR* Receive();
+
+ // Returns number of chars in the BSTR.
+ size_t Length() const;
+
+ // Returns the number of bytes allocated for the BSTR.
+ size_t ByteLength() const;
+
+ operator BSTR() const {
+ return bstr_;
+ }
+
+ protected:
+ BSTR bstr_;
+
+ private:
+ // Forbid comparison of ScopedBstr types. You should never have the same
+ // BSTR owned by two different scoped_ptrs.
+ bool operator==(const ScopedBstr& bstr2) const;
+ bool operator!=(const ScopedBstr& bstr2) const;
+ DISALLOW_COPY_AND_ASSIGN(ScopedBstr);
+};
+
+} // namespace win
+} // namespace base
+
+#endif // BASE_SCOPED_BSTR_H_
diff --git a/base/win/scoped_bstr_unittest.cc b/base/win/scoped_bstr_unittest.cc
new file mode 100644
index 0000000..5f6f7df
--- /dev/null
+++ b/base/win/scoped_bstr_unittest.cc
@@ -0,0 +1,77 @@
+// 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_bstr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+static const wchar_t kTestString1[] = L"123";
+static const wchar_t kTestString2[] = L"456789";
+size_t test1_len = arraysize(kTestString1) - 1;
+size_t test2_len = arraysize(kTestString2) - 1;
+
+void DumbBstrTests() {
+ ScopedBstr b;
+ EXPECT_TRUE(b == NULL);
+ EXPECT_EQ(0, b.Length());
+ EXPECT_EQ(0, b.ByteLength());
+ b.Reset(NULL);
+ EXPECT_TRUE(b == NULL);
+ EXPECT_TRUE(b.Release() == NULL);
+ ScopedBstr b2;
+ b.Swap(b2);
+ EXPECT_TRUE(b2 == NULL);
+}
+
+void GiveMeABstr(BSTR* ret) {
+ *ret = SysAllocString(kTestString1);
+}
+
+void BasicBstrTests() {
+ ScopedBstr b1(kTestString1);
+ EXPECT_EQ(test1_len, b1.Length());
+ EXPECT_EQ(test1_len * sizeof(kTestString1[0]), b1.ByteLength());
+
+ ScopedBstr b2;
+ b1.Swap(b2);
+ EXPECT_EQ(test1_len, b2.Length());
+ EXPECT_EQ(0, b1.Length());
+ EXPECT_EQ(0, lstrcmp(b2, kTestString1));
+ BSTR tmp = b2.Release();
+ EXPECT_TRUE(tmp != NULL);
+ EXPECT_EQ(0, lstrcmp(tmp, kTestString1));
+ EXPECT_TRUE(b2 == NULL);
+ SysFreeString(tmp);
+
+ GiveMeABstr(b2.Receive());
+ EXPECT_TRUE(b2 != NULL);
+ b2.Reset();
+ EXPECT_TRUE(b2.AllocateBytes(100) != NULL);
+ EXPECT_EQ(100, b2.ByteLength());
+ EXPECT_EQ(100 / sizeof(kTestString1[0]), b2.Length());
+ lstrcpy(static_cast<BSTR>(b2), kTestString1);
+ EXPECT_EQ(test1_len, lstrlen(b2));
+ EXPECT_EQ(100 / sizeof(kTestString1[0]), b2.Length());
+ b2.SetByteLen(lstrlen(b2) * sizeof(kTestString2[0]));
+ EXPECT_EQ(b2.Length(), lstrlen(b2));
+
+ EXPECT_TRUE(b1.Allocate(kTestString2) != NULL);
+ EXPECT_EQ(test2_len, b1.Length());
+ b1.SetByteLen((test2_len - 1) * sizeof(kTestString2[0]));
+ EXPECT_EQ(test2_len - 1, b1.Length());
+}
+
+} // namespace
+
+TEST(ScopedBstrTest, ScopedBstr) {
+ DumbBstrTests();
+ BasicBstrTests();
+}
+
+} // namespace win
+} // namespace base
diff --git a/base/win/scoped_comptr.h b/base/win/scoped_comptr.h
new file mode 100644
index 0000000..385c79f
--- /dev/null
+++ b/base/win/scoped_comptr.h
@@ -0,0 +1,165 @@
+// Copyright (c) 2006-2008 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.
+
+#ifndef BASE_WIN_SCOPED_COMPTR_H_
+#define BASE_WIN_SCOPED_COMPTR_H_
+#pragma once
+
+#include <unknwn.h>
+
+#include "base/logging.h"
+#include "base/ref_counted.h"
+
+namespace base {
+namespace win {
+
+// A fairly minimalistic smart class for COM interface pointers.
+// Uses scoped_refptr for the basic smart pointer functionality
+// and adds a few IUnknown specific services.
+template <class Interface, const IID* interface_id = &__uuidof(Interface)>
+class ScopedComPtr : public scoped_refptr<Interface> {
+ public:
+ // Utility template to prevent users of ScopedComPtr from calling AddRef
+ // and/or Release() without going through the ScopedComPtr class.
+ template <class Interface>
+ class BlockIUnknownMethods : public Interface {
+ private:
+ STDMETHOD(QueryInterface)(REFIID iid, void** object) = 0;
+ STDMETHOD_(ULONG, AddRef)() = 0;
+ STDMETHOD_(ULONG, Release)() = 0;
+ };
+
+ typedef scoped_refptr<Interface> ParentClass;
+
+ ScopedComPtr() {
+ }
+
+ explicit ScopedComPtr(Interface* p) : ParentClass(p) {
+ }
+
+ ScopedComPtr(const ScopedComPtr<Interface, interface_id>& p)
+ : ParentClass(p) {
+ }
+
+ ~ScopedComPtr() {
+ // We don't want the smart pointer class to be bigger than the pointer
+ // it wraps.
+ COMPILE_ASSERT(sizeof(ScopedComPtr<Interface, interface_id>) ==
+ sizeof(Interface*), ScopedComPtrSize);
+ }
+
+ // Explicit Release() of the held object. Useful for reuse of the
+ // ScopedComPtr instance.
+ // Note that this function equates to IUnknown::Release and should not
+ // be confused with e.g. scoped_ptr::release().
+ void Release() {
+ if (ptr_ != NULL) {
+ ptr_->Release();
+ ptr_ = NULL;
+ }
+ }
+
+ // Sets the internal pointer to NULL and returns the held object without
+ // releasing the reference.
+ Interface* Detach() {
+ Interface* p = ptr_;
+ ptr_ = NULL;
+ return p;
+ }
+
+ // Accepts an interface pointer that has already been addref-ed.
+ void Attach(Interface* p) {
+ DCHECK(ptr_ == NULL);
+ ptr_ = p;
+ }
+
+ // Retrieves the pointer address.
+ // Used to receive object pointers as out arguments (and take ownership).
+ // The function DCHECKs on the current value being NULL.
+ // Usage: Foo(p.Receive());
+ Interface** Receive() {
+ DCHECK(ptr_ == NULL) << "Object leak. Pointer must be NULL";
+ return &ptr_;
+ }
+
+ template <class Query>
+ HRESULT QueryInterface(Query** p) {
+ DCHECK(p != NULL);
+ DCHECK(ptr_ != NULL);
+ // IUnknown already has a template version of QueryInterface
+ // so the iid parameter is implicit here. The only thing this
+ // function adds are the DCHECKs.
+ return ptr_->QueryInterface(p);
+ }
+
+ // QI for times when the IID is not associated with the type.
+ HRESULT QueryInterface(const IID& iid, void** obj) {
+ DCHECK(obj != NULL);
+ DCHECK(ptr_ != NULL);
+ return ptr_->QueryInterface(iid, obj);
+ }
+
+ // Queries |other| for the interface this object wraps and returns the
+ // error code from the other->QueryInterface operation.
+ HRESULT QueryFrom(IUnknown* object) {
+ DCHECK(object != NULL);
+ return object->QueryInterface(Receive());
+ }
+
+ // Convenience wrapper around CoCreateInstance
+ HRESULT CreateInstance(const CLSID& clsid, IUnknown* outer = NULL,
+ DWORD context = CLSCTX_ALL) {
+ DCHECK(ptr_ == NULL);
+ HRESULT hr = ::CoCreateInstance(clsid, outer, context, *interface_id,
+ reinterpret_cast<void**>(&ptr_));
+ return hr;
+ }
+
+ // Checks if the identity of |other| and this object is the same.
+ bool IsSameObject(IUnknown* other) {
+ if (!other && !ptr_)
+ return true;
+
+ if (!other || !ptr_)
+ return false;
+
+ ScopedComPtr<IUnknown> my_identity;
+ QueryInterface(my_identity.Receive());
+
+ ScopedComPtr<IUnknown> other_identity;
+ other->QueryInterface(other_identity.Receive());
+
+ return static_cast<IUnknown*>(my_identity) ==
+ static_cast<IUnknown*>(other_identity);
+ }
+
+ // Provides direct access to the interface.
+ // Here we use a well known trick to make sure we block access to
+ // IUknown methods so that something bad like this doesn't happen:
+ // ScopedComPtr<IUnknown> p(Foo());
+ // p->Release();
+ // ... later the destructor runs, which will Release() again.
+ // and to get the benefit of the DCHECKs we add to QueryInterface.
+ // There's still a way to call these methods if you absolutely must
+ // by statically casting the ScopedComPtr instance to the wrapped interface
+ // and then making the call... but generally that shouldn't be necessary.
+ BlockIUnknownMethods<Interface>* operator->() const {
+ DCHECK(ptr_ != NULL);
+ return reinterpret_cast<BlockIUnknownMethods<Interface>*>(ptr_);
+ }
+
+ // Pull in operator=() from the parent class.
+ using scoped_refptr<Interface>::operator=;
+
+ // static methods
+
+ static const IID& iid() {
+ return *interface_id;
+ }
+};
+
+} // namespace win
+} // namespace base
+
+#endif // BASE_WIN_SCOPED_COMPTR_H_
diff --git a/base/win/scoped_comptr_unittest.cc b/base/win/scoped_comptr_unittest.cc
new file mode 100644
index 0000000..fcd0791
--- /dev/null
+++ b/base/win/scoped_comptr_unittest.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2006-2008 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_comptr.h"
+
+#include <shlobj.h>
+
+#include "base/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+struct Dummy {
+ Dummy() : adds(0), releases(0) { }
+ void AddRef() { ++adds; }
+ void Release() { ++releases; }
+
+ int adds;
+ int releases;
+};
+
+extern const IID dummy_iid;
+const IID dummy_iid = { 0x12345678u, 0x1234u, 0x5678u, 01, 23, 45, 67, 89,
+ 01, 23, 45 };
+
+} // namespace
+
+TEST(ScopedComPtrTest, ScopedComPtr) {
+ EXPECT_TRUE(memcmp(&ScopedComPtr<IUnknown>::iid(), &IID_IUnknown,
+ sizeof(IID)) == 0);
+
+ EXPECT_TRUE(SUCCEEDED(::CoInitialize(NULL)));
+
+ {
+ ScopedComPtr<IUnknown> unk;
+ EXPECT_TRUE(SUCCEEDED(unk.CreateInstance(CLSID_ShellLink)));
+ ScopedComPtr<IUnknown> unk2;
+ unk2.Attach(unk.Detach());
+ EXPECT_TRUE(unk == NULL);
+ EXPECT_TRUE(unk2 != NULL);
+
+ ScopedComPtr<IMalloc> mem_alloc;
+ EXPECT_TRUE(SUCCEEDED(CoGetMalloc(1, mem_alloc.Receive())));
+
+ ScopedComPtr<IUnknown> qi_test;
+ EXPECT_HRESULT_SUCCEEDED(mem_alloc.QueryInterface(IID_IUnknown,
+ reinterpret_cast<void**>(qi_test.Receive())));
+ EXPECT_TRUE(qi_test.get() != NULL);
+ qi_test.Release();
+
+ // test ScopedComPtr& constructor
+ ScopedComPtr<IMalloc> copy1(mem_alloc);
+ EXPECT_TRUE(copy1.IsSameObject(mem_alloc));
+ EXPECT_FALSE(copy1.IsSameObject(unk2)); // unk2 is valid but different
+ EXPECT_FALSE(copy1.IsSameObject(unk)); // unk is NULL
+
+ IMalloc* naked_copy = copy1.Detach();
+ copy1 = naked_copy; // Test the =(T*) operator.
+ naked_copy->Release();
+
+ copy1.Release();
+ EXPECT_FALSE(copy1.IsSameObject(unk2)); // unk2 is valid, copy1 is not
+
+ // test Interface* constructor
+ ScopedComPtr<IMalloc> copy2(static_cast<IMalloc*>(mem_alloc));
+ EXPECT_TRUE(copy2.IsSameObject(mem_alloc));
+
+ EXPECT_TRUE(SUCCEEDED(unk.QueryFrom(mem_alloc)));
+ EXPECT_TRUE(unk != NULL);
+ unk.Release();
+ EXPECT_TRUE(unk == NULL);
+ EXPECT_TRUE(unk.IsSameObject(copy1)); // both are NULL
+ }
+
+ ::CoUninitialize();
+}
+
+TEST(ScopedComPtrTest, ScopedComPtrVector) {
+ // Verify we don't get error C2558.
+ typedef ScopedComPtr<Dummy, &dummy_iid> Ptr;
+ std::vector<Ptr> bleh;
+
+ scoped_ptr<Dummy> p(new Dummy);
+ {
+ Ptr p2(p.get());
+ EXPECT_EQ(p->adds, 1);
+ EXPECT_EQ(p->releases, 0);
+ Ptr p3 = p2;
+ EXPECT_EQ(p->adds, 2);
+ EXPECT_EQ(p->releases, 0);
+ p3 = p2;
+ EXPECT_EQ(p->adds, 3);
+ EXPECT_EQ(p->releases, 1);
+ // To avoid hitting a reallocation.
+ bleh.reserve(1);
+ bleh.push_back(p2);
+ EXPECT_EQ(p->adds, 4);
+ EXPECT_EQ(p->releases, 1);
+ EXPECT_EQ(bleh[0], p.get());
+ bleh.pop_back();
+ EXPECT_EQ(p->adds, 4);
+ EXPECT_EQ(p->releases, 2);
+ }
+ EXPECT_EQ(p->adds, 4);
+ EXPECT_EQ(p->releases, 4);
+}
+
+} // namespace win
+} // namespace base \ No newline at end of file
diff --git a/base/win/scoped_gdi_object.h b/base/win/scoped_gdi_object.h
new file mode 100644
index 0000000..3ce2245
--- /dev/null
+++ b/base/win/scoped_gdi_object.h
@@ -0,0 +1,78 @@
+// 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.
+
+#ifndef BASE_WIN_SCOPED_GDI_OBJECT_H_
+#define BASE_WIN_SCOPED_GDI_OBJECT_H_
+#pragma once
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+// Like ScopedHandle but for GDI objects.
+template<class T>
+class ScopedGDIObject {
+ public:
+ ScopedGDIObject() : object_(NULL) {}
+ explicit ScopedGDIObject(T object) : object_(object) {}
+
+ ~ScopedGDIObject() {
+ Close();
+ }
+
+ T Get() {
+ return object_;
+ }
+
+ void Set(T object) {
+ if (object_ && object != object_)
+ Close();
+ object_ = object;
+ }
+
+ ScopedGDIObject& operator=(T object) {
+ Set(object);
+ return *this;
+ }
+
+ T release() {
+ T object = object_;
+ object_ = NULL;
+ return object;
+ }
+
+ operator T() { return object_; }
+
+ private:
+ void Close() {
+ if (object_)
+ DeleteObject(object_);
+ }
+
+ T object_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedGDIObject);
+};
+
+// An explicit specialization for HICON because we have to call DestroyIcon()
+// instead of DeleteObject() for HICON.
+template<>
+void ScopedGDIObject<HICON>::Close() {
+ if (object_)
+ DestroyIcon(object_);
+}
+
+// Typedefs for some common use cases.
+typedef ScopedGDIObject<HBITMAP> ScopedBitmap;
+typedef ScopedGDIObject<HRGN> ScopedRegion;
+typedef ScopedGDIObject<HFONT> ScopedHFONT;
+typedef ScopedGDIObject<HICON> ScopedHICON;
+
+} // namespace win
+} // namespace base
+
+#endif // BASE_WIN_SCOPED_GDI_OBJECT_H_
diff --git a/base/win/scoped_handle.h b/base/win/scoped_handle.h
new file mode 100644
index 0000000..3bb0279
--- /dev/null
+++ b/base/win/scoped_handle.h
@@ -0,0 +1,90 @@
+// 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.
+
+#ifndef BASE_WIN_SCOPED_HANDLE_H_
+#define BASE_WIN_SCOPED_HANDLE_H_
+#pragma once
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+// Used so we always remember to close the handle.
+// The class interface matches that of ScopedStdioHandle in addition to an
+// IsValid() method since invalid handles on windows can be either NULL or
+// INVALID_HANDLE_VALUE (-1).
+//
+// Example:
+// ScopedHandle hfile(CreateFile(...));
+// if (!hfile.Get())
+// ...process error
+// ReadFile(hfile.Get(), ...);
+//
+// To sqirrel the handle away somewhere else:
+// secret_handle_ = hfile.Take();
+//
+// To explicitly close the handle:
+// hfile.Close();
+class ScopedHandle {
+ public:
+ ScopedHandle() : handle_(NULL) {
+ }
+
+ explicit ScopedHandle(HANDLE h) : handle_(NULL) {
+ Set(h);
+ }
+
+ ~ScopedHandle() {
+ Close();
+ }
+
+ // Use this instead of comparing to INVALID_HANDLE_VALUE to pick up our NULL
+ // usage for errors.
+ bool IsValid() const {
+ return handle_ != NULL;
+ }
+
+ void Set(HANDLE new_handle) {
+ Close();
+
+ // Windows is inconsistent about invalid handles, so we always use NULL
+ if (new_handle != INVALID_HANDLE_VALUE)
+ handle_ = new_handle;
+ }
+
+ HANDLE Get() {
+ return handle_;
+ }
+
+ operator HANDLE() { return handle_; }
+
+ HANDLE Take() {
+ // transfers ownership away from this object
+ HANDLE h = handle_;
+ handle_ = NULL;
+ return h;
+ }
+
+ void Close() {
+ if (handle_) {
+ if (!::CloseHandle(handle_)) {
+ NOTREACHED();
+ }
+ handle_ = NULL;
+ }
+ }
+
+ private:
+ HANDLE handle_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedHandle);
+};
+
+} // namespace win
+} // namespace base
+
+#endif // BASE_SCOPED_HANDLE_WIN_H_
diff --git a/base/win/scoped_hdc.h b/base/win/scoped_hdc.h
new file mode 100644
index 0000000..73d369a7
--- /dev/null
+++ b/base/win/scoped_hdc.h
@@ -0,0 +1,55 @@
+// 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.
+
+#ifndef BASE_WIN_SCOPED_HDC_H_
+#define BASE_WIN_SCOPED_HDC_H_
+#pragma once
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// Like ScopedHandle but for HDC. Only use this on HDCs returned from
+// CreateCompatibleDC. For an HDC returned by GetDC, use ReleaseDC instead.
+class ScopedHDC {
+ public:
+ ScopedHDC() : hdc_(NULL) { }
+ explicit ScopedHDC(HDC h) : hdc_(h) { }
+
+ ~ScopedHDC() {
+ Close();
+ }
+
+ HDC Get() {
+ return hdc_;
+ }
+
+ void Set(HDC h) {
+ Close();
+ hdc_ = h;
+ }
+
+ operator HDC() { return hdc_; }
+
+ private:
+ void Close() {
+#ifdef NOGDI
+ assert(false);
+#else
+ if (hdc_)
+ DeleteDC(hdc_);
+#endif // NOGDI
+ }
+
+ HDC hdc_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedHDC);
+};
+
+} // namespace win
+} // namespace base
+
+#endif // BASE_WIN_SCOPED_HDC_H_
diff --git a/base/win/scoped_hglobal.h b/base/win/scoped_hglobal.h
new file mode 100644
index 0000000..23b36e4
--- /dev/null
+++ b/base/win/scoped_hglobal.h
@@ -0,0 +1,53 @@
+// 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.
+
+#ifndef BASE_WIN_SCOPED_HGLOBAL_H_
+#define BASE_WIN_SCOPED_HGLOBAL_H_
+#pragma once
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// Like ScopedHandle except for HGLOBAL.
+template<class T>
+class ScopedHGlobal {
+ public:
+ explicit ScopedHGlobal(HGLOBAL glob) : glob_(glob) {
+ data_ = static_cast<T*>(GlobalLock(glob_));
+ }
+ ~ScopedHGlobal() {
+ GlobalUnlock(glob_);
+ }
+
+ T* get() { return data_; }
+
+ size_t Size() const { return GlobalSize(glob_); }
+
+ T* operator->() const {
+ assert(data_ != 0);
+ return data_;
+ }
+
+ T* release() {
+ T* data = data_;
+ data_ = NULL;
+ return data;
+ }
+
+ private:
+ HGLOBAL glob_;
+
+ T* data_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedHGlobal);
+};
+
+} // namespace win
+} // namespace base
+
+#endif // BASE_WIN_SCOPED_HGLOBAL_H_
diff --git a/base/win/scoped_variant.cc b/base/win/scoped_variant.cc
new file mode 100644
index 0000000..278e976
--- /dev/null
+++ b/base/win/scoped_variant.cc
@@ -0,0 +1,276 @@
+// 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/scoped_variant_win.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+// 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;
+}
+
+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 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;
+ }
+}
+
+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
diff --git a/base/win/scoped_variant.h b/base/win/scoped_variant.h
new file mode 100644
index 0000000..6c4d23f
--- /dev/null
+++ b/base/win/scoped_variant.h
@@ -0,0 +1,166 @@
+// 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.
+
+#ifndef BASE_WIN_SCOPED_VARIANT_H_
+#define BASE_WIN_SCOPED_VARIANT_H_
+#pragma once
+
+#include <windows.h>
+#include <oleauto.h>
+
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// Scoped VARIANT 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, we take the containment approach
+// in order to have more control over the usage of the variant and guard
+// against memory leaks.
+class ScopedVariant {
+ public:
+ // Declaration of a global variant variable that's always VT_EMPTY
+ static const VARIANT kEmptyVariant;
+
+ // Default constructor.
+ ScopedVariant() {
+ // This is equivalent to what VariantInit does, but less code.
+ var_.vt = VT_EMPTY;
+ }
+
+ // Constructor to create a new VT_BSTR VARIANT.
+ // NOTE: Do not pass a BSTR to this constructor expecting ownership to
+ // be transferred
+ explicit ScopedVariant(const wchar_t* str);
+
+ // Creates a new VT_BSTR variant of a specified length.
+ explicit ScopedVariant(const wchar_t* str, UINT length);
+
+ // Creates a new integral type variant and assigns the value to
+ // VARIANT.lVal (32 bit sized field).
+ explicit ScopedVariant(int value, VARTYPE vt = VT_I4);
+
+ // Creates a new double-precision type variant. |vt| must be either VT_R8
+ // or VT_DATE.
+ explicit ScopedVariant(double value, VARTYPE vt = VT_R8);
+
+ // VT_DISPATCH
+ explicit ScopedVariant(IDispatch* dispatch);
+
+ // VT_UNKNOWN
+ explicit ScopedVariant(IUnknown* unknown);
+
+ // SAFEARRAY
+ explicit ScopedVariant(SAFEARRAY* safearray);
+
+ // Copies the variant.
+ explicit ScopedVariant(const VARIANT& var);
+
+ ~ScopedVariant();
+
+ inline VARTYPE type() const {
+ return var_.vt;
+ }
+
+ // Give ScopedVariant ownership over an already allocated VARIANT.
+ void Reset(const VARIANT& var = kEmptyVariant);
+
+ // Releases ownership of the VARIANT to the caller.
+ VARIANT Release();
+
+ // Swap two ScopedVariant's.
+ void Swap(ScopedVariant& var);
+
+ // Returns a copy of the variant.
+ VARIANT Copy() const;
+
+ // The return value is 0 if the variants are equal, 1 if this object is
+ // greater than |var|, -1 if it is smaller.
+ int Compare(const VARIANT& var, bool ignore_case = false) const;
+
+ // Retrieves the pointer address.
+ // Used to receive a VARIANT as an out argument (and take ownership).
+ // The function DCHECKs on the current value being empty/null.
+ // Usage: GetVariant(var.receive());
+ VARIANT* Receive();
+
+ void Set(const wchar_t* str);
+
+ // Setters for simple types.
+ void Set(int8 i8);
+ void Set(uint8 ui8);
+ void Set(int16 i16);
+ void Set(uint16 ui16);
+ void Set(int32 i32);
+ void Set(uint32 ui32);
+ void Set(int64 i64);
+ void Set(uint64 ui64);
+ void Set(float r32);
+ void Set(double r64);
+ void Set(bool b);
+
+ // Creates a copy of |var| and assigns as this instance's value.
+ // Note that this is different from the Reset() method that's used to
+ // free the current value and assume ownership.
+ void Set(const VARIANT& var);
+
+ // COM object setters
+ void Set(IDispatch* disp);
+ void Set(IUnknown* unk);
+
+ // SAFEARRAY support
+ void Set(SAFEARRAY* array);
+
+ // Special setter for DATE since DATE is a double and we already have
+ // a setter for double.
+ void SetDate(DATE date);
+
+ // Allows const access to the contained variant without DCHECKs etc.
+ // This support is necessary for the V_XYZ (e.g. V_BSTR) set of macros to
+ // work properly but still doesn't allow modifications since we want control
+ // over that.
+ const VARIANT* operator&() const {
+ return &var_;
+ }
+
+ // Like other scoped classes (e.g scoped_refptr, ScopedComPtr, ScopedBstr)
+ // we support the assignment operator for the type we wrap.
+ ScopedVariant& operator=(const VARIANT& var);
+
+ // A hack to pass a pointer to the variant where the accepting
+ // function treats the variant as an input-only, read-only value
+ // but the function prototype requires a non const variant pointer.
+ // There's no DCHECK or anything here. Callers must know what they're doing.
+ VARIANT* AsInput() const {
+ // The nature of this function is const, so we declare
+ // it as such and cast away the constness here.
+ return const_cast<VARIANT*>(&var_);
+ }
+
+ // Allows the ScopedVariant instance to be passed to functions either by value
+ // or by const reference.
+ operator const VARIANT&() const {
+ return var_;
+ }
+
+ // Used as a debug check to see if we're leaking anything.
+ static bool IsLeakableVarType(VARTYPE vt);
+
+ protected:
+ VARIANT var_;
+
+ private:
+ // Comparison operators for ScopedVariant are not supported at this point.
+ // Use the Compare method instead.
+ bool operator==(const ScopedVariant& var) const;
+ bool operator!=(const ScopedVariant& var) const;
+ DISALLOW_COPY_AND_ASSIGN(ScopedVariant);
+};
+
+} // namespace win
+} // namesoace base
+
+#endif // BASE_WIN_SCOPED_VARIANT_H_
diff --git a/base/win/scoped_variant_unittest.cc b/base/win/scoped_variant_unittest.cc
new file mode 100644
index 0000000..2cd5be1
--- /dev/null
+++ b/base/win/scoped_variant_unittest.cc
@@ -0,0 +1,263 @@
+// 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/win/scoped_variant.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+static const wchar_t kTestString1[] = L"Used to create BSTRs";
+static const wchar_t kTestString2[] = L"Also used to create BSTRs";
+
+void GiveMeAVariant(VARIANT* ret) {
+ EXPECT_TRUE(ret != NULL);
+ ret->vt = VT_BSTR;
+ V_BSTR(ret) = ::SysAllocString(kTestString1);
+}
+
+// A dummy IDispatch implementation (if you can call it that).
+// The class does nothing intelligent really. Only increments a counter
+// when AddRef is called and decrements it when Release is called.
+class FakeComObject : public IDispatch {
+ public:
+ FakeComObject() : ref_(0) {
+ }
+
+ STDMETHOD_(DWORD, AddRef)() {
+ ref_++;
+ return ref_;
+ }
+
+ STDMETHOD_(DWORD, Release)() {
+ ref_--;
+ return ref_;
+ }
+
+ STDMETHOD(QueryInterface)(REFIID, void**) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(GetTypeInfoCount)(UINT*) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(GetTypeInfo)(UINT, LCID, ITypeInfo**) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(GetIDsOfNames)(REFIID, LPOLESTR*, UINT, LCID, DISPID*) {
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(Invoke)(DISPID, REFIID, LCID, WORD, DISPPARAMS*, VARIANT*,
+ EXCEPINFO*, UINT*) {
+ return E_NOTIMPL;
+ }
+
+ // A way to check the internal reference count of the class.
+ int ref_count() const {
+ return ref_;
+ }
+
+ protected:
+ int ref_;
+};
+
+} // namespace
+
+TEST(ScopedVariantTest, ScopedVariant) {
+ ScopedVariant var;
+ EXPECT_TRUE(var.type() == VT_EMPTY);
+ // V_BSTR(&var) = NULL; <- NOTE: Assignment like that is not supported
+
+ ScopedVariant var_bstr(L"VT_BSTR");
+ EXPECT_EQ(VT_BSTR, V_VT(&var_bstr));
+ EXPECT_TRUE(V_BSTR(&var_bstr) != NULL); // can't use EXPECT_NE for BSTR
+ var_bstr.Reset();
+ EXPECT_NE(VT_BSTR, V_VT(&var_bstr));
+ var_bstr.Set(kTestString2);
+ EXPECT_EQ(VT_BSTR, V_VT(&var_bstr));
+
+ VARIANT tmp = var_bstr.Release();
+ EXPECT_EQ(VT_EMPTY, V_VT(&var_bstr));
+ EXPECT_EQ(VT_BSTR, V_VT(&tmp));
+ EXPECT_EQ(0, lstrcmp(V_BSTR(&tmp), kTestString2));
+
+ var.Reset(tmp);
+ EXPECT_EQ(VT_BSTR, V_VT(&var));
+ EXPECT_EQ(0, lstrcmpW(V_BSTR(&var), kTestString2));
+
+ var_bstr.Swap(var);
+ EXPECT_EQ(VT_EMPTY, V_VT(&var));
+ EXPECT_EQ(VT_BSTR, V_VT(&var_bstr));
+ EXPECT_EQ(0, lstrcmpW(V_BSTR(&var_bstr), kTestString2));
+ var_bstr.Reset();
+
+ // Test the Compare and Copy routines.
+ GiveMeAVariant(var_bstr.Receive());
+ ScopedVariant var_bstr2(V_BSTR(&var_bstr));
+ EXPECT_EQ(0, var_bstr.Compare(var_bstr2));
+ var_bstr2.Reset();
+ EXPECT_NE(0, var_bstr.Compare(var_bstr2));
+ var_bstr2.Reset(var_bstr.Copy());
+ EXPECT_EQ(0, var_bstr.Compare(var_bstr2));
+ var_bstr2.Reset();
+ var_bstr2.Set(V_BSTR(&var_bstr));
+ EXPECT_EQ(0, var_bstr.Compare(var_bstr2));
+ var_bstr2.Reset();
+ var_bstr.Reset();
+
+ // Test for the SetDate setter.
+ SYSTEMTIME sys_time;
+ ::GetSystemTime(&sys_time);
+ DATE date;
+ ::SystemTimeToVariantTime(&sys_time, &date);
+ var.Reset();
+ var.SetDate(date);
+ EXPECT_EQ(VT_DATE, var.type());
+ EXPECT_EQ(date, V_DATE(&var));
+
+ // Simple setter tests. These do not require resetting the variant
+ // after each test since the variant type is not "leakable" (i.e. doesn't
+ // need to be freed explicitly).
+
+ // We need static cast here since char defaults to int (!?).
+ var.Set(static_cast<int8>('v'));
+ EXPECT_EQ(VT_I1, var.type());
+ EXPECT_EQ('v', V_I1(&var));
+
+ var.Set(static_cast<short>(123));
+ EXPECT_EQ(VT_I2, var.type());
+ EXPECT_EQ(123, V_I2(&var));
+
+ var.Set(static_cast<int32>(123));
+ EXPECT_EQ(VT_I4, var.type());
+ EXPECT_EQ(123, V_I4(&var));
+
+ var.Set(static_cast<int64>(123));
+ EXPECT_EQ(VT_I8, var.type());
+ EXPECT_EQ(123, V_I8(&var));
+
+ var.Set(static_cast<uint8>(123));
+ EXPECT_EQ(VT_UI1, var.type());
+ EXPECT_EQ(123, V_UI1(&var));
+
+ var.Set(static_cast<unsigned short>(123));
+ EXPECT_EQ(VT_UI2, var.type());
+ EXPECT_EQ(123, V_UI2(&var));
+
+ var.Set(static_cast<uint32>(123));
+ EXPECT_EQ(VT_UI4, var.type());
+ EXPECT_EQ(123, V_UI4(&var));
+
+ var.Set(static_cast<uint64>(123));
+ EXPECT_EQ(VT_UI8, var.type());
+ EXPECT_EQ(123, V_UI8(&var));
+
+ var.Set(123.123f);
+ EXPECT_EQ(VT_R4, var.type());
+ EXPECT_EQ(123.123f, V_R4(&var));
+
+ var.Set(static_cast<double>(123.123));
+ EXPECT_EQ(VT_R8, var.type());
+ EXPECT_EQ(123.123, V_R8(&var));
+
+ var.Set(true);
+ EXPECT_EQ(VT_BOOL, var.type());
+ EXPECT_EQ(VARIANT_TRUE, V_BOOL(&var));
+ var.Set(false);
+ EXPECT_EQ(VT_BOOL, var.type());
+ EXPECT_EQ(VARIANT_FALSE, V_BOOL(&var));
+
+ // Com interface tests
+
+ var.Set(static_cast<IDispatch*>(NULL));
+ EXPECT_EQ(VT_DISPATCH, var.type());
+ EXPECT_EQ(NULL, V_DISPATCH(&var));
+ var.Reset();
+
+ var.Set(static_cast<IUnknown*>(NULL));
+ EXPECT_EQ(VT_UNKNOWN, var.type());
+ EXPECT_EQ(NULL, V_UNKNOWN(&var));
+ var.Reset();
+
+ FakeComObject faker;
+ EXPECT_EQ(0, faker.ref_count());
+ var.Set(static_cast<IDispatch*>(&faker));
+ EXPECT_EQ(VT_DISPATCH, var.type());
+ EXPECT_EQ(&faker, V_DISPATCH(&var));
+ EXPECT_EQ(1, faker.ref_count());
+ var.Reset();
+ EXPECT_EQ(0, faker.ref_count());
+
+ var.Set(static_cast<IUnknown*>(&faker));
+ EXPECT_EQ(VT_UNKNOWN, var.type());
+ EXPECT_EQ(&faker, V_UNKNOWN(&var));
+ EXPECT_EQ(1, faker.ref_count());
+ var.Reset();
+ EXPECT_EQ(0, faker.ref_count());
+
+ {
+ ScopedVariant disp_var(&faker);
+ EXPECT_EQ(VT_DISPATCH, disp_var.type());
+ EXPECT_EQ(&faker, V_DISPATCH(&disp_var));
+ EXPECT_EQ(1, faker.ref_count());
+ }
+ EXPECT_EQ(0, faker.ref_count());
+
+ {
+ ScopedVariant ref1(&faker);
+ EXPECT_EQ(1, faker.ref_count());
+ ScopedVariant ref2(static_cast<const VARIANT&>(ref1));
+ EXPECT_EQ(2, faker.ref_count());
+ ScopedVariant ref3;
+ ref3 = static_cast<const VARIANT&>(ref2);
+ EXPECT_EQ(3, faker.ref_count());
+ }
+ EXPECT_EQ(0, faker.ref_count());
+
+ {
+ ScopedVariant unk_var(static_cast<IUnknown*>(&faker));
+ EXPECT_EQ(VT_UNKNOWN, unk_var.type());
+ EXPECT_EQ(&faker, V_UNKNOWN(&unk_var));
+ EXPECT_EQ(1, faker.ref_count());
+ }
+ EXPECT_EQ(0, faker.ref_count());
+
+ VARIANT raw;
+ raw.vt = VT_UNKNOWN;
+ raw.punkVal = &faker;
+ EXPECT_EQ(0, faker.ref_count());
+ var.Set(raw);
+ EXPECT_EQ(1, faker.ref_count());
+ var.Reset();
+ EXPECT_EQ(0, faker.ref_count());
+
+ {
+ ScopedVariant number(123);
+ EXPECT_EQ(VT_I4, number.type());
+ EXPECT_EQ(123, V_I4(&number));
+ }
+
+ // SAFEARRAY tests
+ var.Set(static_cast<SAFEARRAY*>(NULL));
+ EXPECT_EQ(VT_EMPTY, var.type());
+
+ SAFEARRAY* sa = ::SafeArrayCreateVector(VT_UI1, 0, 100);
+ ASSERT_TRUE(sa != NULL);
+
+ var.Set(sa);
+#ifndef OFFICIAL_BUILD
+ EXPECT_TRUE(ScopedVariant::IsLeakableVarType(var.type()));
+#endif
+ EXPECT_EQ(VT_ARRAY | VT_UI1, var.type());
+ EXPECT_EQ(sa, V_ARRAY(&var));
+ // The array is destroyed in the destructor of var.
+}
+
+} // namespace win
+} // namespace base