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 #pragma once 8 9 #include <unknwn.h> 10 11 #include "base/logging.h" 12 #include "base/memory/ref_counted.h" 13 14 namespace base { 15 namespace win { 16 17 // A fairly minimalistic smart class for COM interface pointers. 18 // Uses scoped_refptr for the basic smart pointer functionality 19 // and adds a few IUnknown specific services. 20 template <class Interface, const IID* interface_id = &__uuidof(Interface)> 21 class ScopedComPtr : public scoped_refptr<Interface> { 22 public: 23 // Utility template to prevent users of ScopedComPtr from calling AddRef 24 // and/or Release() without going through the ScopedComPtr class. 25 class BlockIUnknownMethods : public Interface { 26 private: 27 STDMETHOD(QueryInterface)(REFIID iid, void** object) = 0; 28 STDMETHOD_(ULONG, AddRef)() = 0; 29 STDMETHOD_(ULONG, Release)() = 0; 30 }; 31 32 typedef scoped_refptr<Interface> ParentClass; 33 ScopedComPtr()34 ScopedComPtr() { 35 } 36 ScopedComPtr(Interface * p)37 explicit ScopedComPtr(Interface* p) : ParentClass(p) { 38 } 39 ScopedComPtr(const ScopedComPtr<Interface,interface_id> & p)40 ScopedComPtr(const ScopedComPtr<Interface, interface_id>& p) 41 : ParentClass(p) { 42 } 43 ~ScopedComPtr()44 ~ScopedComPtr() { 45 // We don't want the smart pointer class to be bigger than the pointer 46 // it wraps. 47 COMPILE_ASSERT(sizeof(ScopedComPtr<Interface, interface_id>) == 48 sizeof(Interface*), 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 (ptr_ != NULL) { 57 ptr_->Release(); 58 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 = ptr_; 66 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(!ptr_); 73 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(!ptr_) << "Object leak. Pointer must be NULL"; 82 return &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(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 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(ptr_ != NULL); 104 return 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(!ptr_); 118 HRESULT hr = ::CoCreateInstance(clsid, outer, context, *interface_id, 119 reinterpret_cast<void**>(&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 && !ptr_) 126 return true; 127 128 if (!other || !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 static_cast<IUnknown*>(my_identity) == 138 static_cast<IUnknown*>(other_identity); 139 } 140 141 // Provides direct access to the interface. 142 // Here we use a well known trick to make sure we block access to 143 // IUknown methods so that something bad like this doesn't happen: 144 // ScopedComPtr<IUnknown> p(Foo()); 145 // p->Release(); 146 // ... later the destructor runs, which will Release() again. 147 // and to get the benefit of the DCHECKs we add to QueryInterface. 148 // There's still a way to call these methods if you absolutely must 149 // by statically casting the ScopedComPtr instance to the wrapped interface 150 // and then making the call... but generally that shouldn't be necessary. 151 BlockIUnknownMethods* operator->() const { 152 DCHECK(ptr_ != NULL); 153 return reinterpret_cast<BlockIUnknownMethods*>(ptr_); 154 } 155 156 // Pull in operator=() from the parent class. 157 using scoped_refptr<Interface>::operator=; 158 159 // static methods 160 iid()161 static const IID& iid() { 162 return *interface_id; 163 } 164 }; 165 166 } // namespace win 167 } // namespace base 168 169 #endif // BASE_WIN_SCOPED_COMPTR_H_ 170