blob: 3fa419f2b5fbc19f92ca8e72e1b99f27f16d88e6 [file] [log] [blame]
[email protected]49457c32009-01-12 20:10:491// Copyright (c) 2006-2008 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
[email protected]f5f36152009-01-15 17:16:485#ifndef BASE_SCOPED_COMPTR_WIN_H_
6#define BASE_SCOPED_COMPTR_WIN_H_
7
8#include <unknwn.h>
[email protected]49457c32009-01-12 20:10:499
10#include "base/logging.h"
11#include "base/ref_counted.h"
12
[email protected]f5f36152009-01-15 17:16:4813// Utility template to prevent users of ScopedComPtr from calling AddRef and/or
14// Release() without going through the ScopedComPtr class.
[email protected]c71b654f2009-01-21 23:55:0215template <class Interface>
16class BlockIUnknownMethods : public Interface {
17 private:
[email protected]49457c32009-01-12 20:10:4918 STDMETHOD(QueryInterface)(REFIID iid, void** object) = 0;
[email protected]c71b654f2009-01-21 23:55:0219 STDMETHOD_(ULONG, AddRef)() = 0;
20 STDMETHOD_(ULONG, Release)() = 0;
21};
[email protected]49457c32009-01-12 20:10:4922
23// A fairly minimalistic smart class for COM interface pointers.
24// Uses scoped_refptr for the basic smart pointer functionality
25// and adds a few IUnknown specific services.
26template <class Interface, const IID* interface_id = &__uuidof(Interface)>
[email protected]f5f36152009-01-15 17:16:4827class ScopedComPtr : public scoped_refptr<Interface> {
[email protected]49457c32009-01-12 20:10:4928 public:
29 typedef scoped_refptr<Interface> ParentClass;
30
[email protected]f5f36152009-01-15 17:16:4831 ScopedComPtr() {
[email protected]49457c32009-01-12 20:10:4932 }
33
[email protected]f5f36152009-01-15 17:16:4834 explicit ScopedComPtr(Interface* p) : ParentClass(p) {
[email protected]49457c32009-01-12 20:10:4935 }
36
[email protected]c074a54a2009-05-13 15:46:3437 ScopedComPtr(const ScopedComPtr<Interface, interface_id>& p)
[email protected]49457c32009-01-12 20:10:4938 : ParentClass(p) {
39 }
40
[email protected]f5f36152009-01-15 17:16:4841 ~ScopedComPtr() {
[email protected]49457c32009-01-12 20:10:4942 // We don't want the smart pointer class to be bigger than the pointer
43 // it wraps.
[email protected]f5f36152009-01-15 17:16:4844 COMPILE_ASSERT(sizeof(ScopedComPtr<Interface, interface_id>) ==
[email protected]49457c32009-01-12 20:10:4945 sizeof(Interface*), ScopedComPtrSize);
46 }
47
48 // Explicit Release() of the held object. Useful for reuse of the
[email protected]f5f36152009-01-15 17:16:4849 // ScopedComPtr instance.
[email protected]49457c32009-01-12 20:10:4950 // Note that this function equates to IUnknown::Release and should not
51 // be confused with e.g. scoped_ptr::release().
52 void Release() {
53 if (ptr_ != NULL) {
54 ptr_->Release();
55 ptr_ = NULL;
56 }
57 }
58
59 // Sets the internal pointer to NULL and returns the held object without
60 // releasing the reference.
61 Interface* Detach() {
62 Interface* p = ptr_;
63 ptr_ = NULL;
64 return p;
65 }
66
67 // Accepts an interface pointer that has already been addref-ed.
68 void Attach(Interface* p) {
69 DCHECK(ptr_ == NULL);
70 ptr_ = p;
71 }
72
73 // Retrieves the pointer address.
74 // Used to receive object pointers as out arguments (and take ownership).
75 // The function DCHECKs on the current value being NULL.
76 // Usage: Foo(p.Receive());
77 Interface** Receive() {
78 DCHECK(ptr_ == NULL) << "Object leak. Pointer must be NULL";
79 return &ptr_;
80 }
81
82 template <class Query>
83 HRESULT QueryInterface(Query** p) {
84 DCHECK(p != NULL);
85 DCHECK(ptr_ != NULL);
86 // IUnknown already has a template version of QueryInterface
87 // so the iid parameter is implicit here. The only thing this
88 // function adds are the DCHECKs.
89 return ptr_->QueryInterface(p);
90 }
91
92 // Queries |other| for the interface this object wraps and returns the
93 // error code from the other->QueryInterface operation.
94 HRESULT QueryFrom(IUnknown* object) {
95 DCHECK(object != NULL);
96 return object->QueryInterface(Receive());
97 }
98
99 // Convenience wrapper around CoCreateInstance
100 HRESULT CreateInstance(const CLSID& clsid, IUnknown* outer = NULL,
101 DWORD context = CLSCTX_ALL) {
102 DCHECK(ptr_ == NULL);
103 HRESULT hr = ::CoCreateInstance(clsid, outer, context, *interface_id,
104 reinterpret_cast<void**>(&ptr_));
105 return hr;
106 }
107
108 // Checks if the identity of |other| and this object is the same.
109 bool IsSameObject(IUnknown* other) {
110 if (!other && !ptr_)
111 return true;
[email protected]c71b654f2009-01-21 23:55:02112
113 if (!other || !ptr_)
114 return false;
115
116 ScopedComPtr<IUnknown> my_identity;
117 QueryInterface(my_identity.Receive());
118
119 ScopedComPtr<IUnknown> other_identity;
120 other->QueryInterface(other_identity.Receive());
121
122 return static_cast<IUnknown*>(my_identity) ==
123 static_cast<IUnknown*>(other_identity);
[email protected]49457c32009-01-12 20:10:49124 }
125
126 // Provides direct access to the interface.
127 // Here we use a well known trick to make sure we block access to
128 // IUknown methods so that something bad like this doesn't happen:
[email protected]f5f36152009-01-15 17:16:48129 // ScopedComPtr<IUnknown> p(Foo());
[email protected]49457c32009-01-12 20:10:49130 // p->Release();
131 // ... later the destructor runs, which will Release() again.
132 // and to get the benefit of the DCHECKs we add to QueryInterface.
133 // There's still a way to call these methods if you absolutely must
[email protected]f5f36152009-01-15 17:16:48134 // by statically casting the ScopedComPtr instance to the wrapped interface
[email protected]49457c32009-01-12 20:10:49135 // and then making the call... but generally that shouldn't be necessary.
136 BlockIUnknownMethods<Interface>* operator->() const {
137 DCHECK(ptr_ != NULL);
138 return reinterpret_cast<BlockIUnknownMethods<Interface>*>(ptr_);
139 }
140
[email protected]330436f2009-03-07 02:54:45141 // Pull in operator=() from the parent class.
142 using scoped_refptr<Interface>::operator=;
143
[email protected]49457c32009-01-12 20:10:49144 // static methods
145
146 static const IID& iid() {
147 return *interface_id;
148 }
149};
150
[email protected]f5f36152009-01-15 17:16:48151#endif // BASE_SCOPED_COMPTR_WIN_H_