/** @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 #define LOGREF(prefix, pObj, cRefs) com::LogRef("%s {%p} cRefs=%d\n", (prefix), (pObj), (cRefs)) namespace com { void LogRef(const char *pcszFormat, ...); } /** * 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 ComPtrBase { 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; } /** * Dereferences 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) p->AddRef(); } void release() { if (p) p->Release(); } void safe_assign (C *that_p) { /* be aware of self-assignment */ if (that_p) that_p->AddRef(); release(); p = that_p; } C *p; }; /** * Smart COM pointer wrapper that automatically manages refcounting of * interface pointers. * * @param I COM interface class */ template 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); } /** * Creates 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; } /** * Creates 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 /** * Creates 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<> 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); } template ComPtr(const ComPtr &oc) : Base() { operator=((OC*)oc); } template ComPtr &operator=(OI *that_p) { if (that_p) that_p->QueryInterface(COM_IIDOF(IUnknown), (void**)Base::asOutParam()); else Base::setNull(); return *this; } template ComPtr &operator=(const ComPtr &oc) { return operator=((OC*)oc); } }; /** * Smart COM pointer wrapper that automatically manages refcounting of * pointers to interface implementation classes created on the component's * (i.e. the server's) side. Differs from ComPtr by providing additional * platform independent operations for creating new class instances. * * @param C class that implements some COM interface */ template class ComObjPtr : public ComPtrBase { typedef ComPtrBase Base; public: ComObjPtr() : Base() {} ComObjPtr(const ComObjPtr &that) : Base(that) {} ComObjPtr(C *that_p) : Base(that_p) {} ComObjPtr& operator=(const ComObjPtr &that) { Base::operator=(that); return *this; } ComObjPtr& operator=(C *that_p) { Base::operator=(that_p); return *this; } /** * Creates a new server-side object of the given component class and * immediately starts to manage a pointer to the created object (the * previous pointer, if any, is of course released when appropriate). * * @note This method should be used with care on weakly referenced * smart pointers because it leaves the newly created object completely * unreferenced (i.e., with reference count equal to zero), * * @note Win32: when VBOX_COM_OUTOFPROC_MODULE is defined, the created * object doesn't increase the lock count of the server module, as it * does otherwise. */ HRESULT createObject() { HRESULT rc; #if !defined (VBOX_WITH_XPCOM) # ifdef VBOX_COM_OUTOFPROC_MODULE CComObjectNoLock *obj = new CComObjectNoLock(); if (obj) { obj->InternalFinalConstructAddRef(); rc = obj->FinalConstruct(); obj->InternalFinalConstructRelease(); } else rc = E_OUTOFMEMORY; # else CComObject *obj = NULL; rc = CComObject::CreateInstance(&obj); # endif #else /* !defined (VBOX_WITH_XPCOM) */ CComObject *obj = new CComObject(); if (obj) rc = obj->FinalConstruct(); else rc = E_OUTOFMEMORY; #endif /* !defined (VBOX_WITH_XPCOM) */ *this = obj; return rc; } }; #endif