• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 
5 #ifndef BASE_WIN_SCOPED_COMPTR_H_
6 #define BASE_WIN_SCOPED_COMPTR_H_
7 
8 #include <unknwn.h>
9 
10 #include "base/logging.h"
11 #include "base/memory/ref_counted.h"
12 
13 namespace base {
14 namespace win {
15 
16 // A fairly minimalistic smart class for COM interface pointers.
17 // Uses scoped_refptr for the basic smart pointer functionality
18 // and adds a few IUnknown specific services.
19 template <class Interface, const IID* interface_id = &__uuidof(Interface)>
20 class ScopedComPtr : public scoped_refptr<Interface> {
21  public:
22   // Utility template to prevent users of ScopedComPtr from calling AddRef
23   // and/or Release() without going through the ScopedComPtr class.
24   class BlockIUnknownMethods : public Interface {
25    private:
26     STDMETHOD(QueryInterface)(REFIID iid, void** object) = 0;
27     STDMETHOD_(ULONG, AddRef)() = 0;
28     STDMETHOD_(ULONG, Release)() = 0;
29   };
30 
31   typedef scoped_refptr<Interface> ParentClass;
32 
ScopedComPtr()33   ScopedComPtr() {
34   }
35 
ScopedComPtr(Interface * p)36   explicit ScopedComPtr(Interface* p) : ParentClass(p) {
37   }
38 
ScopedComPtr(const ScopedComPtr<Interface,interface_id> & p)39   ScopedComPtr(const ScopedComPtr<Interface, interface_id>& p)
40       : ParentClass(p) {
41   }
42 
~ScopedComPtr()43   ~ScopedComPtr() {
44     // We don't want the smart pointer class to be bigger than the pointer
45     // it wraps.
46     COMPILE_ASSERT(sizeof(ScopedComPtr<Interface, interface_id>) ==
47                    sizeof(Interface*), ScopedComPtrSize);
48   }
49 
50   // Explicit Release() of the held object.  Useful for reuse of the
51   // ScopedComPtr instance.
52   // Note that this function equates to IUnknown::Release and should not
53   // be confused with e.g. scoped_ptr::release().
Release()54   void Release() {
55     if (ptr_ != NULL) {
56       ptr_->Release();
57       ptr_ = NULL;
58     }
59   }
60 
61   // Sets the internal pointer to NULL and returns the held object without
62   // releasing the reference.
Detach()63   Interface* Detach() {
64     Interface* p = ptr_;
65     ptr_ = NULL;
66     return p;
67   }
68 
69   // Accepts an interface pointer that has already been addref-ed.
Attach(Interface * p)70   void Attach(Interface* p) {
71     DCHECK(!ptr_);
72     ptr_ = p;
73   }
74 
75   // Retrieves the pointer address.
76   // Used to receive object pointers as out arguments (and take ownership).
77   // The function DCHECKs on the current value being NULL.
78   // Usage: Foo(p.Receive());
Receive()79   Interface** Receive() {
80     DCHECK(!ptr_) << "Object leak. Pointer must be NULL";
81     return &ptr_;
82   }
83 
84   // A convenience for whenever a void pointer is needed as an out argument.
ReceiveVoid()85   void** ReceiveVoid() {
86     return reinterpret_cast<void**>(Receive());
87   }
88 
89   template <class Query>
QueryInterface(Query ** p)90   HRESULT QueryInterface(Query** p) {
91     DCHECK(p != NULL);
92     DCHECK(ptr_ != NULL);
93     // IUnknown already has a template version of QueryInterface
94     // so the iid parameter is implicit here. The only thing this
95     // function adds are the DCHECKs.
96     return ptr_->QueryInterface(p);
97   }
98 
99   // QI for times when the IID is not associated with the type.
QueryInterface(const IID & iid,void ** obj)100   HRESULT QueryInterface(const IID& iid, void** obj) {
101     DCHECK(obj != NULL);
102     DCHECK(ptr_ != NULL);
103     return ptr_->QueryInterface(iid, obj);
104   }
105 
106   // Queries |other| for the interface this object wraps and returns the
107   // error code from the other->QueryInterface operation.
QueryFrom(IUnknown * object)108   HRESULT QueryFrom(IUnknown* object) {
109     DCHECK(object != NULL);
110     return object->QueryInterface(Receive());
111   }
112 
113   // Convenience wrapper around CoCreateInstance
114   HRESULT CreateInstance(const CLSID& clsid, IUnknown* outer = NULL,
115                          DWORD context = CLSCTX_ALL) {
116     DCHECK(!ptr_);
117     HRESULT hr = ::CoCreateInstance(clsid, outer, context, *interface_id,
118                                     reinterpret_cast<void**>(&ptr_));
119     return hr;
120   }
121 
122   // Checks if the identity of |other| and this object is the same.
IsSameObject(IUnknown * other)123   bool IsSameObject(IUnknown* other) {
124     if (!other && !ptr_)
125       return true;
126 
127     if (!other || !ptr_)
128       return false;
129 
130     ScopedComPtr<IUnknown> my_identity;
131     QueryInterface(my_identity.Receive());
132 
133     ScopedComPtr<IUnknown> other_identity;
134     other->QueryInterface(other_identity.Receive());
135 
136     return static_cast<IUnknown*>(my_identity) ==
137            static_cast<IUnknown*>(other_identity);
138   }
139 
140   // Provides direct access to the interface.
141   // Here we use a well known trick to make sure we block access to
142   // IUnknown methods so that something bad like this doesn't happen:
143   //    ScopedComPtr<IUnknown> p(Foo());
144   //    p->Release();
145   //    ... later the destructor runs, which will Release() again.
146   // and to get the benefit of the DCHECKs we add to QueryInterface.
147   // There's still a way to call these methods if you absolutely must
148   // by statically casting the ScopedComPtr instance to the wrapped interface
149   // and then making the call... but generally that shouldn't be necessary.
150   BlockIUnknownMethods* operator->() const {
151     DCHECK(ptr_ != NULL);
152     return reinterpret_cast<BlockIUnknownMethods*>(ptr_);
153   }
154 
155   // Pull in operator=() from the parent class.
156   using scoped_refptr<Interface>::operator=;
157 
158   // static methods
159 
iid()160   static const IID& iid() {
161     return *interface_id;
162   }
163 };
164 
165 }  // namespace win
166 }  // namespace base
167 
168 #endif  // BASE_WIN_SCOPED_COMPTR_H_
169