Index: /trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Main/Makefile.kmk	(revision 29858)
+++ /trunk/src/VBox/Main/Makefile.kmk	(revision 29859)
@@ -302,4 +302,5 @@
 	MediumFormatImpl.cpp \
 	ProgressImpl.cpp \
+	ProgressProxyImpl.cpp \
 	HostImpl.cpp \
 	HostNetworkInterfaceImpl.cpp \
@@ -869,5 +870,5 @@
               --stringparam G_vboxGlueStyle mscom              \
               -o $(VBOX_JMSCOM_GEN)/java/merged.file $(VBOX_GLUE_XSLT_DIR)/glue-java.xsl $<
-	$(QUIET)$(VBOX_FILESPLIT) $(VBOX_JMSCOM_GEN)/java/merged.file $(VBOX_JMSCOM_GEN)/java	
+	$(QUIET)$(VBOX_FILESPLIT) $(VBOX_JMSCOM_GEN)/java/merged.file $(VBOX_JMSCOM_GEN)/java
 	$(QUIET)echo $(VBOX_JMSCOM_GEN)/java/*.java > $@
 
Index: /trunk/src/VBox/Main/ProgressProxyImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/ProgressProxyImpl.cpp	(revision 29859)
+++ /trunk/src/VBox/Main/ProgressProxyImpl.cpp	(revision 29859)
@@ -0,0 +1,582 @@
+/* $Id$ */
+/** @file
+ * IProgress implementation for Machine::openRemoteSession in VBoxSVC.
+ */
+
+/*
+ * Copyright (C) 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.
+ */
+
+#include <iprt/types.h>
+
+#if defined (VBOX_WITH_XPCOM)
+#include <nsIServiceManager.h>
+#include <nsIExceptionService.h>
+#include <nsCOMPtr.h>
+#endif /* defined (VBOX_WITH_XPCOM) */
+
+#include "ProgressProxyImpl.h"
+
+#include "VirtualBoxImpl.h"
+#include "VirtualBoxErrorInfoImpl.h"
+
+#include "Logging.h"
+
+#include <iprt/time.h>
+#include <iprt/semaphore.h>
+
+#include <VBox/err.h>
+
+////////////////////////////////////////////////////////////////////////////////
+// ProgressProxy class
+////////////////////////////////////////////////////////////////////////////////
+
+// constructor / destructor / uninitializer
+////////////////////////////////////////////////////////////////////////////////
+
+
+HRESULT ProgressProxy::FinalConstruct()
+{
+    mcOtherProgressObjects = 1;
+    miCurOtherProgressObject = 0;
+
+    HRESULT rc = Progress::FinalConstruct();
+    return rc;
+}
+
+/**
+ * Initalize it as a one operation Progress object.
+ *
+ * This is used by SessionMachine::OnSessionEnd.
+ */
+HRESULT ProgressProxy::init(
+#if !defined (VBOX_COM_INPROC)
+                            VirtualBox *pParent,
+#endif
+                            IUnknown *pInitiator,
+                            CBSTR bstrDescription,
+                            BOOL fCancelable)
+{
+    miCurOtherProgressObject = 0;
+    mcOtherProgressObjects = 0;
+
+    return Progress::init(
+#if !defined (VBOX_COM_INPROC)
+                          pParent,
+#endif
+                          pInitiator,
+                          bstrDescription,
+                          fCancelable,
+                          1 /* cOperations */,
+                          1 /* ulTotalOperationsWeight */,
+                          bstrDescription /* bstrFirstOperationDescription */,
+                          1 /* ulFirstOperationWeight */,
+                          NULL /* pId */);
+}
+
+/**
+ * Initialize for proxying one or more other objects, assuming we start out and
+ * end without proxying anyone.
+ *
+ * The user must call clearOtherProgressObject when there are no more progress
+ * objects to be proxied or we'll leave threads waiting forever.
+ */
+HRESULT ProgressProxy::init(
+#if !defined (VBOX_COM_INPROC)
+                            VirtualBox *pParent,
+#endif
+                            IUnknown *pInitiator,
+                            CBSTR bstrDescription,
+                            BOOL fCancelable,
+                            ULONG cOtherProgressObjects,
+                            ULONG uTotalOperationsWeight,
+                            CBSTR bstrFirstOperationDescription,
+                            ULONG uFirstOperationWeight,
+                            OUT_GUID pId)
+{
+    miCurOtherProgressObject = 0;
+    mcOtherProgressObjects = cOtherProgressObjects;
+
+    return Progress::init(
+#if !defined (VBOX_COM_INPROC)
+                          pParent,
+#endif
+                          pInitiator,
+                          bstrDescription,
+                          fCancelable,
+                          1 + cOtherProgressObjects + 1 /* cOperations */,
+                          uTotalOperationsWeight,
+                          bstrFirstOperationDescription,
+                          uFirstOperationWeight,
+                          pId);
+}
+
+void ProgressProxy::FinalRelease()
+{
+    uninit();
+    miCurOtherProgressObject = 0;
+}
+
+void ProgressProxy::uninit()
+{
+    LogFlowThisFunc(("\n"));
+
+    mptrOtherProgress.setNull();
+    Progress::uninit();
+}
+
+// Public methods
+////////////////////////////////////////////////////////////////////////////////
+
+/** Just a wrapper so we can automatically do the handover before setting
+ *  the result locally. */
+HRESULT ProgressProxy::setResultCode(HRESULT aResultCode)
+{
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+    clearOtherProgressObjectInternal(true /* fEarly */);
+    return Progress::setResultCode(aResultCode);
+}
+
+/** Just a wrapper so we can automatically do the handover before setting
+ *  the result locally. */
+HRESULT ProgressProxy::notifyComplete(HRESULT aResultCode)
+{
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+    clearOtherProgressObjectInternal(true /* fEarly */);
+    return Progress::notifyComplete(aResultCode);
+}
+
+/** Just a wrapper so we can automatically do the handover before setting
+ *  the result locally. */
+HRESULT ProgressProxy::notifyComplete(HRESULT aResultCode,
+                                      const GUID &aIID,
+                                      const Bstr &aComponent,
+                                      const char *aText,
+                                      ...)
+{
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+    clearOtherProgressObjectInternal(true /* fEarly */);
+
+    va_list va;
+    va_start(va, aText);
+    HRESULT hrc = Progress::notifyCompleteV(aResultCode, aIID, aComponent, aText, va);
+    va_end(va);
+    return hrc;
+}
+
+/** Just a wrapper so we can automatically do the handover before setting
+ *  the result locally. */
+bool    ProgressProxy::notifyPointOfNoReturn(void)
+{
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+    clearOtherProgressObjectInternal(true /* fEarly */);
+    return Progress::notifyPointOfNoReturn();
+}
+
+/**
+ * Sets the other progress object unless the operation has been completed /
+ * canceled already.
+ *
+ * @returns false if failed/canceled, true if not.
+ * @param   pOtherProgress      The other progress object. Must not be NULL.
+ * @param   uOperationWeight    The weight of this operation.  (The description
+ *                              is taken from the other progress object.)
+ */
+bool ProgressProxy::setOtherProgressObject(IProgress *pOtherProgress, ULONG uOperationWeight)
+{
+    LogFlowThisFunc(("setOtherProgressObject: %p %u\n", pOtherProgress, uOperationWeight));
+    ComPtr<IProgress> ptrOtherProgress = pOtherProgress;
+
+    /* Get the description first. */
+    Bstr    bstrOperationDescription;
+    HRESULT hrc = pOtherProgress->COMGETTER(Description)(bstrOperationDescription.asOutParam());
+    if (FAILED(hrc))
+        bstrOperationDescription = "oops";
+
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    /* Do the hand over from any previous progress object. */
+    clearOtherProgressObjectInternal(false /*fEarly*/);
+    BOOL fCompletedOrCanceled = mCompleted || mCanceled;
+    if (!fCompletedOrCanceled)
+    {
+        /* Advance to the next object and operation, checking for cancelation
+           and completion right away to be on the safe side. */
+        Assert(miCurOtherProgressObject < mcOtherProgressObjects);
+        mptrOtherProgress = ptrOtherProgress;
+
+        Progress::SetNextOperation(bstrOperationDescription, uOperationWeight);
+
+        BOOL f;
+        hrc = ptrOtherProgress->COMGETTER(Completed)(&f);
+        fCompletedOrCanceled = FAILED(hrc) || f;
+
+        if (!fCompletedOrCanceled)
+        {
+            hrc = ptrOtherProgress->COMGETTER(Canceled)(&f);
+            fCompletedOrCanceled = SUCCEEDED(hrc) && f;
+        }
+
+        if (fCompletedOrCanceled)
+        {
+            LogFlowThisFunc(("Other object completed or canceled, clearing...\n"));
+            clearOtherProgressObjectInternal(false /*fEarly*/);
+        }
+        else
+        {
+            /* Mirror the cancelable property. */
+            if (mCancelable)
+            {
+                hrc = ptrOtherProgress->COMGETTER(Cancelable)(&f);
+                if (SUCCEEDED(hrc) && !f)
+                {
+                    LogFlowThisFunc(("The other progress object is not cancelable\n"));
+                    mCancelable = FALSE;
+                }
+            }
+        }
+    }
+    else
+    {
+        LogFlowThisFunc(("mCompleted=%RTbool mCanceled=%RTbool - Canceling the other progress object!\n",
+                         mCompleted, mCanceled));
+        hrc = ptrOtherProgress->Cancel();
+        LogFlowThisFunc(("Cancel -> %Rhrc", hrc));
+    }
+
+    LogFlowThisFunc(("Returns %RTbool\n", !fCompletedOrCanceled));
+    return !fCompletedOrCanceled;
+}
+
+/**
+ * Clears the last other progress objects.
+ *
+ * @returns false if failed/canceled, true if not.
+ * @param   pszLastOperationDescription     The description of the final bit.
+ * @param   uLastOperationWeight            The weight of the final bit.
+ */
+bool ProgressProxy::clearOtherProgressObject(const char *pszLastOperationDescription, ULONG uLastOperationWeight)
+{
+    LogFlowThisFunc(("%p %u\n", pszLastOperationDescription, uLastOperationWeight));
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    clearOtherProgressObjectInternal(false /* fEarly */);
+
+    /* Advance to the next operation if applicable. */
+    bool fCompletedOrCanceled = mCompleted || mCanceled;
+    if (!fCompletedOrCanceled)
+        Progress::SetNextOperation(Bstr(pszLastOperationDescription), uLastOperationWeight);
+
+    LogFlowThisFunc(("Returns %RTbool\n", !fCompletedOrCanceled));
+    return !fCompletedOrCanceled;
+}
+
+// Internal methods.
+////////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * Internal version of clearOtherProgressObject that doesn't advance to the next
+ * operation.
+ *
+ * This is used both by clearOtherProgressObject as well as a number of places
+ * where we automatically do the hand over because of failure/completion.
+ *
+ * @param   fEarly          Early clearing or not.
+ */
+void ProgressProxy::clearOtherProgressObjectInternal(bool fEarly)
+{
+    if (!mptrOtherProgress.isNull())
+    {
+        ComPtr<IProgress> ptrOtherProgress = mptrOtherProgress;
+        mptrOtherProgress.setNull();
+        copyProgressInfo(ptrOtherProgress, fEarly);
+
+        miCurOtherProgressObject++;
+        Assert(miCurOtherProgressObject <= mcOtherProgressObjects);
+    }
+}
+
+/**
+ * Called to copy over the progress information from @a pOtherProgress.
+ *
+ * @param   pOtherProgress  The source of the information.
+ * @param   fEarly          Early copy.
+ *
+ * @note    The caller owns the write lock and as cleared mptrOtherProgress
+ *          already (or we might recurse forever)!
+ */
+void ProgressProxy::copyProgressInfo(IProgress *pOtherProgress, bool fEarly)
+{
+    HRESULT hrc;
+    LogFlowThisFunc(("\n"));
+
+    /*
+     * No point in doing this if the progress object was canceled already.
+     */
+    if (!mCanceled)
+    {
+        /* Detect if the other progress object was canceled. */
+        BOOL fCanceled;
+        hrc = pOtherProgress->COMGETTER(Canceled)(&fCanceled); AssertComRC(hrc);
+        if (FAILED(hrc))
+            fCanceled = FALSE;
+        if (fCanceled)
+        {
+            LogFlowThisFunc(("Canceled\n"));
+            mCanceled = TRUE;
+            if (m_pfnCancelCallback)
+                m_pfnCancelCallback(m_pvCancelUserArg);
+        }
+        else
+        {
+            /* Has it completed? */
+            BOOL fCompleted;
+            hrc = pOtherProgress->COMGETTER(Completed)(&fCompleted); AssertComRC(hrc);
+            if (FAILED(hrc))
+                fCompleted = TRUE;
+            Assert(fCompleted || fEarly);
+            if (fCompleted)
+            {
+                /* Check the result. */
+                LONG hrcResult;
+                hrc = pOtherProgress->COMGETTER(ResultCode)(&hrcResult); AssertComRC(hrc);
+                if (FAILED(hrc))
+                    hrcResult = hrc;
+                if (SUCCEEDED((HRESULT)hrcResult))
+                    LogFlowThisFunc(("Succeeded\n"));
+                else
+                {
+                    /* Get the error information. */
+                    ComPtr<IVirtualBoxErrorInfo> ptrErrorInfo;
+                    hrc = pOtherProgress->COMGETTER(ErrorInfo)(ptrErrorInfo.asOutParam());
+                    if (SUCCEEDED(hrc))
+                    {
+                        Bstr bstrIID;
+                        hrc = ptrErrorInfo->COMGETTER(InterfaceID)(bstrIID.asOutParam());
+                        if (FAILED(hrc))
+                            bstrIID.setNull();
+
+                        Bstr bstrComponent;
+                        hrc = ptrErrorInfo->COMGETTER(Component)(bstrComponent.asOutParam());
+                        if (FAILED(hrc))
+                            bstrComponent = "failed";
+
+                        Bstr bstrText;
+                        hrc = ptrErrorInfo->COMGETTER(Text)(bstrText.asOutParam());
+                        if (FAILED(hrc))
+                            bstrText = "<failed>";
+
+                        Utf8Str strText(bstrText);
+                        LogFlowThisFunc(("Got ErrorInfo(%s); hrcResult=%Rhrc\n", strText.c_str(), hrcResult));
+                        Progress::notifyComplete((HRESULT)hrcResult, Guid(bstrIID), bstrComponent, "%s", strText.c_str());
+                    }
+                    else
+                    {
+                        LogFlowThisFunc(("ErrorInfo failed with hrc=%Rhrc; hrcResult=%Rhrc\n", hrc, hrcResult));
+                        Progress::notifyComplete((HRESULT)hrcResult);
+                    }
+                }
+            }
+            else
+                LogFlowThisFunc(("Not completed\n"));
+        }
+    }
+    else
+        LogFlowThisFunc(("Already canceled\n"));
+
+    /*
+     * Did cancelable state change (point of no return)?
+     */
+    if (mCancelable)
+    {
+        BOOL fCancelable;
+        hrc = pOtherProgress->COMGETTER(Cancelable)(&fCancelable); AssertComRC(hrc);
+        if (SUCCEEDED(hrc) && !fCancelable)
+        {
+            LogFlowThisFunc(("point-of-no-return reached\n"));
+            mCancelable = FALSE;
+        }
+    }
+}
+
+
+// IProgress properties
+////////////////////////////////////////////////////////////////////////////////
+
+STDMETHODIMP ProgressProxy::COMGETTER(Percent)(ULONG *aPercent)
+{
+#if 0
+    CheckComArgOutPointerValid(aPercent);
+
+    AutoCaller autoCaller(this);
+    HRESULT hrc = autoCaller.rc();
+    if (SUCCEEDED(rc))
+    {
+        AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+        if (mptrOtherProgress.isNull())
+            hrc = Progress::COMGETTER(Percent)(aPercent);
+        else
+        {
+            ULONG uPct;
+            hrc = mptrOtherProgress->COMGETTER(Percent)(&uPct);
+            ....
+        }
+    }
+    return hrc;
+#else
+    return Progress::COMGETTER(Percent)(aPercent);
+#endif
+}
+
+STDMETHODIMP ProgressProxy::COMGETTER(Completed)(BOOL *aCompleted)
+{
+    /* Not proxied since we EXPECT a hand back call. */
+    return Progress::COMGETTER(Completed)(aCompleted);
+}
+
+STDMETHODIMP ProgressProxy::COMGETTER(Canceled)(BOOL *aCanceled)
+{
+    CheckComArgOutPointerValid(aCanceled);
+
+    AutoCaller autoCaller(this);
+    HRESULT hrc = autoCaller.rc();
+    if (SUCCEEDED(hrc))
+    {
+        /* Check the local data first, then the other object. */
+        AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+        hrc = Progress::COMGETTER(Canceled)(aCanceled);
+        if (   SUCCEEDED(hrc)
+            && !*aCanceled
+            && !mptrOtherProgress.isNull())
+        {
+            hrc = mptrOtherProgress->COMGETTER(Canceled)(aCanceled);
+            if (SUCCEEDED(hrc) && *aCanceled)
+                clearOtherProgressObjectInternal(true /*fEarly*/);
+        }
+    }
+    return hrc;
+}
+
+STDMETHODIMP ProgressProxy::COMGETTER(ResultCode)(LONG *aResultCode)
+{
+    /* Not proxied yet since we EXPECT a hand back call. */
+    return Progress::COMGETTER(ResultCode)(aResultCode);
+}
+
+STDMETHODIMP ProgressProxy::COMGETTER(ErrorInfo)(IVirtualBoxErrorInfo **aErrorInfo)
+{
+    /* Not proxied yet since we EXPECT a hand back call. */
+    return Progress::COMGETTER(ErrorInfo)(aErrorInfo);
+}
+
+STDMETHODIMP ProgressProxy::COMGETTER(OperationPercent)(ULONG *aOperationPercent)
+{
+    /* Not proxied, should be proxied later on. */
+    return Progress::COMGETTER(OperationPercent)(aOperationPercent);
+}
+
+STDMETHODIMP ProgressProxy::COMSETTER(Timeout)(ULONG aTimeout)
+{
+    /* Not currently supported. */
+    NOREF(aTimeout);
+    AssertFailed();
+    return E_NOTIMPL;
+}
+
+STDMETHODIMP ProgressProxy::COMGETTER(Timeout)(ULONG *aTimeout)
+{
+    /* Not currently supported. */
+    CheckComArgOutPointerValid(aTimeout);
+
+    AssertFailed();
+    return E_NOTIMPL;
+}
+
+// IProgress methods
+/////////////////////////////////////////////////////////////////////////////
+
+STDMETHODIMP ProgressProxy::WaitForCompletion(LONG aTimeout)
+{
+    HRESULT hrc;
+    LogFlowThisFuncEnter();
+    LogFlowThisFunc(("aTimeout=%d\n", aTimeout));
+
+    /* For now we'll always block locally. */
+    hrc = Progress::WaitForCompletion(aTimeout);
+
+    LogFlowThisFuncLeave();
+    return hrc;
+}
+
+STDMETHODIMP ProgressProxy::WaitForOperationCompletion(ULONG aOperation, LONG aTimeout)
+{
+    HRESULT hrc;
+    LogFlowThisFuncEnter();
+    LogFlowThisFunc(("aOperation=%d aTimeout=%d\n", aOperation, aTimeout));
+
+    /* For now we'll always block locally. Later though, we could consider
+       blocking remotely when we can. */
+    hrc = Progress::WaitForOperationCompletion(aOperation, aTimeout);
+
+    LogFlowThisFuncLeave();
+    return hrc;
+}
+
+STDMETHODIMP ProgressProxy::Cancel()
+{
+    LogFlowThisFunc(("\n"));
+    AutoCaller autoCaller(this);
+    HRESULT hrc = autoCaller.rc();
+    if (SUCCEEDED(hrc))
+    {
+        AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+        if (mCancelable)
+        {
+            if (!mptrOtherProgress.isNull())
+            {
+                hrc = mptrOtherProgress->Cancel();
+                if (SUCCEEDED(hrc))
+                {
+                    if (m_pfnCancelCallback)
+                        m_pfnCancelCallback(m_pvCancelUserArg);
+                    clearOtherProgressObjectInternal(true /*fEarly*/);
+                }
+            }
+            else
+                hrc = Progress::Cancel();
+        }
+        else
+            hrc = setError(E_FAIL, tr("Operation cannot be canceled"));
+    }
+
+    LogFlowThisFunc(("returns %Rhrc\n", hrc));
+    return hrc;
+}
+
+STDMETHODIMP ProgressProxy::SetCurrentOperationProgress(ULONG aPercent)
+{
+    /* Not supported - why do we actually expose this? */
+    NOREF(aPercent);
+    return E_NOTIMPL;
+}
+
+STDMETHODIMP ProgressProxy::SetNextOperation(IN_BSTR bstrNextOperationDescription, ULONG ulNextOperationsWeight)
+{
+    /* Not supported - why do we actually expose this? */
+    NOREF(bstrNextOperationDescription);
+    NOREF(ulNextOperationsWeight);
+    return E_NOTIMPL;
+}
+
+/* vi: set tabstop=4 shiftwidth=4 expandtab: */
+
Index: /trunk/src/VBox/Main/include/ProgressProxyImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/ProgressProxyImpl.h	(revision 29859)
+++ /trunk/src/VBox/Main/include/ProgressProxyImpl.h	(revision 29859)
@@ -0,0 +1,114 @@
+/* $Id$ */
+/** @file
+ * IProgress implementation for Machine::openRemoteSession in VBoxSVC.
+ */
+
+/*
+ * 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.
+ */
+
+#ifndef ____H_PROGRESSPROXYIMPL
+#define ____H_PROGRESSPROXYIMPL
+
+#include "ProgressImpl.h"
+#include "AutoCaller.h"
+
+
+/**
+ * The ProgressProxy class allows proxying the important Progress calls and
+ * attributes to a different IProgress object for a period of time.
+ */
+class ATL_NO_VTABLE ProgressProxy :
+    public com::SupportErrorInfoDerived<Progress, ProgressProxy, IProgress>,
+    public VirtualBoxSupportTranslation<ProgressProxy>
+{
+public:
+    VIRTUALBOXSUPPORTTRANSLATION_OVERRIDE(ProgressProxy)
+    DECLARE_NOT_AGGREGATABLE(ProgressProxy)
+    DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+    BEGIN_COM_MAP(ProgressProxy)
+        COM_INTERFACE_ENTRY (ISupportErrorInfo)
+        COM_INTERFACE_ENTRY (IProgress)
+        COM_INTERFACE_ENTRY2(IDispatch, IProgress)
+    END_COM_MAP()
+
+    HRESULT FinalConstruct();
+    void    FinalRelease();
+    HRESULT init(
+#if !defined (VBOX_COM_INPROC)
+                 VirtualBox *pParent,
+#endif
+                 IUnknown *pInitiator,
+                 CBSTR bstrDescription,
+                 BOOL fCancelable);
+    HRESULT init(
+#if !defined (VBOX_COM_INPROC)
+                 VirtualBox *pParent,
+#endif
+                 IUnknown *pInitiator,
+                 CBSTR bstrDescription,
+                 BOOL fCancelable,
+                 ULONG cOtherProgressObjects,
+                 ULONG uTotalOperationsWeight,
+                 CBSTR bstrFirstOperationDescription,
+                 ULONG uFirstOperationWeight,
+                 OUT_GUID pId = NULL);
+    void    uninit();
+
+    // IProgress properties
+    STDMETHOD(COMGETTER(Percent))(ULONG *aPercent);
+    STDMETHOD(COMGETTER(Completed))(BOOL *aCompleted);
+    STDMETHOD(COMGETTER(Canceled))(BOOL *aCanceled);
+    STDMETHOD(COMGETTER(ResultCode))(LONG *aResultCode);
+    STDMETHOD(COMGETTER(ErrorInfo))(IVirtualBoxErrorInfo **aErrorInfo);
+    STDMETHOD(COMGETTER(OperationPercent))(ULONG *aOperationPercent);
+    STDMETHOD(COMSETTER(Timeout))(ULONG aTimeout);
+    STDMETHOD(COMGETTER(Timeout))(ULONG *aTimeout);
+
+    // IProgress methods
+    STDMETHOD(WaitForCompletion)(LONG aTimeout);
+    STDMETHOD(WaitForOperationCompletion)(ULONG aOperation, LONG aTimeout);
+    STDMETHOD(Cancel)();
+    STDMETHOD(SetCurrentOperationProgress)(ULONG aPercent);
+    STDMETHOD(SetNextOperation)(IN_BSTR bstrNextOperationDescription, ULONG ulNextOperationsWeight);
+
+    // public methods only for internal purposes
+
+    HRESULT setResultCode(HRESULT aResultCode);
+    HRESULT notifyComplete(HRESULT aResultCode);
+    HRESULT notifyComplete(HRESULT aResultCode,
+                           const GUID &aIID,
+                           const Bstr &aComponent,
+                           const char *aText, ...);
+    bool    notifyPointOfNoReturn(void);
+    bool    setOtherProgressObject(IProgress *pOtherProgress, ULONG uOperationWeight);
+    bool    clearOtherProgressObject(const char *pszLastOperationDescription, ULONG uLastOperationWeight);
+
+    /** For com::SupportErrorInfoImpl. */
+    static const char *ComponentName() { return "ProgressProxy"; }
+
+protected:
+    void clearOtherProgressObjectInternal(bool fEarly);
+    void copyProgressInfo(IProgress *pOtherProgress, bool fEarly);
+
+private:
+    /** The other progress object.  This can be NULL. */
+    ComPtr<IProgress> mptrOtherProgress;
+    /** The number of other progress objects expected. */
+    ULONG mcOtherProgressObjects;
+    /** The current other progress object. */
+    ULONG miCurOtherProgressObject;
+
+};
+
+#endif /* !____H_PROGRESSPROXYIMPL */
+
