| // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_FRAME_SCOPED_NS_PTR_WIN_H_ |
| #define CHROME_FRAME_SCOPED_NS_PTR_WIN_H_ |
| |
| #include "base/logging.h" |
| #include "base/ref_counted.h" |
| |
| #include "third_party/xulrunner-sdk/win/include/xpcom/nsISupports.h" |
| |
| |
| // Utility template to prevent users of ScopedNsPtr from calling AddRef and/or |
| // Release() without going through the ScopedNsPtr class. |
| template <class nsInterface> |
| class BlocknsISupportsMethods : public nsInterface { |
| private: |
| NS_IMETHOD QueryInterface(REFNSIID iid, void** object) = 0; |
| NS_IMETHOD_(nsrefcnt) AddRef() = 0; |
| NS_IMETHOD_(nsrefcnt) Release() = 0; |
| }; |
| |
| // A smart pointer class for nsISupports. |
| // Based on ScopedComPtr. |
| // We have our own class instead of nsCOMPtr. nsCOMPtr has parts of its |
| // implementation in the xpcomglue lib which we can't use since that lib |
| // is built with incompatible build flags to ours. |
| template <class nsInterface, |
| const nsIID* interface_id = |
| reinterpret_cast<const nsIID*>(&__uuidof(nsInterface))> |
| class ScopedNsPtr : public scoped_refptr<nsInterface> { |
| public: |
| typedef scoped_refptr<nsInterface> ParentClass; |
| |
| ScopedNsPtr() { |
| } |
| |
| explicit ScopedNsPtr(nsInterface* p) : ParentClass(p) { |
| } |
| |
| explicit ScopedNsPtr(const ScopedNsPtr<nsInterface, interface_id>& p) |
| : ParentClass(p) { |
| } |
| |
| ~ScopedNsPtr() { |
| // We don't want the smart pointer class to be bigger than the pointer |
| // it wraps. |
| COMPILE_ASSERT(sizeof(ScopedNsPtr<nsInterface, interface_id>) == |
| sizeof(nsInterface*), ScopedNsPtrSize); |
| } |
| |
| // Explicit Release() of the held object. Useful for reuse of the |
| // ScopedNsPtr instance. |
| // Note that this function equates to nsISupports::Release and should not |
| // be confused with e.g. scoped_ptr::release(). |
| void Release() { |
| if (ptr_ != NULL) { |
| ptr_->Release(); |
| ptr_ = NULL; |
| } |
| } |
| |
| // Sets the internal pointer to NULL and returns the held object without |
| // releasing the reference. |
| nsInterface* Detach() { |
| nsInterface* p = ptr_; |
| ptr_ = NULL; |
| return p; |
| } |
| |
| // Accepts an interface pointer that has already been addref-ed. |
| void Attach(nsInterface* p) { |
| DCHECK(ptr_ == NULL); |
| ptr_ = p; |
| } |
| |
| // Retrieves the pointer address. |
| // Used to receive object pointers as out arguments (and take ownership). |
| // The function DCHECKs on the current value being NULL. |
| // Usage: Foo(p.Receive()); |
| nsInterface** Receive() { |
| DCHECK(ptr_ == NULL) << "Object leak. Pointer must be NULL"; |
| return &ptr_; |
| } |
| |
| template <class Query> |
| nsresult QueryInterface(Query** p) { |
| DCHECK(p != NULL); |
| DCHECK(ptr_ != NULL); |
| return ptr_->QueryInterface(Query::GetIID(), reinterpret_cast<void**>(p)); |
| } |
| |
| template <class Query> |
| nsresult QueryInterface(const nsIID& iid, Query** p) { |
| DCHECK(p != NULL); |
| DCHECK(ptr_ != NULL); |
| return ptr_->QueryInterface(iid, reinterpret_cast<void**>(p)); |
| } |
| |
| // Queries |other| for the interface this object wraps and returns the |
| // error code from the other->QueryInterface operation. |
| nsresult QueryFrom(nsISupports* other) { |
| DCHECK(other != NULL); |
| return other->QueryInterface(iid(), reinterpret_cast<void**>(Receive())); |
| } |
| |
| // Checks if the identity of |other| and this object is the same. |
| bool IsSameObject(nsISupports* other) { |
| if (!other && !ptr_) |
| return true; |
| |
| if (!other || !ptr_) |
| return false; |
| |
| nsIID iid = NS_ISUPPORTS_IID; |
| ScopedNsPtr<nsISupports, iid> my_identity; |
| QueryInterface(my_identity.Receive()); |
| |
| ScopedNsPtr<nsISupports, iid> other_identity; |
| other->QueryInterface(other_identity.Receive()); |
| |
| return static_cast<nsISupports*>(my_identity) == |
| static_cast<nsISupports*>(other_identity); |
| } |
| |
| // Provides direct access to the interface. |
| // Here we use a well known trick to make sure we block access to |
| // IUknown methods so that something bad like this doesn't happen: |
| // ScopedNsPtr<nsISupports> p(Foo()); |
| // p->Release(); |
| // ... later the destructor runs, which will Release() again. |
| // and to get the benefit of the DCHECKs we add to QueryInterface. |
| // There's still a way to call these methods if you absolutely must |
| // by statically casting the ScopedNsPtr instance to the wrapped interface |
| // and then making the call... but generally that shouldn't be necessary. |
| BlocknsISupportsMethods<nsInterface>* operator->() const { |
| DCHECK(ptr_ != NULL); |
| return reinterpret_cast<BlocknsISupportsMethods<nsInterface>*>(ptr_); |
| } |
| |
| // static methods |
| |
| static const nsIID& iid() { |
| return *interface_id; |
| } |
| }; |
| |
| #endif // CHROME_FRAME_SCOPED_NS_PTR_WIN_H_ |