ptr.h revision d19316699d7f91959d88c850fd7e0d64840f39a7
/** @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 <atlbase.h>
#ifndef _ATL_IIDOF
# define _ATL_IIDOF(c) __uuidof(c)
#endif
#else /* !defined (VBOX_WITH_XPCOM) */
#include <nsXPCOM.h>
#include <nsIComponentManager.h>
#include <nsCOMPtr.h>
#include <ipcIService.h>
#include <nsIServiceManagerUtils.h>
#include <ipcCID.h>
#include <ipcIDConnectService.h>
// official XPCOM headers don't define it yet
#define IPC_DCONNECTSERVICE_CONTRACTID \
"@mozilla.org/ipc/dconnect-service;1"
#endif /* !defined (VBOX_WITH_XPCOM) */
#include <VBox/com/defs.h>
#include <VBox/com/assert.h>
#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 <class I1, class I2>
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 <Any, IUnknown> */
template <class I1>
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 <IUnknown, Any> */
template <class I2>
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, IUnknown>(IUnknown *aThis, IUnknown *aThat)
{
return aThis == aThat;
}
/**
* Base template for smart COM pointers. Not intended to be used directly.
*/
template <class C>
class ComPtrBase
{
public:
/* special template to disable AddRef()/Release() */
template <class I>
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 <class I>
bool equalsTo(I *aThat) const
{
return ComPtrEquals(p, aThat);
}
template <class OC>
bool equalsTo(const ComPtrBase <OC> &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<C>* operator->() const
{
AssertMsg(p, ("Managed pointer must not be null\n"));
return (NoAddRefRelease<C>*)p;
}
template <class I>
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 I>
class ComPtr : public ComPtrBase<I>
{
typedef ComPtrBase<I> Base;
public:
ComPtr() : Base() {}
ComPtr(const ComPtr &that) : Base(that) {}
ComPtr& operator=(const ComPtr &that)
{
Base::operator= (that);
return *this;
}
template <class OI>
ComPtr(OI *that_p) : Base() { operator=(that_p); }
/* specialization for I */
ComPtr(I *that_p) : Base(that_p) {}
template <class OC>
ComPtr(const ComPtr<OC> &oc) : Base() { operator=((OC*)oc); }
template <class OI>
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 <class OC>
ComPtr &operator=(const ComPtr<OC> &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<nsIComponentManager> 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<ipcIService> ipcServ = do_GetService(IPC_SERVICE_CONTRACTID, &rc);
if (SUCCEEDED(rc))
{
PRUint32 serverID = 0;
rc = ipcServ->ResolveClientName(serverName, &serverID);
if (SUCCEEDED (rc))
{
nsCOMPtr<ipcIDConnectService> 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<IUnknown> : public ComPtrBase<IUnknown>
{
typedef ComPtrBase<IUnknown> Base;
public:
ComPtr() : Base() {}
ComPtr(const ComPtr &that) : Base (that) {}
ComPtr& operator=(const ComPtr &that)
{
Base::operator=(that);
return *this;
}
template <class OI>
ComPtr(OI *that_p) : Base() { operator=(that_p); }
template <class OC>
ComPtr(const ComPtr<OC> &oc) : Base() { operator=((OC*)oc); }
template <class OI>
ComPtr &operator=(OI *that_p)
{
if (that_p)
that_p->QueryInterface(COM_IIDOF(IUnknown), (void**)Base::asOutParam());
else
Base::setNull();
return *this;
}
template <class OC>
ComPtr &operator=(const ComPtr<OC> &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 C>
class ComObjPtr : public ComPtrBase<C>
{
typedef ComPtrBase<C> 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<C> *obj = new CComObjectNoLock<C>();
if (obj)
{
obj->InternalFinalConstructAddRef();
rc = obj->FinalConstruct();
obj->InternalFinalConstructRelease();
}
else
rc = E_OUTOFMEMORY;
# else
CComObject<C> *obj = NULL;
rc = CComObject<C>::CreateInstance(&obj);
# endif
#else /* !defined (VBOX_WITH_XPCOM) */
CComObject<C> *obj = new CComObject<C>();
if (obj)
rc = obj->FinalConstruct();
else
rc = E_OUTOFMEMORY;
#endif /* !defined (VBOX_WITH_XPCOM) */
*this = obj;
return rc;
}
};
#endif