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 static_assert( 47 sizeof(ScopedComPtr<Interface, interface_id>) == sizeof(Interface*), 48 "ScopedComPtrSize"); 49 } 50 51 // Explicit Release() of the held object. Useful for reuse of the 52 // ScopedComPtr instance. 53 // Note that this function equates to IUnknown::Release and should not 54 // be confused with e.g. scoped_ptr::release(). Release()55 void Release() { 56 if (this->ptr_ != NULL) { 57 this->ptr_->Release(); 58 this->ptr_ = NULL; 59 } 60 } 61 62 // Sets the internal pointer to NULL and returns the held object without 63 // releasing the reference. Detach()64 Interface* Detach() { 65 Interface* p = this->ptr_; 66 this->ptr_ = NULL; 67 return p; 68 } 69 70 // Accepts an interface pointer that has already been addref-ed. Attach(Interface * p)71 void Attach(Interface* p) { 72 DCHECK(!this->ptr_); 73 this->ptr_ = p; 74 } 75 76 // Retrieves the pointer address. 77 // Used to receive object pointers as out arguments (and take ownership). 78 // The function DCHECKs on the current value being NULL. 79 // Usage: Foo(p.Receive()); Receive()80 Interface** Receive() { 81 DCHECK(!this->ptr_) << "Object leak. Pointer must be NULL"; 82 return &this->ptr_; 83 } 84 85 // A convenience for whenever a void pointer is needed as an out argument. ReceiveVoid()86 void** ReceiveVoid() { 87 return reinterpret_cast<void**>(Receive()); 88 } 89 90 template <class Query> QueryInterface(Query ** p)91 HRESULT QueryInterface(Query** p) { 92 DCHECK(p != NULL); 93 DCHECK(this->ptr_ != NULL); 94 // IUnknown already has a template version of QueryInterface 95 // so the iid parameter is implicit here. The only thing this 96 // function adds are the DCHECKs. 97 return this->ptr_->QueryInterface(p); 98 } 99 100 // QI for times when the IID is not associated with the type. QueryInterface(const IID & iid,void ** obj)101 HRESULT QueryInterface(const IID& iid, void** obj) { 102 DCHECK(obj != NULL); 103 DCHECK(this->ptr_ != NULL); 104 return this->ptr_->QueryInterface(iid, obj); 105 } 106 107 // Queries |other| for the interface this object wraps and returns the 108 // error code from the other->QueryInterface operation. QueryFrom(IUnknown * object)109 HRESULT QueryFrom(IUnknown* object) { 110 DCHECK(object != NULL); 111 return object->QueryInterface(Receive()); 112 } 113 114 // Convenience wrapper around CoCreateInstance 115 HRESULT CreateInstance(const CLSID& clsid, IUnknown* outer = NULL, 116 DWORD context = CLSCTX_ALL) { 117 DCHECK(!this->ptr_); 118 HRESULT hr = ::CoCreateInstance(clsid, outer, context, *interface_id, 119 reinterpret_cast<void**>(&this->ptr_)); 120 return hr; 121 } 122 123 // Checks if the identity of |other| and this object is the same. IsSameObject(IUnknown * other)124 bool IsSameObject(IUnknown* other) { 125 if (!other && !this->ptr_) 126 return true; 127 128 if (!other || !this->ptr_) 129 return false; 130 131 ScopedComPtr<IUnknown> my_identity; 132 QueryInterface(my_identity.Receive()); 133 134 ScopedComPtr<IUnknown> other_identity; 135 other->QueryInterface(other_identity.Receive()); 136 137 return my_identity == 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(this->ptr_ != NULL); 152 return reinterpret_cast<BlockIUnknownMethods*>(this->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