• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
5 #ifndef BASE_SCOPED_COMPTR_WIN_H_
6 #define BASE_SCOPED_COMPTR_WIN_H_
7 
8 #include <unknwn.h>
9 
10 #include "base/logging.h"
11 #include "base/ref_counted.h"
12 
13 // Utility template to prevent users of ScopedComPtr from calling AddRef and/or
14 // Release() without going through the ScopedComPtr class.
15 template <class Interface>
16 class BlockIUnknownMethods : public Interface {
17  private:
18   STDMETHOD(QueryInterface)(REFIID iid, void** object) = 0;
19   STDMETHOD_(ULONG, AddRef)() = 0;
20   STDMETHOD_(ULONG, Release)() = 0;
21 };
22 
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.
26 template <class Interface, const IID* interface_id = &__uuidof(Interface)>
27 class ScopedComPtr : public scoped_refptr<Interface> {
28  public:
29   typedef scoped_refptr<Interface> ParentClass;
30 
ScopedComPtr()31   ScopedComPtr() {
32   }
33 
ScopedComPtr(Interface * p)34   explicit ScopedComPtr(Interface* p) : ParentClass(p) {
35   }
36 
ScopedComPtr(const ScopedComPtr<Interface,interface_id> & p)37   ScopedComPtr(const ScopedComPtr<Interface, interface_id>& p)
38       : ParentClass(p) {
39   }
40 
~ScopedComPtr()41   ~ScopedComPtr() {
42     // We don't want the smart pointer class to be bigger than the pointer
43     // it wraps.
44     COMPILE_ASSERT(sizeof(ScopedComPtr<Interface, interface_id>) ==
45                    sizeof(Interface*), ScopedComPtrSize);
46   }
47 
48   // Explicit Release() of the held object.  Useful for reuse of the
49   // ScopedComPtr instance.
50   // Note that this function equates to IUnknown::Release and should not
51   // be confused with e.g. scoped_ptr::release().
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.
Detach()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.
Attach(Interface * p)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());
Receive()77   Interface** Receive() {
78     DCHECK(ptr_ == NULL) << "Object leak. Pointer must be NULL";
79     return &ptr_;
80   }
81 
82   template <class Query>
QueryInterface(Query ** p)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   // QI for times when the IID is not associated with the type.
QueryInterface(const IID & iid,void ** obj)93   HRESULT QueryInterface(const IID& iid, void** obj) {
94     DCHECK(obj != NULL);
95     DCHECK(ptr_ != NULL);
96     return ptr_->QueryInterface(iid, obj);
97   }
98 
99   // Queries |other| for the interface this object wraps and returns the
100   // error code from the other->QueryInterface operation.
QueryFrom(IUnknown * object)101   HRESULT QueryFrom(IUnknown* object) {
102     DCHECK(object != NULL);
103     return object->QueryInterface(Receive());
104   }
105 
106   // Convenience wrapper around CoCreateInstance
107   HRESULT CreateInstance(const CLSID& clsid, IUnknown* outer = NULL,
108                          DWORD context = CLSCTX_ALL) {
109     DCHECK(ptr_ == NULL);
110     HRESULT hr = ::CoCreateInstance(clsid, outer, context, *interface_id,
111                                     reinterpret_cast<void**>(&ptr_));
112     return hr;
113   }
114 
115   // Checks if the identity of |other| and this object is the same.
IsSameObject(IUnknown * other)116   bool IsSameObject(IUnknown* other) {
117     if (!other && !ptr_)
118       return true;
119 
120     if (!other || !ptr_)
121       return false;
122 
123     ScopedComPtr<IUnknown> my_identity;
124     QueryInterface(my_identity.Receive());
125 
126     ScopedComPtr<IUnknown> other_identity;
127     other->QueryInterface(other_identity.Receive());
128 
129     return static_cast<IUnknown*>(my_identity) ==
130            static_cast<IUnknown*>(other_identity);
131   }
132 
133   // Provides direct access to the interface.
134   // Here we use a well known trick to make sure we block access to
135   // IUknown methods so that something bad like this doesn't happen:
136   //    ScopedComPtr<IUnknown> p(Foo());
137   //    p->Release();
138   //    ... later the destructor runs, which will Release() again.
139   // and to get the benefit of the DCHECKs we add to QueryInterface.
140   // There's still a way to call these methods if you absolutely must
141   // by statically casting the ScopedComPtr instance to the wrapped interface
142   // and then making the call... but generally that shouldn't be necessary.
143   BlockIUnknownMethods<Interface>* operator->() const {
144     DCHECK(ptr_ != NULL);
145     return reinterpret_cast<BlockIUnknownMethods<Interface>*>(ptr_);
146   }
147 
148   // Pull in operator=() from the parent class.
149   using scoped_refptr<Interface>::operator=;
150 
151   // static methods
152 
iid()153   static const IID& iid() {
154     return *interface_id;
155   }
156 };
157 
158 #endif  // BASE_SCOPED_COMPTR_WIN_H_
159