Logo Search packages:      
Sourcecode: virtualbox-ose version File versions  Download package

ptr.h

Go to the documentation of this file.
/** @file
 * MS COM / XPCOM Abstraction Layer:
 * Smart COM pointer classes declaration
 */

/*
 * Copyright (C) 2006-2007 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 /* !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>
00086 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>
00116 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>
00138 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 */
00222     operator C*() const { return p; }

    /**
     *  Dereferences the instance (redirects the -> operator to the managed
     *  pointer).
     */
00228     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 */
00254     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>
00293 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.
     */
00343     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.
     */
00372     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<>
00426 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>
00472 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.
     */
00507     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

Generated by  Doxygen 1.6.0   Back to index