/** @file * MS COM / XPCOM Abstraction Layer: * Smart COM pointer classes declaration */ /* * Copyright (C) 2006-2007 innotek GmbH * * 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 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. */ #ifndef ___VBox_com_ptr_h #define ___VBox_com_ptr_h #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) {} }; /** * Base template for smart COM pointers. Not intended to be used directly. */ template class RefOps = ComStrongRef> class ComPtrBase : protected RefOps { public: // a 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 *i) const { IUnknown *this_unk = NULL, *that_unk = NULL; if (i) i->QueryInterface (COM_IIDOF (IUnknown), (void**) &that_unk); if (p) p->QueryInterface (COM_IIDOF (IUnknown), (void**) &this_unk); bool equal = this_unk == that_unk; if (that_unk) that_unk->Release(); if (this_unk) this_unk->Release(); return equal; } 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; } } else { 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