/** @file * MS COM / XPCOM Abstraction Layer: * Smart COM pointer classes declaration */ /* * Copyright (C) 2006-2007 Sun Microsystems, Inc. * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. * * The contents of this file may alternatively be used under the terms * of the Common Development and Distribution License Version 1.0 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the * VirtualBox OSE distribution, in which case the provisions of the * CDDL are applicable instead of those of the GPL. * * You may elect to license modified versions of this file under the * terms and conditions of either the GPL or the CDDL or both. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 USA or visit http://www.sun.com if you need * additional information or have any questions. */ #ifndef ___VBox_com_ptr_h #define ___VBox_com_ptr_h /* Make sure all the stdint.h macros are included - must come first! */ #ifndef __STDC_LIMIT_MACROS # define __STDC_LIMIT_MACROS #endif #ifndef __STDC_CONSTANT_MACROS # define __STDC_CONSTANT_MACROS #endif #if !defined (VBOX_WITH_XPCOM) #include #ifndef _ATL_IIDOF # define _ATL_IIDOF(c) __uuidof(c) #endif #else /* !defined (VBOX_WITH_XPCOM) */ #include #include #include #include #include #include #include // official XPCOM headers don't define it yet #define IPC_DCONNECTSERVICE_CONTRACTID \ "@mozilla.org/ipc/dconnect-service;1" #endif /* !defined (VBOX_WITH_XPCOM) */ #include #include /** * Strong referencing operators. Used as a second argument to ComPtr<>/ComObjPtr<>. */ template class ComStrongRef { protected: static void addref (C *p) { p->AddRef(); } static void release (C *p) { p->Release(); } }; /** * Weak referencing operators. Used as a second argument to ComPtr<>/ComObjPtr<>. */ template class ComWeakRef { protected: static void addref (C *p) {} static void release (C *p) {} }; /** * Returns @c true if two interface pointers are equal. * * According to the COM Identity Rule, interface pointers are considered to be * equal if and only if IUnknown pointers queried on these interfaces pointers * are equal (e.g. have the same binary value). Equal interface pointers * represent the same object even if they are pointers to different interfaces. * * @param I1 Class of the first interface pointer (must be derived from * IUnknown). * @param I2 Class of the second interface pointer (must be derived from * IUnknown). */ template inline bool ComPtrEquals (I1 *aThis, I2 *aThat) { IUnknown *thatUnk = NULL, *thisUnk = NULL; if (aThat) aThat->QueryInterface (COM_IIDOF (IUnknown), (void **) &thatUnk); if (aThis) aThis->QueryInterface (COM_IIDOF (IUnknown), (void **) &thisUnk); bool equal = thisUnk == thatUnk; if (thisUnk) thisUnk->Release(); if (thatUnk) thatUnk->Release(); return equal; } /* specialization for */ template inline bool ComPtrEquals (I1 *aThis, IUnknown *aThat) { IUnknown *thisUnk = NULL; if (aThis) aThis->QueryInterface (COM_IIDOF (IUnknown), (void **) &thisUnk); bool equal = thisUnk == aThat; if (thisUnk) thisUnk->Release(); return equal; } /** Specialization for */ template inline bool ComPtrEquals (IUnknown *aThis, I2 *aThat) { IUnknown *thatUnk = NULL; if (aThat) aThat->QueryInterface (COM_IIDOF (IUnknown), (void **) &thatUnk); bool equal = aThis == thatUnk; if (thatUnk) thatUnk->Release(); return equal; } /* specialization for IUnknown */ template<> inline bool ComPtrEquals (IUnknown *aThis, IUnknown *aThat) { return aThis == aThat; } /** * Base template for smart COM pointers. Not intended to be used directly. */ template class RefOps = ComStrongRef> class ComPtrBase : protected RefOps { public: /* special template to disable AddRef()/Release() */ template class NoAddRefRelease : public I { private: #if !defined (VBOX_WITH_XPCOM) STDMETHOD_(ULONG, AddRef)() = 0; STDMETHOD_(ULONG, Release)() = 0; #else /* !defined (VBOX_WITH_XPCOM) */ NS_IMETHOD_(nsrefcnt) AddRef(void) = 0; NS_IMETHOD_(nsrefcnt) Release(void) = 0; #endif /* !defined (VBOX_WITH_XPCOM) */ }; protected: ComPtrBase () : p (NULL) {} ComPtrBase (const ComPtrBase &that) : p (that.p) { addref(); } ComPtrBase (C *that_p) : p (that_p) { addref(); } ~ComPtrBase() { release(); } ComPtrBase &operator= (const ComPtrBase &that) { safe_assign (that.p); return *this; } ComPtrBase &operator= (C *that_p) { safe_assign (that_p); return *this; } public: void setNull() { release(); p = NULL; } bool isNull() const { return (p == NULL); } bool operator! () const { return isNull(); } bool operator< (C* that_p) const { return p < that_p; } bool operator== (C* that_p) const { return p == that_p; } template bool equalsTo (I *aThat) const { return ComPtrEquals (p, aThat); } template bool equalsTo (const ComPtrBase &oc) const { return equalsTo ((OC *) oc); } /** Intended to pass instances as in parameters to interface methods */ operator C* () const { return p; } /** * Derefereces the instance (redirects the -> operator to the managed * pointer). */ NoAddRefRelease *operator-> () const { AssertMsg (p, ("Managed pointer must not be null\n")); return (NoAddRefRelease *) p; } template HRESULT queryInterfaceTo (I **pp) const { if (pp) { if (p) { return p->QueryInterface (COM_IIDOF (I), (void **) pp); } else { *pp = NULL; return S_OK; } } return E_INVALIDARG; } /** Intended to pass instances as out parameters to interface methods */ C **asOutParam() { setNull(); return &p; } private: void addref() { if (p) RefOps ::addref (p); } void release() { if (p) RefOps ::release (p); } void safe_assign (C *that_p) { /* be aware of self-assignment */ if (that_p) RefOps ::addref (that_p); release(); p = that_p; } C *p; }; /** * Smart COM pointer wrapper that automatically manages refcounting of * interface pointers. * * @param I COM interface class */ template class RefOps = ComStrongRef> class ComPtr : public ComPtrBase { typedef ComPtrBase Base; public: ComPtr () : Base() {} ComPtr (const ComPtr &that) : Base (that) {} ComPtr &operator= (const ComPtr &that) { Base::operator= (that); return *this; } template ComPtr (OI *that_p) : Base () { operator= (that_p); } /* specialization for I */ ComPtr (I *that_p) : Base (that_p) {} template ComPtr (const ComPtr &oc) : Base () { operator= ((OC *) oc); } template ComPtr &operator= (OI *that_p) { if (that_p) that_p->QueryInterface (COM_IIDOF (I), (void **) Base::asOutParam()); else Base::setNull(); return *this; } /* specialization for I */ ComPtr &operator=(I *that_p) { Base::operator= (that_p); return *this; } template ComPtr &operator= (const ComPtr &oc) { return operator= ((OC *) oc); } /** * Createas an in-process object of the given class ID and starts to * manage a reference to the created object in case of success. */ HRESULT createInprocObject (const CLSID &clsid) { HRESULT rc; I *obj = NULL; #if !defined (VBOX_WITH_XPCOM) rc = CoCreateInstance (clsid, NULL, CLSCTX_INPROC_SERVER, _ATL_IIDOF (I), (void **) &obj); #else /* !defined (VBOX_WITH_XPCOM) */ nsCOMPtr manager; rc = NS_GetComponentManager (getter_AddRefs (manager)); if (SUCCEEDED (rc)) rc = manager->CreateInstance (clsid, nsnull, NS_GET_IID (I), (void **) &obj); #endif /* !defined (VBOX_WITH_XPCOM) */ *this = obj; if (SUCCEEDED (rc)) obj->Release(); return rc; } /** * Createas a local (out-of-process) object of the given class ID and starts * to manage a reference to the created object in case of success. * * Note: In XPCOM, the out-of-process functionality is currently emulated * through in-process wrapper objects (that start a dedicated process and * redirect all object requests to that process). For this reason, this * method is fully equivalent to #createInprocObject() for now. */ HRESULT createLocalObject (const CLSID &clsid) { #if !defined (VBOX_WITH_XPCOM) HRESULT rc; I *obj = NULL; rc = CoCreateInstance (clsid, NULL, CLSCTX_LOCAL_SERVER, _ATL_IIDOF (I), (void **) &obj); *this = obj; if (SUCCEEDED (rc)) obj->Release(); return rc; #else /* !defined (VBOX_WITH_XPCOM) */ return createInprocObject (clsid); #endif /* !defined (VBOX_WITH_XPCOM) */ } #ifdef VBOX_WITH_XPCOM /** * Createas an object of the given class ID on the specified server and * starts to manage a reference to the created object in case of success. * * @param serverName Name of the server to create an object within. */ HRESULT createObjectOnServer (const CLSID &clsid, const char *serverName) { HRESULT rc; I *obj = NULL; nsCOMPtr ipcServ = do_GetService (IPC_SERVICE_CONTRACTID, &rc); if (SUCCEEDED (rc)) { PRUint32 serverID = 0; rc = ipcServ->ResolveClientName (serverName, &serverID); if (SUCCEEDED (rc)) { nsCOMPtr dconServ = do_GetService (IPC_DCONNECTSERVICE_CONTRACTID, &rc); if (SUCCEEDED (rc)) rc = dconServ->CreateInstance (serverID, clsid, NS_GET_IID (I), (void **) &obj); } } *this = obj; if (SUCCEEDED (rc)) obj->Release(); return rc; } #endif }; /** * Specialization of ComPtr<> for IUnknown to guarantee identity * by always doing QueryInterface() when constructing or assigning from * another interface pointer disregarding its type. */ template