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