| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef BASE_WIN_SCOPED_COMPTR_H_ | 5 #ifndef BASE_WIN_SCOPED_COMPTR_H_ |
| 6 #define BASE_WIN_SCOPED_COMPTR_H_ | 6 #define BASE_WIN_SCOPED_COMPTR_H_ |
| 7 | 7 |
| 8 #include <unknwn.h> | 8 #include <unknwn.h> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/memory/ref_counted.h" | |
| 12 | 11 |
| 13 namespace base { | 12 namespace base { |
| 14 namespace win { | 13 namespace win { |
| 15 | 14 |
| 15 // DEPRECATED: Use Microsoft::WRL::ComPtr instead. |
| 16 // A fairly minimalistic smart class for COM interface pointers. | 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)> | 17 template <class Interface, const IID* interface_id = &__uuidof(Interface)> |
| 20 class ScopedComPtr : public scoped_refptr<Interface> { | 18 class ScopedComPtr { |
| 21 public: | 19 public: |
| 22 // Utility template to prevent users of ScopedComPtr from calling AddRef | 20 // Utility template to prevent users of ScopedComPtr from calling AddRef |
| 23 // and/or Release() without going through the ScopedComPtr class. | 21 // and/or Release() without going through the ScopedComPtr class. |
| 24 class BlockIUnknownMethods : public Interface { | 22 class BlockIUnknownMethods : public Interface { |
| 25 private: | 23 private: |
| 26 STDMETHOD(QueryInterface)(REFIID iid, void** object) = 0; | 24 STDMETHOD(QueryInterface)(REFIID iid, void** object) = 0; |
| 27 STDMETHOD_(ULONG, AddRef)() = 0; | 25 STDMETHOD_(ULONG, AddRef)() = 0; |
| 28 STDMETHOD_(ULONG, Release)() = 0; | 26 STDMETHOD_(ULONG, Release)() = 0; |
| 29 }; | 27 }; |
| 30 | 28 |
| 31 typedef scoped_refptr<Interface> ParentClass; | |
| 32 | |
| 33 ScopedComPtr() { | 29 ScopedComPtr() { |
| 34 } | 30 } |
| 35 | 31 |
| 36 explicit ScopedComPtr(Interface* p) : ParentClass(p) { | 32 explicit ScopedComPtr(Interface* p) : ptr_(p) { |
| 33 if (ptr_) |
| 34 ptr_->AddRef(); |
| 37 } | 35 } |
| 38 | 36 |
| 39 ScopedComPtr(const ScopedComPtr<Interface, interface_id>& p) | 37 ScopedComPtr(const ScopedComPtr<Interface, interface_id>& p) : ptr_(p.get()) { |
| 40 : ParentClass(p) { | 38 if (ptr_) |
| 39 ptr_->AddRef(); |
| 41 } | 40 } |
| 42 | 41 |
| 43 ~ScopedComPtr() { | 42 ~ScopedComPtr() { |
| 44 // We don't want the smart pointer class to be bigger than the pointer | 43 // We don't want the smart pointer class to be bigger than the pointer |
| 45 // it wraps. | 44 // it wraps. |
| 46 static_assert( | 45 static_assert( |
| 47 sizeof(ScopedComPtr<Interface, interface_id>) == sizeof(Interface*), | 46 sizeof(ScopedComPtr<Interface, interface_id>) == sizeof(Interface*), |
| 48 "ScopedComPtrSize"); | 47 "ScopedComPtrSize"); |
| 48 Release(); |
| 49 } | 49 } |
| 50 | 50 |
| 51 Interface* get() const { return ptr_; } |
| 52 |
| 53 explicit operator bool() const { return ptr_ != nullptr; } |
| 54 |
| 51 // Explicit Release() of the held object. Useful for reuse of the | 55 // Explicit Release() of the held object. Useful for reuse of the |
| 52 // ScopedComPtr instance. | 56 // ScopedComPtr instance. |
| 53 // Note that this function equates to IUnknown::Release and should not | 57 // Note that this function equates to IUnknown::Release and should not |
| 54 // be confused with e.g. unique_ptr::release(). | 58 // be confused with e.g. unique_ptr::release(). |
| 55 void Release() { | 59 void Release() { |
| 56 if (this->ptr_ != NULL) { | 60 Interface* temp = ptr_; |
| 57 this->ptr_->Release(); | 61 if (temp) { |
| 58 this->ptr_ = NULL; | 62 ptr_ = nullptr; |
| 63 temp->Release(); |
| 59 } | 64 } |
| 60 } | 65 } |
| 61 | 66 |
| 62 // Sets the internal pointer to NULL and returns the held object without | 67 // Sets the internal pointer to NULL and returns the held object without |
| 63 // releasing the reference. | 68 // releasing the reference. |
| 64 Interface* Detach() { | 69 Interface* Detach() { |
| 65 Interface* p = this->ptr_; | 70 Interface* p = ptr_; |
| 66 this->ptr_ = NULL; | 71 ptr_ = nullptr; |
| 67 return p; | 72 return p; |
| 68 } | 73 } |
| 69 | 74 |
| 70 // Accepts an interface pointer that has already been addref-ed. | 75 // Accepts an interface pointer that has already been addref-ed. |
| 71 void Attach(Interface* p) { | 76 void Attach(Interface* p) { |
| 72 DCHECK(!this->ptr_); | 77 DCHECK(!ptr_); |
| 73 this->ptr_ = p; | 78 ptr_ = p; |
| 74 } | 79 } |
| 75 | 80 |
| 76 // Retrieves the pointer address. | 81 // Retrieves the pointer address. |
| 77 // Used to receive object pointers as out arguments (and take ownership). | 82 // Used to receive object pointers as out arguments (and take ownership). |
| 78 // The function DCHECKs on the current value being NULL. | 83 // The function DCHECKs on the current value being NULL. |
| 79 // Usage: Foo(p.Receive()); | 84 // Usage: Foo(p.Receive()); |
| 80 Interface** Receive() { | 85 Interface** Receive() { |
| 81 DCHECK(!this->ptr_) << "Object leak. Pointer must be NULL"; | 86 DCHECK(!ptr_) << "Object leak. Pointer must be NULL"; |
| 82 return &this->ptr_; | 87 return &ptr_; |
| 83 } | 88 } |
| 84 | 89 |
| 85 // A convenience for whenever a void pointer is needed as an out argument. | 90 // A convenience for whenever a void pointer is needed as an out argument. |
| 86 void** ReceiveVoid() { | 91 void** ReceiveVoid() { |
| 87 return reinterpret_cast<void**>(Receive()); | 92 return reinterpret_cast<void**>(Receive()); |
| 88 } | 93 } |
| 89 | 94 |
| 90 template <class Query> | 95 template <class Query> |
| 91 HRESULT QueryInterface(Query** p) { | 96 HRESULT QueryInterface(Query** p) { |
| 92 DCHECK(p != NULL); | 97 DCHECK(p); |
| 93 DCHECK(this->ptr_ != NULL); | 98 DCHECK(ptr_); |
| 94 // IUnknown already has a template version of QueryInterface | 99 // IUnknown already has a template version of QueryInterface |
| 95 // so the iid parameter is implicit here. The only thing this | 100 // so the iid parameter is implicit here. The only thing this |
| 96 // function adds are the DCHECKs. | 101 // function adds are the DCHECKs. |
| 97 return this->ptr_->QueryInterface(p); | 102 return ptr_->QueryInterface(p); |
| 98 } | 103 } |
| 99 | 104 |
| 100 // QI for times when the IID is not associated with the type. | 105 // QI for times when the IID is not associated with the type. |
| 101 HRESULT QueryInterface(const IID& iid, void** obj) { | 106 HRESULT QueryInterface(const IID& iid, void** obj) { |
| 102 DCHECK(obj != NULL); | 107 DCHECK(obj); |
| 103 DCHECK(this->ptr_ != NULL); | 108 DCHECK(ptr_); |
| 104 return this->ptr_->QueryInterface(iid, obj); | 109 return ptr_->QueryInterface(iid, obj); |
| 105 } | 110 } |
| 106 | 111 |
| 107 // Queries |other| for the interface this object wraps and returns the | 112 // Queries |other| for the interface this object wraps and returns the |
| 108 // error code from the other->QueryInterface operation. | 113 // error code from the other->QueryInterface operation. |
| 109 HRESULT QueryFrom(IUnknown* object) { | 114 HRESULT QueryFrom(IUnknown* object) { |
| 110 DCHECK(object != NULL); | 115 DCHECK(object); |
| 111 return object->QueryInterface(Receive()); | 116 return object->QueryInterface(Receive()); |
| 112 } | 117 } |
| 113 | 118 |
| 114 // Convenience wrapper around CoCreateInstance | 119 // Convenience wrapper around CoCreateInstance |
| 115 HRESULT CreateInstance(const CLSID& clsid, IUnknown* outer = NULL, | 120 HRESULT CreateInstance(const CLSID& clsid, |
| 121 IUnknown* outer = nullptr, |
| 116 DWORD context = CLSCTX_ALL) { | 122 DWORD context = CLSCTX_ALL) { |
| 117 DCHECK(!this->ptr_); | 123 DCHECK(!ptr_); |
| 118 HRESULT hr = ::CoCreateInstance(clsid, outer, context, *interface_id, | 124 HRESULT hr = ::CoCreateInstance(clsid, outer, context, *interface_id, |
| 119 reinterpret_cast<void**>(&this->ptr_)); | 125 reinterpret_cast<void**>(&ptr_)); |
| 120 return hr; | 126 return hr; |
| 121 } | 127 } |
| 122 | 128 |
| 123 // Checks if the identity of |other| and this object is the same. | 129 // Checks if the identity of |other| and this object is the same. |
| 124 bool IsSameObject(IUnknown* other) { | 130 bool IsSameObject(IUnknown* other) { |
| 125 if (!other && !this->ptr_) | 131 if (!other && !ptr_) |
| 126 return true; | 132 return true; |
| 127 | 133 |
| 128 if (!other || !this->ptr_) | 134 if (!other || !ptr_) |
| 129 return false; | 135 return false; |
| 130 | 136 |
| 131 ScopedComPtr<IUnknown> my_identity; | 137 ScopedComPtr<IUnknown> my_identity; |
| 132 QueryInterface(my_identity.Receive()); | 138 QueryInterface(my_identity.Receive()); |
| 133 | 139 |
| 134 ScopedComPtr<IUnknown> other_identity; | 140 ScopedComPtr<IUnknown> other_identity; |
| 135 other->QueryInterface(other_identity.Receive()); | 141 other->QueryInterface(other_identity.Receive()); |
| 136 | 142 |
| 137 return my_identity == other_identity; | 143 return my_identity == other_identity; |
| 138 } | 144 } |
| 139 | 145 |
| 140 // Provides direct access to the interface. | 146 // Provides direct access to the interface. |
| 141 // Here we use a well known trick to make sure we block access to | 147 // 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: | 148 // IUnknown methods so that something bad like this doesn't happen: |
| 143 // ScopedComPtr<IUnknown> p(Foo()); | 149 // ScopedComPtr<IUnknown> p(Foo()); |
| 144 // p->Release(); | 150 // p->Release(); |
| 145 // ... later the destructor runs, which will Release() again. | 151 // ... later the destructor runs, which will Release() again. |
| 146 // and to get the benefit of the DCHECKs we add to QueryInterface. | 152 // 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 | 153 // There's still a way to call these methods if you absolutely must |
| 148 // by statically casting the ScopedComPtr instance to the wrapped interface | 154 // by statically casting the ScopedComPtr instance to the wrapped interface |
| 149 // and then making the call... but generally that shouldn't be necessary. | 155 // and then making the call... but generally that shouldn't be necessary. |
| 150 BlockIUnknownMethods* operator->() const { | 156 BlockIUnknownMethods* operator->() const { |
| 151 DCHECK(this->ptr_ != NULL); | 157 DCHECK(ptr_); |
| 152 return reinterpret_cast<BlockIUnknownMethods*>(this->ptr_); | 158 return reinterpret_cast<BlockIUnknownMethods*>(ptr_); |
| 153 } | 159 } |
| 154 | 160 |
| 155 // Pull in operator=() from the parent class. | 161 ScopedComPtr<Interface, interface_id>& operator=(Interface* rhs) { |
| 156 using scoped_refptr<Interface>::operator=; | 162 // AddRef first so that self assignment should work |
| 163 if (rhs) |
| 164 rhs->AddRef(); |
| 165 Interface* old_ptr = ptr_; |
| 166 ptr_ = rhs; |
| 167 if (old_ptr) |
| 168 old_ptr->Release(); |
| 169 return *this; |
| 170 } |
| 171 |
| 172 ScopedComPtr<Interface, interface_id>& operator=( |
| 173 const ScopedComPtr<Interface, interface_id>& rhs) { |
| 174 return *this = rhs.ptr_; |
| 175 } |
| 176 |
| 177 Interface& operator*() const { |
| 178 DCHECK(ptr_); |
| 179 return *ptr_; |
| 180 } |
| 181 |
| 182 bool operator==(const ScopedComPtr<Interface, interface_id>& rhs) const { |
| 183 return ptr_ == rhs.get(); |
| 184 } |
| 185 |
| 186 template <typename U> |
| 187 bool operator==(const ScopedComPtr<U>& rhs) const { |
| 188 return ptr_ == rhs.get(); |
| 189 } |
| 190 |
| 191 template <typename U> |
| 192 bool operator==(const U* rhs) const { |
| 193 return ptr_ == rhs; |
| 194 } |
| 195 |
| 196 bool operator!=(const ScopedComPtr<Interface, interface_id>& rhs) const { |
| 197 return ptr_ != rhs.get(); |
| 198 } |
| 199 |
| 200 template <typename U> |
| 201 bool operator!=(const ScopedComPtr<U>& rhs) const { |
| 202 return ptr_ != rhs.get(); |
| 203 } |
| 204 |
| 205 template <typename U> |
| 206 bool operator!=(const U* rhs) const { |
| 207 return ptr_ != rhs; |
| 208 } |
| 209 |
| 210 void swap(ScopedComPtr<Interface, interface_id>& r) { |
| 211 Interface* tmp = ptr_; |
| 212 ptr_ = r.ptr_; |
| 213 r.ptr_ = tmp; |
| 214 } |
| 157 | 215 |
| 158 // static methods | 216 // static methods |
| 159 | |
| 160 static const IID& iid() { | 217 static const IID& iid() { |
| 161 return *interface_id; | 218 return *interface_id; |
| 162 } | 219 } |
| 220 |
| 221 private: |
| 222 Interface* ptr_ = nullptr; |
| 163 }; | 223 }; |
| 164 | 224 |
| 225 template <typename T, typename U> |
| 226 bool operator==(const T* lhs, const ScopedComPtr<U>& rhs) { |
| 227 return lhs == rhs.get(); |
| 228 } |
| 229 |
| 230 template <typename T> |
| 231 bool operator==(const ScopedComPtr<T>& lhs, std::nullptr_t null) { |
| 232 return !static_cast<bool>(lhs); |
| 233 } |
| 234 |
| 235 template <typename T> |
| 236 bool operator==(std::nullptr_t null, const ScopedComPtr<T>& rhs) { |
| 237 return !static_cast<bool>(rhs); |
| 238 } |
| 239 |
| 240 template <typename T, typename U> |
| 241 bool operator!=(const T* lhs, const ScopedComPtr<U>& rhs) { |
| 242 return !operator==(lhs, rhs); |
| 243 } |
| 244 |
| 245 template <typename T> |
| 246 bool operator!=(const ScopedComPtr<T>& lhs, std::nullptr_t null) { |
| 247 return !operator==(lhs, null); |
| 248 } |
| 249 |
| 250 template <typename T> |
| 251 bool operator!=(std::nullptr_t null, const ScopedComPtr<T>& rhs) { |
| 252 return !operator==(null, rhs); |
| 253 } |
| 254 |
| 255 template <typename T> |
| 256 std::ostream& operator<<(std::ostream& out, const ScopedComPtr<T>& p) { |
| 257 return out << p.get(); |
| 258 } |
| 259 |
| 165 } // namespace win | 260 } // namespace win |
| 166 } // namespace base | 261 } // namespace base |
| 167 | 262 |
| 168 #endif // BASE_WIN_SCOPED_COMPTR_H_ | 263 #endif // BASE_WIN_SCOPED_COMPTR_H_ |
| OLD | NEW |