diff options
Diffstat (limited to 'include/VBox/com/ptr.h')
-rw-r--r-- | include/VBox/com/ptr.h | 493 |
1 files changed, 493 insertions, 0 deletions
diff --git a/include/VBox/com/ptr.h b/include/VBox/com/ptr.h new file mode 100644 index 00000000..1942274b --- /dev/null +++ b/include/VBox/com/ptr.h @@ -0,0 +1,493 @@ +/** @file + * MS COM / XPCOM Abstraction Layer: + * Smart COM pointer classes declaration + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * 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. + */ + +#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 <atlbase.h> + #ifndef _ATL_IIDOF + # define _ATL_IIDOF(c) __uuidof(c) + #endif +#else + #include <nsISupportsUtils.h> + +#endif /* !defined (VBOX_WITH_XPCOM) */ + +#include <VBox/com/defs.h> + +#ifdef VBOX_WITH_XPCOM + +namespace com +{ +// declare a couple of XPCOM helper methods (defined in glue/com.cpp) +// so we don't have to include a ton of XPCOM implementation headers here +HRESULT GlueCreateObjectOnServer(const CLSID &clsid, + const char *serverName, + const nsIID &id, + void** ppobj); +HRESULT GlueCreateInstance(const CLSID &clsid, + const nsIID &id, + void** ppobj); +} + +#endif // VBOX_WITH_XPCOM + +/** + * COM autopointer class which takes care of all required reference counting. + * + * This automatically calls the required basic COM methods on COM pointers + * given to it: + * + * -- AddRef() gets called automatically whenever a new COM pointer is assigned + * to the ComPtr instance (either in the copy constructor or by assignment); + * + * -- Release() gets called automatically by the destructor and when an existing + * object gets released in assignment; + * + * -- QueryInterface() gets called automatically when COM pointers get converted + * from one interface to another. + * + * Example usage: + * + * @code + * + * { + * ComPtr<IMachine> pMachine = findMachine("blah"); // calls AddRef() + * ComPtr<IUnknown> pUnknown = pMachine; // calls QueryInterface() + * } # ComPtr destructor of both instances calls Release() + * + * @endcode + */ +template <class T> +class ComPtr +{ +public: + + /** + * Default constructor, sets up a NULL pointer. + */ + ComPtr() + : m_p(NULL) + { } + + /** + * Destructor. Calls Release() on the contained COM object. + */ + ~ComPtr() + { + cleanup(); + } + + /** + * Copy constructor from another ComPtr of any interface. + * + * This calls QueryInterface(T) and can result in a NULL pointer if the input + * pointer p does not support the ComPtr interface T. + * + * Does not call AddRef explicitly because if QueryInterface succeeded, then + * the refcount will have been increased by one already . + */ + template <class T2> + ComPtr(const ComPtr<T2> &that) + { + m_p = NULL; + if (!that.isNull()) + that->QueryInterface(COM_IIDOF(T), (void**)&m_p); + } + + /** + * Specialization: copy constructor from another ComPtr<T>. Calls AddRef(). + */ + ComPtr(const ComPtr &that) + { + copyFrom(that.m_p); + } + + /** + * Copy constructor from another interface pointer of any interface. + * + * This calls QueryInterface(T) and can result in a NULL pointer if the input + * pointer p does not support the ComPtr interface T. + * + * Does not call AddRef explicitly because if QueryInterface succeeded, then + * the refcount will have been increased by one already . + */ + template <class T2> + ComPtr(T2 *p) + { + m_p = NULL; + if (p) + p->QueryInterface(COM_IIDOF(T), (void**)&m_p); + } + + /** + * Specialization: copy constructor from a plain T* pointer. Calls AddRef(). + */ + ComPtr(T *that_p) + { + copyFrom(that_p); + } + + /** + * Assignment from another ComPtr of any interface. + * + * This calls QueryInterface(T) and can result in a NULL pointer if the input + * pointer p does not support the ComPtr interface T. + * + * Does not call AddRef explicitly because if QueryInterface succeeded, then + * the refcount will have been increased by one already . + */ + template <class T2> + ComPtr& operator=(const ComPtr<T2> &that) + { + return operator=((T2*)that); + } + + /** + * Specialization of the previous: assignment from another ComPtr<T>. + * Calls Release() on the previous member pointer, if any, and AddRef() on the new one. + */ + ComPtr& operator=(const ComPtr &that) + { + return operator=((T*)that); + } + + /** + * Assignment from another interface pointer of any interface. + * + * This calls QueryInterface(T) and can result in a NULL pointer if the input + * pointer p does not support the ComPtr interface T. + * + * Does not call AddRef explicitly because if QueryInterface succeeded, then + * the refcount will have been increased by one already . + */ + template <class T2> + ComPtr& operator=(T2 *p) + { + cleanup(); + if (p) + p->QueryInterface(COM_IIDOF(T), (void**)&m_p); + return *this; + } + + /** + * Specialization of the previous: assignment from a plain T* pointer. + * Calls Release() on the previous member pointer, if any, and AddRef() on the new one. + */ + ComPtr& operator=(T *p) + { + cleanup(); + copyFrom(p); + return *this; + } + + /** + * Resets the ComPtr to NULL. Works like a NULL assignment except it avoids the templates. + */ + void setNull() + { + cleanup(); + } + + /** + * Returns true if the pointer is NULL. + */ + bool isNull() const + { + return (m_p == NULL); + } + + bool operator<(T* p) const + { + return m_p < p; + } + + /** + * Conversion operator, most often used to pass ComPtr instances as + * parameters to COM method calls. + */ + operator T*() const + { + return m_p; + } + + /** + * Dereferences the instance (redirects the -> operator to the managed + * pointer). + */ + T* operator->() const + { + return m_p; + } + + /** + * Special method which allows using a ComPtr as an output argument of a COM method. + * The ComPtr will then accept the method's interface pointer without calling AddRef() + * itself, since by COM convention this must has been done by the method which created + * the object that is being accepted. + * + * The ComPtr destructor will then still invoke Release() so that the returned object + * can get cleaned up properly. + */ + T** asOutParam() + { + cleanup(); + return &m_p; + } + + /** + * Converts the contained pointer to a different interface + * by calling QueryInterface() on it. + * @param pp + * @return + */ + template <class T2> + HRESULT queryInterfaceTo(T2 **pp) const + { + if (pp) + { + if (m_p) + return m_p->QueryInterface(COM_IIDOF(T2), (void**)pp); + else + { + *pp = NULL; + return S_OK; + } + } + + return E_INVALIDARG; + } + + /** + * Equality test operator. By COM definition, two COM objects are considered + * equal if their IUnknown interface pointers are equal. + */ + template <class T2> + bool operator==(T2* p) + { + IUnknown *p1 = NULL; + bool fNeedsRelease1 = false; + if (m_p) + fNeedsRelease1 = (SUCCEEDED(m_p->QueryInterface(COM_IIDOF(IUnknown), (void**)&p1))); + + IUnknown *p2 = NULL; + bool fNeedsRelease2 = false; + if (p) + fNeedsRelease2 = (SUCCEEDED(p->QueryInterface(COM_IIDOF(IUnknown), (void**)&p2))); + + bool f = p1 == p2; + if (fNeedsRelease1) + p1->Release(); + if (fNeedsRelease2) + p2->Release(); + return f; + } + + /** + * 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; + T *obj = NULL; +#if !defined (VBOX_WITH_XPCOM) + rc = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, _ATL_IIDOF(T), + (void**)&obj); +#else /* !defined (VBOX_WITH_XPCOM) */ + using namespace com; + rc = GlueCreateInstance(clsid, NS_GET_IID(T), (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; + T *obj = NULL; + rc = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, _ATL_IIDOF(T), + (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) + { + T *obj = NULL; + HRESULT rc = GlueCreateObjectOnServer(clsid, serverName, NS_GET_IID(T), (void**)&obj); + *this = obj; + if (SUCCEEDED(rc)) + obj->Release(); + return rc; + } +#endif + +protected: + void copyFrom(T* p) + { + m_p = p; + if (m_p) + m_p->AddRef(); + } + + void cleanup() + { + if (m_p) + { + m_p->Release(); + m_p = NULL; + } + } + + T *m_p; +}; + +/** + * ComObjPtr is a more specialized variant of ComPtr designed to be used for implementation + * objects. For example, use ComPtr<IMachine> for a client pointer that calls the interface + * but ComObjPtr<Machine> for a pointer to an implementation object. + * + * The methods behave the same except that ComObjPtr has the additional createObject() + * method which allows for instantiating a new implementation object. + * + * Note: To convert a ComObjPtr<InterfaceImpl> to a ComObj<IInterface> you have + * to query the interface. See the following example code for the IProgress + * interface: + * + * @code + * + * { + * ComObjPtr<Progress> pProgress; // create the server side object + * pProgress.createObject(); // ... + * pProgress->init(...); // ... + * ComPtr<IProgress> pProgress2; // create an interface pointer + * pProgress.queryInterfaceTo(pProgress2.asOutParam()); // transfer the interface + * } + * + * @endcode + */ +template <class T> +class ComObjPtr : public ComPtr<T> +{ +public: + + ComObjPtr() + : ComPtr<T>() + {} + + ComObjPtr(const ComObjPtr &that) + : ComPtr<T>(that) + {} + + ComObjPtr(T *that_p) + : ComPtr<T>(that_p) + {} + + ComObjPtr& operator=(const ComObjPtr &that) + { + ComPtr<T>::operator=(that); + return *this; + } + + ComObjPtr& operator=(T *that_p) + { + ComPtr<T>::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 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<T> *obj = new CComObjectNoLock<T>(); + if (obj) + { + obj->InternalFinalConstructAddRef(); + rc = obj->FinalConstruct(); + obj->InternalFinalConstructRelease(); + } + else + rc = E_OUTOFMEMORY; +# else + CComObject<T> *obj = NULL; + rc = CComObject<T>::CreateInstance(&obj); +# endif +#else /* !defined (VBOX_WITH_XPCOM) */ + CComObject<T> *obj = new CComObject<T>(); + if (obj) + rc = obj->FinalConstruct(); + else + rc = E_OUTOFMEMORY; +#endif /* !defined (VBOX_WITH_XPCOM) */ + *this = obj; + return rc; + } +}; +#endif |