blob: 91780fd61bf0d69f775144487ae6ceaa2b5335ca [file] [log] [blame]
// 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_