// 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 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 (&__uuidof(nsInterface))> class ScopedNsPtr : public scoped_refptr { public: typedef scoped_refptr ParentClass; ScopedNsPtr() { } explicit ScopedNsPtr(nsInterface* p) : ParentClass(p) { } explicit ScopedNsPtr(const ScopedNsPtr& p) : ParentClass(p) { } ~ScopedNsPtr() { // We don't want the smart pointer class to be bigger than the pointer // it wraps. COMPILE_ASSERT(sizeof(ScopedNsPtr) == 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 nsresult QueryInterface(Query** p) { DCHECK(p != NULL); DCHECK(ptr_ != NULL); return ptr_->QueryInterface(Query::GetIID(), reinterpret_cast(p)); } template nsresult QueryInterface(const nsIID& iid, Query** p) { DCHECK(p != NULL); DCHECK(ptr_ != NULL); return ptr_->QueryInterface(iid, reinterpret_cast(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(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 my_identity; QueryInterface(my_identity.Receive()); ScopedNsPtr other_identity; other->QueryInterface(other_identity.Receive()); return static_cast(my_identity) == static_cast(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 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* operator->() const { DCHECK(ptr_ != NULL); return reinterpret_cast*>(ptr_); } // static methods static const nsIID& iid() { return *interface_id; } }; #endif // CHROME_FRAME_SCOPED_NS_PTR_WIN_H_