/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * Scott Collins */ #ifndef nsCOMPtr_h___ #define nsCOMPtr_h___ /* Having problems? See the User Manual at: */ // Wrapping includes can speed up compiles (see "Large Scale C++ Software Design") #ifndef nsDebug_h___ #include "nsDebug.h" // for |NS_PRECONDITION| #endif #ifndef nsISupports_h___ #include "nsISupports.h" // for |nsresult|, |NS_ADDREF|, |NS_GET_IID| et al #endif #ifndef nscore_h__ #include "nscore.h" // for |NS_..._CAST|, |NS_EXPORT| #endif /* WARNING: This file defines several macros for internal use only. These macros begin with the prefix |NSCAP_|. Do not use these macros in your own code. They are for internal use only for cross-platform compatibility, and are subject to change without notice. */ /* Set up some |#define|s to turn off a couple of troublesome C++ features. Interestingly, none of the compilers barf on template stuff. These are set up automatically by the autoconf system for all Unixes. (Temporarily, I hope) I have to define them myself for Mac and Windows. */ // under Metrowerks (Mac), we don't have autoconf yet #ifdef __MWERKS__ #define HAVE_CPP_USING #define HAVE_CPP_EXPLICIT #define HAVE_CPP_BOOL #endif // under VC++ (Windows), we don't have autoconf yet #ifdef _MSC_VER #define HAVE_CPP_EXPLICIT #define HAVE_CPP_USING #if (_MSC_VER<1100) // before 5.0, VC++ couldn't handle explicit #undef HAVE_CPP_EXPLICIT #elif (_MSC_VER==1100) // VC++5.0 has an internal compiler error (sometimes) without this #undef HAVE_CPP_USING #endif #define NSCAP_FEATURE_INLINE_STARTASSIGNMENT // under VC++, we win by inlining StartAssignment // Also under VC++, at the highest warning level, we are overwhelmed with warnings // about (unused) inline functions being removed. This is to be expected with // templates, so we disable the warning. #pragma warning( disable: 4514 ) #endif #define NSCAP_FEATURE_FACTOR_DESTRUCTOR #ifdef NS_DEBUG #define NSCAP_FEATURE_TEST_DONTQUERY_CASES #define NSCAP_FEATURE_DEBUG_PTR_TYPES #endif /* |...TEST_DONTQUERY_CASES| and |...DEBUG_PTR_TYPES| introduce some code that is problematic on a select few of our platforms, e.g., QNX. Therefore, I'm providing a mechanism by which these features can be explicitly disabled from the command-line. */ #ifdef NSCAP_DISABLE_TEST_DONTQUERY_CASES #undef NSCAP_FEATURE_TEST_DONTQUERY_CASES #endif #if defined(NSCAP_DISABLE_DEBUG_PTR_TYPES) || !defined(NS_DEBUG) #undef NSCAP_FEATURE_DEBUG_PTR_TYPES #endif #ifdef NSCAP_FEATURE_DEBUG_PTR_TYPES #undef NSCAP_FEATURE_FACTOR_DESTRUCTOR #endif /* If the compiler doesn't support |explicit|, we'll just make it go away, trusting that the builds under compilers that do have it will keep us on the straight and narrow. */ #ifndef HAVE_CPP_EXPLICIT #define explicit #endif #ifdef HAVE_CPP_BOOL typedef bool NSCAP_BOOL; #else typedef PRBool NSCAP_BOOL; #endif #ifdef NSCAP_FEATURE_DEBUG_MACROS #define NSCAP_ADDREF(ptr) NS_ADDREF(ptr) #define NSCAP_RELEASE(ptr) NS_RELEASE(ptr) #else #define NSCAP_ADDREF(ptr) (ptr)->AddRef() #define NSCAP_RELEASE(ptr) (ptr)->Release() #endif /* WARNING: VC++4.2 is very picky. To compile under VC++4.2, the classes must be defined in an order that satisfies: nsDerivedSafe < nsCOMPtr nsDontAddRef < nsCOMPtr nsCOMPtr < nsGetterAddRefs The other compilers probably won't complain, so please don't reorder these classes, on pain of breaking 4.2 compatibility. */ template class nsDerivedSafe : public T /* No client should ever see or have to type the name of this class. It is the artifact that makes it a compile-time error to call |AddRef| and |Release| on a |nsCOMPtr|. DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. See |nsCOMPtr::operator->|, |nsCOMPtr::operator*|, et al. This type should be a nested class inside |nsCOMPtr|. */ { private: #ifdef HAVE_CPP_USING using T::AddRef; using T::Release; #else NS_IMETHOD_(nsrefcnt) AddRef(void); NS_IMETHOD_(nsrefcnt) Release(void); #endif void operator delete( void*, size_t ); // NOT TO BE IMPLEMENTED // declaring |operator delete| private makes calling delete on an interface pointer a compile error nsDerivedSafe& operator=( const T& ); // NOT TO BE IMPLEMENTED // you may not call |operator=()| through a dereferenced |nsCOMPtr|, because you'd get the wrong one /* Compiler warnings and errors: nsDerivedSafe operator=() hides inherited operator=(). If you see that, that means somebody checked in a (XP)COM interface class that declares an |operator=()|, and that's _bad_. So bad, in fact, that this declaration exists explicitly to stop people from doing it. */ }; #if !defined(HAVE_CPP_USING) && defined(NEED_CPP_UNUSED_IMPLEMENTATIONS) template nsrefcnt nsDerivedSafe::AddRef() { return 0; } template nsrefcnt nsDerivedSafe::Release() { return 0; } #endif /* There used to be machinery to allow |dont_QueryInterface()| to work, but since it is now equivalent to using a raw pointer ... all that machinery has gone away. For pointer arguments, the following definition should optimize away. This is better than using a |#define| because it is scoped. */ template inline T* dont_QueryInterface( T* expr ) { return expr; } class nsCOMPtr_helper /* An |nsCOMPtr_helper| transforms commonly called getters into typesafe forms that are more convenient to call, and more efficient to use with |nsCOMPtr|s. Good candidates for helpers are |QueryInterface()|, |CreateInstance()|, etc. Here are the rules for a helper: - it implements operator() to produce an interface pointer - (except for its name) operator() is a valid [XP]COM `getter' - that interface pointer it returns is already |AddRef()|ed (as from any good getter) - it matches the type requested with the supplied |nsIID| argument - its constructor provides an optional |nsresult*| that |operator()| can fill in with an error when it is executed See |class nsQueryInterface| for an example. */ { public: virtual nsresult operator()( const nsIID&, void** ) const = 0; }; class NS_EXPORT nsQueryInterface : public nsCOMPtr_helper { public: nsQueryInterface( nsISupports* aRawPtr, nsresult* error ) : mRawPtr(aRawPtr), mErrorPtr(error) { // nothing else to do here } virtual nsresult operator()( const nsIID& aIID, void** ) const; private: nsISupports* mRawPtr; nsresult* mErrorPtr; }; inline const nsQueryInterface do_QueryInterface( nsISupports* aRawPtr, nsresult* error = 0 ) { return nsQueryInterface(aRawPtr, error); } /** * |null_nsCOMPtr| is deprecated. Please use the value |0| instead. * |#define|s are bad, because they aren't scoped. But I can't replace * this definition with an inline, because only a compile-time |0| gets * magically converted to arbitrary pointer types. This doesn't automatically * happen for just any |const int| with the value |0|. * * Ergo: we really want to eliminate all uses of |null_nsCOMPtr()| in favor of * |0|. */ #define null_nsCOMPtr() (0) template struct nsDontAddRef /* ...cooperates with |nsCOMPtr| to allow you to assign in a pointer _without_ |AddRef|ing it. You would rarely use this directly, but rather through the machinery of |getter_AddRefs| in the argument list to functions that |AddRef| their results before returning them to the caller. DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| or |dont_AddRef()| instead. See also |getter_AddRefs()|, |dont_AddRef()|, and |class nsGetterAddRefs|. This type should be a nested class inside |nsCOMPtr|. Yes, |nsDontAddRef| could have been implemented as an |nsCOMPtr_helper| to avoid adding specialized machinery to |nsCOMPtr| ... but this is the simplest case, and perhaps worth the savings in time and space that its specific implementation affords over the more general solution offered by |nsCOMPtr_helper|. */ { explicit nsDontAddRef( T* aRawPtr ) : mRawPtr(aRawPtr) { // nothing else to do here } T* mRawPtr; }; template inline const nsDontAddRef getter_AddRefs( T* aRawPtr ) /* ...makes typing easier, because it deduces the template type, e.g., you write |dont_AddRef(fooP)| instead of |nsDontAddRef(fooP)|. */ { return nsDontAddRef(aRawPtr); } template inline const nsDontAddRef dont_AddRef( T* aRawPtr ) { return nsDontAddRef(aRawPtr); } class nsCOMPtr_base /* ...factors implementation for all template versions of |nsCOMPtr|. This should really be an |nsCOMPtr|, but this wouldn't work because unlike the Here's the way people normally do things like this template class Foo { ... }; template <> class Foo { ... }; template class Foo : private Foo { ... }; */ { public: nsCOMPtr_base( nsISupports* rawPtr = 0 ) : mRawPtr(rawPtr) { // nothing else to do here } #ifdef NSCAP_FEATURE_FACTOR_DESTRUCTOR NS_EXPORT ~nsCOMPtr_base(); #endif NS_EXPORT void assign_with_AddRef( nsISupports* ); NS_EXPORT void assign_from_helper( const nsCOMPtr_helper&, const nsIID& ); NS_EXPORT void** begin_assignment(); protected: nsISupports* mRawPtr; void assign_assuming_AddRef( nsISupports* newPtr ) { /* |AddRef()|ing the new value (before entering this function) before |Release()|ing the old lets us safely ignore the self-assignment case. We must, however, be careful only to |Release()| _after_ doing the assignment, in case the |Release()| leads to our _own_ destruction, which would, in turn, cause an incorrect second |Release()| of our old pointer. Thank waterson@netscape.com for discovering this. */ nsISupports* oldPtr = mRawPtr; mRawPtr = newPtr; if ( oldPtr ) NSCAP_RELEASE(oldPtr); } }; // template class nsGetterAddRefs; template class nsCOMPtr #ifndef NSCAP_FEATURE_DEBUG_PTR_TYPES : private nsCOMPtr_base #endif { #ifdef NSCAP_FEATURE_DEBUG_PTR_TYPES private: void assign_with_AddRef( nsISupports* ); void assign_from_helper( const nsCOMPtr_helper&, const nsIID& ); void** begin_assignment(); void assign_assuming_AddRef( T* newPtr ) { T* oldPtr = mRawPtr; mRawPtr = newPtr; if ( oldPtr ) NSCAP_RELEASE(oldPtr); } private: T* mRawPtr; #define NSCAP_CTOR_BASE(x) mRawPtr(x) #else #define NSCAP_CTOR_BASE(x) nsCOMPtr_base(x) #endif public: typedef T element_type; #ifndef NSCAP_FEATURE_FACTOR_DESTRUCTOR ~nsCOMPtr() { if ( mRawPtr ) NSCAP_RELEASE(mRawPtr); } #endif #ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES void Assert_NoQueryNeeded() { if ( mRawPtr ) { T* query_result = 0; nsresult status = CallQueryInterface(mRawPtr, &query_result); NS_ASSERTION(query_result == mRawPtr, "QueryInterface needed"); if ( NS_SUCCEEDED(status) ) NSCAP_RELEASE(query_result); } } #define NSCAP_ASSERT_NO_QUERY_NEEDED(); Assert_NoQueryNeeded(); #else #define NSCAP_ASSERT_NO_QUERY_NEEDED(); #endif // Constructors nsCOMPtr() : NSCAP_CTOR_BASE(0) // default constructor { // nothing else to do here } nsCOMPtr( const nsCOMPtr& aSmartPtr ) : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr) // copy-constructor { if ( mRawPtr ) NSCAP_ADDREF(mRawPtr); } nsCOMPtr( T* aRawPtr ) : NSCAP_CTOR_BASE(aRawPtr) // construct from a raw pointer (of the right type) { if ( mRawPtr ) NSCAP_ADDREF(mRawPtr); NSCAP_ASSERT_NO_QUERY_NEEDED(); } nsCOMPtr( const nsDontAddRef& aSmartPtr ) : NSCAP_CTOR_BASE(aSmartPtr.mRawPtr) // construct from |dont_AddRef(expr)| { NSCAP_ASSERT_NO_QUERY_NEEDED(); } nsCOMPtr( const nsCOMPtr_helper& helper ) : NSCAP_CTOR_BASE(0) // ...and finally, anything else we might need to construct from // can exploit the |nsCOMPtr_helper| facility { assign_from_helper(helper, NS_GET_IID(T)); NSCAP_ASSERT_NO_QUERY_NEEDED(); } // Assignment operators nsCOMPtr& operator=( const nsCOMPtr& rhs ) // copy assignment operator { assign_with_AddRef(rhs.mRawPtr); return *this; } nsCOMPtr& operator=( T* rhs ) // assign from a raw pointer (of the right type) { assign_with_AddRef(rhs); NSCAP_ASSERT_NO_QUERY_NEEDED(); return *this; } nsCOMPtr& operator=( const nsDontAddRef& rhs ) // assign from |dont_AddRef(expr)| { assign_assuming_AddRef(rhs.mRawPtr); NSCAP_ASSERT_NO_QUERY_NEEDED(); return *this; } nsCOMPtr& operator=( const nsCOMPtr_helper& rhs ) // ...and finally, anything else we might need to assign from // can exploit the |nsCOMPtr_helper| facility. { assign_from_helper(rhs, NS_GET_IID(T)); NSCAP_ASSERT_NO_QUERY_NEEDED(); return *this; } // Other pointer operators nsDerivedSafe* get() const /* Prefer the implicit conversion provided automatically by |operator nsDerivedSafe*| to deny clients the use of |AddRef| and |Release|. */ { return NS_REINTERPRET_CAST(nsDerivedSafe*, mRawPtr); } operator nsDerivedSafe*() const /* ...makes an |nsCOMPtr| act like its underlying raw pointer type (except against |AddRef()|, |Release()|, and |delete|) whenever it is used in a context where a raw pointer is expected. It is this operator that makes an |nsCOMPtr| substitutable for a raw pointer. Prefer the implicit use of this operator to calling |get()|, except where necessary to resolve ambiguity. */ { return get(); } nsDerivedSafe* operator->() const { NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator->()."); return get(); } nsDerivedSafe& operator*() const { NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator*()."); return *get(); } #if 0 private: friend class nsGetterAddRefs; #endif T** StartAssignment() { #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT return NS_REINTERPRET_CAST(T**, begin_assignment()); #else assign_assuming_AddRef(0); return NS_REINTERPRET_CAST(T**, &mRawPtr); #endif } }; /* Specializing |nsCOMPtr| for |nsISupports| allows us to */ // template <> class nsCOMPtr : private nsCOMPtr_base { public: typedef nsISupports element_type; #ifndef NSCAP_FEATURE_FACTOR_DESTRUCTOR ~nsCOMPtr() { if ( mRawPtr ) NSCAP_RELEASE(mRawPtr); } #endif // Constructors nsCOMPtr() : nsCOMPtr_base(0) // default constructor { // nothing else to do here } nsCOMPtr( const nsCOMPtr& aSmartPtr ) : nsCOMPtr_base(aSmartPtr.mRawPtr) // copy constructor { if ( mRawPtr ) NSCAP_ADDREF(mRawPtr); } nsCOMPtr( nsISupports* aRawPtr ) : nsCOMPtr_base(aRawPtr) // construct from a raw pointer (of the right type) { if ( mRawPtr ) NSCAP_ADDREF(mRawPtr); } nsCOMPtr( const nsDontAddRef& aSmartPtr ) : nsCOMPtr_base(aSmartPtr.mRawPtr) // construct from |dont_AddRef(expr)| { // nothing else to do here } nsCOMPtr( const nsCOMPtr_helper& helper ) : nsCOMPtr_base(0) // ...and finally, anything else we might need to construct from // can exploit the |nsCOMPtr_helper| facility { assign_from_helper(helper, NS_GET_IID(nsISupports)); } // Assignment operators nsCOMPtr& operator=( const nsCOMPtr& rhs ) // copy assignment operator { assign_with_AddRef(rhs.mRawPtr); return *this; } nsCOMPtr& operator=( nsISupports* rhs ) // assign from a raw pointer (of the right type) { assign_with_AddRef(rhs); return *this; } nsCOMPtr& operator=( const nsDontAddRef& rhs ) // assign from |dont_AddRef(expr)| { assign_assuming_AddRef(rhs.mRawPtr); return *this; } nsCOMPtr& operator=( const nsCOMPtr_helper& rhs ) // ...and finally, anything else we might need to assign from // can exploit the |nsCOMPtr_helper| facility. { assign_from_helper(rhs, NS_GET_IID(nsISupports)); return *this; } // Other pointer operators nsDerivedSafe* get() const /* Prefer the implicit conversion provided automatically by |operator nsDerivedSafe*| to deny clients the use of |AddRef| and |Release|. */ { return NS_REINTERPRET_CAST(nsDerivedSafe*, mRawPtr); } operator nsDerivedSafe*() const /* ...makes an |nsCOMPtr| act like its underlying raw pointer type (except against |AddRef()|, |Release()|, and |delete|) whenever it is used in a context where a raw pointer is expected. It is this operator that makes an |nsCOMPtr| substitutable for a raw pointer. Prefer the implicit use of this operator to calling |get()|, except where necessary to resolve ambiguity. */ { return get(); } nsDerivedSafe* operator->() const { NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator->()."); return get(); } nsDerivedSafe& operator*() const { NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator*()."); return *get(); } #if 0 private: friend class nsGetterAddRefs; #endif nsISupports** StartAssignment() { #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT return NS_REINTERPRET_CAST(nsISupports**, begin_assignment()); #else assign_assuming_AddRef(0); return NS_REINTERPRET_CAST(nsISupports**, &mRawPtr); #endif } }; #ifdef NSCAP_FEATURE_DEBUG_PTR_TYPES template void nsCOMPtr::assign_with_AddRef( nsISupports* rawPtr ) { if ( rawPtr ) NSCAP_ADDREF(rawPtr); assign_assuming_AddRef(NS_REINTERPRET_CAST(T*, rawPtr)); } template void nsCOMPtr::assign_from_helper( const nsCOMPtr_helper& helper, const nsIID& aIID ) { T* newRawPtr; if ( !NS_SUCCEEDED( helper(aIID, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) newRawPtr = 0; assign_assuming_AddRef(newRawPtr); } template void** nsCOMPtr::begin_assignment() { assign_assuming_AddRef(0); return NS_REINTERPRET_CAST(void**, &mRawPtr); } #endif template class nsGetterAddRefs /* ... This class is designed to be used for anonymous temporary objects in the argument list of calls that return COM interface pointers, e.g., nsCOMPtr fooP; ...->QueryInterface(iid, getter_AddRefs(fooP)) DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead. When initialized with a |nsCOMPtr|, as in the example above, it returns a |void**| (or |T**| if needed) that the outer call (|QueryInterface| in this case) can fill in. This type should be a nested class inside |nsCOMPtr|. */ { public: explicit nsGetterAddRefs( nsCOMPtr& aSmartPtr ) : mTargetSmartPtr(aSmartPtr) { // nothing else to do } #if 0 #ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES ~nsGetterAddRefs() { mTargetSmartPtr.Assert_NoQueryNeeded(); } #endif #endif operator void**() { return NS_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment()); } operator T**() { return mTargetSmartPtr.StartAssignment(); } operator nsISupports**() { return NS_REINTERPRET_CAST(nsISupports**, mTargetSmartPtr.StartAssignment()); } T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); } private: nsCOMPtr& mTargetSmartPtr; }; // template <> class nsGetterAddRefs { public: explicit nsGetterAddRefs( nsCOMPtr& aSmartPtr ) : mTargetSmartPtr(aSmartPtr) { // nothing else to do } operator void**() { return NS_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment()); } operator nsISupports**() { return mTargetSmartPtr.StartAssignment(); } nsISupports*& operator*() { return *(mTargetSmartPtr.StartAssignment()); } private: nsCOMPtr& mTargetSmartPtr; }; template inline nsGetterAddRefs getter_AddRefs( nsCOMPtr& aSmartPtr ) /* Used around a |nsCOMPtr| when ...makes the class |nsGetterAddRefs| invisible. */ { return nsGetterAddRefs(aSmartPtr); } class NSCAP_Zero; template inline NSCAP_BOOL operator==( const nsCOMPtr& lhs, const nsCOMPtr& rhs ) { return NS_STATIC_CAST(const void*, lhs.get()) == NS_STATIC_CAST(const void*, rhs.get()); } template inline NSCAP_BOOL operator==( const nsCOMPtr& lhs, const U* rhs ) { return NS_STATIC_CAST(const void*, lhs.get()) == NS_STATIC_CAST(const void*, rhs); } template inline NSCAP_BOOL operator==( const U* lhs, const nsCOMPtr& rhs ) { return NS_STATIC_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); } template inline NSCAP_BOOL operator==( const nsCOMPtr& lhs, NSCAP_Zero* rhs ) // specifically to allow |smartPtr == 0| { return NS_STATIC_CAST(const void*, lhs.get()) == NS_REINTERPRET_CAST(const void*, rhs); } template inline NSCAP_BOOL operator==( NSCAP_Zero* lhs, const nsCOMPtr& rhs ) // specifically to allow |0 == smartPtr| { return NS_REINTERPRET_CAST(const void*, lhs) == NS_STATIC_CAST(const void*, rhs.get()); } template inline NSCAP_BOOL operator!=( const nsCOMPtr& lhs, const nsCOMPtr& rhs ) { return NS_STATIC_CAST(const void*, lhs.get()) != NS_STATIC_CAST(const void*, rhs.get()); } template inline NSCAP_BOOL operator!=( const nsCOMPtr& lhs, const U* rhs ) { return NS_STATIC_CAST(const void*, lhs.get()) != NS_STATIC_CAST(const void*, rhs); } template inline NSCAP_BOOL operator!=( const U* lhs, const nsCOMPtr& rhs ) { return NS_STATIC_CAST(const void*, lhs) != NS_STATIC_CAST(const void*, rhs.get()); } template inline NSCAP_BOOL operator!=( const nsCOMPtr& lhs, NSCAP_Zero* rhs ) // specifically to allow |smartPtr != 0| { return NS_STATIC_CAST(const void*, lhs.get()) != NS_REINTERPRET_CAST(const void*, rhs); } template inline NSCAP_BOOL operator!=( NSCAP_Zero* lhs, const nsCOMPtr& rhs ) // specifically to allow |0 != smartPtr| { return NS_REINTERPRET_CAST(const void*, lhs) != NS_STATIC_CAST(const void*, rhs.get()); } inline NSCAP_BOOL SameCOMIdentity( nsISupports* lhs, nsISupports* rhs ) { return nsCOMPtr( do_QueryInterface(lhs) ) == nsCOMPtr( do_QueryInterface(rhs) ); } #endif // !defined(nsCOMPtr_h___)