Index: /trunk/include/VBox/ExtPack/ExtPack.h
===================================================================
--- /trunk/include/VBox/ExtPack/ExtPack.h	(revision 74803)
+++ /trunk/include/VBox/ExtPack/ExtPack.h	(revision 74804)
@@ -281,7 +281,9 @@
      * @param   pProgressOther  Pointer to an IProgress object reference, the one
      *                          to be waited for.
+     * @param   cTimeoutMS      Timeout in milliseconds, 0 for indefinite wait.
      */
     DECLR3CALLBACKMEMBER(uint32_t, pfnWaitOtherProgress,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress,
-                                                         VBOXEXTPACK_IF_CS(IProgress) *pProgressOther));
+                                                         VBOXEXTPACK_IF_CS(IProgress) *pProgressOther,
+                                                         uint32_t cTimeoutMS));
 
     /**
Index: /trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 74803)
+++ /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 74804)
@@ -14269,7 +14269,8 @@
   <interface
     name="IProgress" extends="$unknown"
-    uuid="64c7fb5c-ce8f-4681-9c8c-d523cb4dea3d"
+    uuid="d3ee3588-a762-4ba1-9e9e-23146587ed3a"
     wsmap="managed"
-    reservedMethods="1" reservedAttributes="2"
+    wrap-hint-server-addinterfaces="IInternalProgressControl"
+    reservedMethods="4" reservedAttributes="8"
     >
     <desc>
@@ -14408,14 +14409,4 @@
     <attribute name="eventSource" type="IEventSource" readonly="yes"/>
 
-    <method name="setCurrentOperationProgress">
-      <desc>Internal method, not to be called externally.</desc>
-      <param name="percent" type="unsigned long" dir="in" />
-    </method>
-    <method name="setNextOperation">
-      <desc>Internal method, not to be called externally.</desc>
-      <param name="nextOperationDescription" type="wstring" dir="in" />
-      <param name="nextOperationsWeight" type="unsigned long" dir="in" />
-    </method>
-
     <method name="waitForCompletion">
       <desc>
@@ -14480,4 +14471,65 @@
 
       </desc>
+    </method>
+
+  </interface>
+
+  <interface
+    name="IInternalProgressControl" extends="$unknown"
+    uuid="9bf38c56-ac64-4f72-871a-321a25f52a57"
+    internal="yes"
+    wsmap="suppress"
+    reservedMethods="4" reservedAttributes="8"
+    >
+
+    <method name="setCurrentOperationProgress">
+      <desc>Internal method, not to be called externally.</desc>
+      <param name="percent" type="unsigned long" dir="in" />
+    </method>
+
+    <method name="waitForOtherProgressCompletion">
+      <desc>
+        Internal method, not to be called externally.
+
+        Waits until the other task is completed (including all sub-operations)
+        and forward all changes from the other progress to this progress. This
+        means sub-operation number, description, percent and so on.
+
+        The caller is responsible for having at least the same count of
+        sub-operations in this progress object as there are in the other
+        progress object.
+
+        If the other progress object supports cancel and this object gets any
+        cancel request (when here enabled as well), it will be forwarded to
+        the other progress object.
+
+        Error information is automatically preserved (by transferring it to
+        the current thread's error information). If the caller wants to set it
+        as the completion state of this progress it needs to be done separately.
+
+        <result name="VBOX_E_TIMEOUT">
+          Waiting time has expired.
+        </result>
+      </desc>
+      <param name="progressOther" type="IProgress" dir="in" />
+      <param name="timeoutMS" type="unsigned long" dir="in">
+        <desc>Timeout (in ms). Pass 0 for an infinite timeout.</desc>
+      </param>
+    </method>
+
+    <method name="setNextOperation">
+      <desc>Internal method, not to be called externally.</desc>
+      <param name="nextOperationDescription" type="wstring" dir="in" />
+      <param name="nextOperationsWeight" type="unsigned long" dir="in" />
+    </method>
+
+    <method name="notifyPointOfNoReturn">
+      <desc>Internal method, not to be called externally.</desc>
+    </method>
+
+    <method name="notifyComplete">
+      <desc>Internal method, not to be called externally.</desc>
+      <param name="resultCode" type="long" dir="in" />
+      <param name="errorInfo" type="IVirtualBoxErrorInfo" dir="in" />
     </method>
 
Index: /trunk/src/VBox/Main/include/ExtPackManagerImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/ExtPackManagerImpl.h	(revision 74803)
+++ /trunk/src/VBox/Main/include/ExtPackManagerImpl.h	(revision 74804)
@@ -163,5 +163,6 @@
                                                              uint32_t uNextOperationWeight);
     static DECLCALLBACK(uint32_t) i_hlpWaitOtherProgress(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress,
-                                                         VBOXEXTPACK_IF_CS(IProgress) *pProgressOther);
+                                                         VBOXEXTPACK_IF_CS(IProgress) *pProgressOther,
+                                                         uint32_t cTimeoutMS);
     static DECLCALLBACK(uint32_t) i_hlpCompleteProgress(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress,
                                                         uint32_t uResultCode);
Index: /trunk/src/VBox/Main/include/ProgressImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/ProgressImpl.h	(revision 74803)
+++ /trunk/src/VBox/Main/include/ProgressImpl.h	(revision 74804)
@@ -136,30 +136,5 @@
                               const char *aText,
                               va_list va);
-    HRESULT i_notifyCompleteEI(HRESULT aResultCode,
-                               const ComPtr<IVirtualBoxErrorInfo> &aErrorInfo);
-    /**
-     * Waits until the other task is completed (including all sub-operations)
-     * and forward all changes from the other progress to this progress. This
-     * means sub-operation number, description, percent and so on.
-     *
-     * The caller is responsible for having at least the same count of
-     * sub-operations in this progress object as there are in the other
-     * progress object.
-     *
-     * If the other progress object supports cancel and this object gets any
-     * cancel request (when here enabled as well), it will be forwarded to
-     * the other progress object.
-     *
-     * Error information is automatically preserved (by transferring it to
-     * the current thread's error information). If the caller wants to set it
-     * as the completion state of this progress it needs to be done separately.
-     *
-     * @param   aProgressOther  Progress object from which the state is
-     *                  forwarded until it is signalling completion.
-     * @return COM error status, also reflecting the failed completion.
-     */
-    HRESULT i_waitForOtherProgressCompletion(const ComPtr<IProgress> &aProgressOther);
-
-    bool i_notifyPointOfNoReturn(void);
+
     bool i_setCancelCallback(void (*pfnCallback)(void *), void *pvUser);
 
@@ -229,7 +204,4 @@
 
     // wrapped IProgress methods
-    HRESULT setCurrentOperationProgress(ULONG aPercent);
-    HRESULT setNextOperation(const com::Utf8Str &aNextOperationDescription,
-                             ULONG aNextOperationsWeight);
     HRESULT waitForCompletion(LONG aTimeout);
     HRESULT waitForOperationCompletion(ULONG aOperation,
@@ -237,4 +209,14 @@
     HRESULT cancel();
 
+    // wrapped IInternalProgressControl methods
+    HRESULT setCurrentOperationProgress(ULONG aPercent);
+    HRESULT waitForOtherProgressCompletion(const ComPtr<IProgress> &aProgressOther,
+                                           ULONG aTimeoutMS);
+    HRESULT setNextOperation(const com::Utf8Str &aNextOperationDescription,
+                             ULONG aNextOperationsWeight);
+    HRESULT notifyPointOfNoReturn();
+    HRESULT notifyComplete(LONG aResultCode,
+                           const ComPtr<IVirtualBoxErrorInfo> &aErrorInfo);
+
     // internal helper methods
     double i_calcTotalPercent();
Index: /trunk/src/VBox/Main/src-all/ExtPackManagerImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-all/ExtPackManagerImpl.cpp	(revision 74803)
+++ /trunk/src/VBox/Main/src-all/ExtPackManagerImpl.cpp	(revision 74804)
@@ -1810,5 +1810,7 @@
     AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, (uint32_t)E_INVALIDARG);
 
-    return pProgress->SetCurrentOperationProgress(uPercent);
+    ComPtr<IInternalProgressControl> pProgressControl(pProgress);
+    AssertReturn(!!pProgressControl, E_INVALIDARG);
+    return pProgressControl->SetCurrentOperationProgress(uPercent);
 }
 
@@ -1828,10 +1830,12 @@
     AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, (uint32_t)E_INVALIDARG);
 
-    return pProgress->SetNextOperation(Bstr(pcszNextOperationDescription).raw(), uNextOperationWeight);
+    ComPtr<IInternalProgressControl> pProgressControl(pProgress);
+    AssertReturn(!!pProgressControl, E_INVALIDARG);
+    return pProgressControl->SetNextOperation(Bstr(pcszNextOperationDescription).raw(), uNextOperationWeight);
 }
 
 /*static*/ DECLCALLBACK(uint32_t)
 ExtPack::i_hlpWaitOtherProgress(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress,
-                                VBOXEXTPACK_IF_CS(IProgress) *pProgressOther)
+                                VBOXEXTPACK_IF_CS(IProgress) *pProgressOther, uint32_t cTimeoutMS)
 {
     /*
@@ -1844,6 +1848,7 @@
     AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, (uint32_t)E_INVALIDARG);
 
-    Progress *pProgressInt = static_cast<Progress *>(pProgress);
-    return pProgressInt->i_waitForOtherProgressCompletion(pProgressOther);
+    ComPtr<IInternalProgressControl> pProgressControl(pProgress);
+    AssertReturn(!!pProgressControl, E_INVALIDARG);
+    return pProgressControl->WaitForOtherProgressCompletion(pProgressOther, cTimeoutMS);
 }
 
@@ -1860,6 +1865,14 @@
     AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, (uint32_t)E_INVALIDARG);
 
-    Progress *pProgressInt = static_cast<Progress *>(pProgress);
-    return pProgressInt->i_notifyComplete(uResultCode);
+    ComPtr<IInternalProgressControl> pProgressControl(pProgress);
+    AssertReturn(!!pProgressControl, E_INVALIDARG);
+
+    ComPtr<IVirtualBoxErrorInfo> errorInfo;
+    if (FAILED((HRESULT)uResultCode))
+    {
+        ErrorInfoKeeper eik;
+        eik.getVirtualBoxErrorInfo(errorInfo);
+    }
+    return pProgressControl->NotifyComplete(uResultCode, errorInfo);
 }
 
Index: /trunk/src/VBox/Main/src-all/ProgressImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-all/ProgressImpl.cpp	(revision 74803)
+++ /trunk/src/VBox/Main/src-all/ProgressImpl.cpp	(revision 74804)
@@ -370,5 +370,5 @@
     }
 
-    return i_notifyCompleteEI(aResultCode, errorInfo);
+    return notifyComplete(aResultCode, errorInfo);
 }
 
@@ -414,58 +414,465 @@
     errorInfo->init(aResultCode, aIID, pcszComponent, text);
 
-    return i_notifyCompleteEI(aResultCode, errorInfo);
-}
-
-/**
- * Marks the operation as complete and attaches full error info.
- *
- * This is where the actual work is done, the related methods all end up here.
- *
- * @param aResultCode   Operation result (error) code, must not be S_OK.
- * @param aErrorInfo            List of arguments for the format string.
- */
-HRESULT Progress::i_notifyCompleteEI(HRESULT aResultCode, const ComPtr<IVirtualBoxErrorInfo> &aErrorInfo)
-{
-    LogThisFunc(("aResultCode=%d\n", aResultCode));
-    /* on failure we expect error info, on success there must be none */
-    AssertMsg(FAILED(aResultCode) ^ aErrorInfo.isNull(),
-              ("No error info but trying to set a failed result (%08X)!\n",
-               aResultCode));
-
+    return notifyComplete(aResultCode, errorInfo);
+}
+
+/**
+ * Sets the cancelation callback, checking for cancelation first.
+ *
+ * @returns Success indicator.
+ * @retval  true on success.
+ * @retval  false if the progress object has already been canceled or is in an
+ *          invalid state
+ *
+ * @param   pfnCallback     The function to be called upon cancelation.
+ * @param   pvUser          The callback argument.
+ */
+bool Progress::i_setCancelCallback(void (*pfnCallback)(void *), void *pvUser)
+{
     AutoCaller autoCaller(this);
-    AssertComRCReturnRC(autoCaller.rc());
+    AssertComRCReturn(autoCaller.rc(), false);
 
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    AssertReturn(mCompleted == FALSE, E_FAIL);
-
-    if (mCanceled && SUCCEEDED(aResultCode))
-        aResultCode = E_FAIL;
-
-    mCompleted = TRUE;
-    mResultCode = aResultCode;
-    if (SUCCEEDED(aResultCode))
-    {
-        m_ulCurrentOperation = m_cOperations - 1; /* last operation */
-        m_ulOperationPercent = 100;
-    }
-    mErrorInfo = aErrorInfo;
-
+    i_checkForAutomaticTimeout();
+    if (mCanceled)
+        return false;
+
+    m_pvCancelUserArg   = pvUser;
+    m_pfnCancelCallback = pfnCallback;
+    return true;
+}
+
+/**
+ * @callback_method_impl{FNRTPROGRESS,
+ *      Works the progress of the current operation.}
+ */
+/*static*/ DECLCALLBACK(int) Progress::i_iprtProgressCallback(unsigned uPercentage, void *pvUser)
+{
+    Progress *pThis = (Progress *)pvUser;
+
+    /*
+     * Same as setCurrentOperationProgress, except we don't fail on mCompleted.
+     */
+    AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
+    int vrc = VINF_SUCCESS;
+    if (!pThis->mCompleted)
+    {
+        pThis->i_checkForAutomaticTimeout();
+        if (!pThis->mCanceled)
+        {
+            if (uPercentage > pThis->m_ulOperationPercent)
+                pThis->setCurrentOperationProgress(uPercentage);
+        }
+        else
+        {
+            Assert(pThis->mCancelable);
+            vrc = VERR_CANCELLED;
+        }
+    }
+    /* else ignored */
+    return vrc;
+}
+
+/**
+ * @callback_method_impl{FNVDPROGRESS,
+ *      Progress::i_iprtProgressCallback with parameters switched around.}
+ */
+/*static*/ DECLCALLBACK(int) Progress::i_vdProgressCallback(void *pvUser, unsigned uPercentage)
+{
+    return i_iprtProgressCallback(uPercentage, pvUser);
+}
+
+
+// IProgress properties
+/////////////////////////////////////////////////////////////////////////////
+
+HRESULT Progress::getId(com::Guid &aId)
+{
+    /* mId is constant during life time, no need to lock */
+    aId = mId;
+
+    return S_OK;
+}
+
+HRESULT Progress::getDescription(com::Utf8Str &aDescription)
+{
+    /* mDescription is constant during life time, no need to lock */
+    aDescription = mDescription;
+
+    return S_OK;
+}
+HRESULT Progress::getInitiator(ComPtr<IUnknown> &aInitiator)
+{
+    /* mInitiator/mParent are constant during life time, no need to lock */
 #if !defined(VBOX_COM_INPROC)
-    /* remove from the global collection of pending progress operations */
-    if (mParent)
-        mParent->i_removeProgress(mId.ref());
+    if (mInitiator)
+        mInitiator.queryInterfaceTo(aInitiator.asOutParam());
+    else
+    {
+        ComObjPtr<VirtualBox> pVirtualBox(mParent);
+        pVirtualBox.queryInterfaceTo(aInitiator.asOutParam());
+    }
+#else
+    mInitiator.queryInterfaceTo(aInitiator.asOutParam());
 #endif
 
-    /* wake up all waiting threads */
-    if (mWaitersCount > 0)
-        RTSemEventMultiSignal(mCompletedSem);
-
-    fireProgressTaskCompletedEvent(pEventSource, mId.toUtf16().raw());
-
-    return S_OK;
-}
-
-HRESULT Progress::i_waitForOtherProgressCompletion(const ComPtr<IProgress> &aProgressOther)
+    return S_OK;
+}
+
+HRESULT Progress::getCancelable(BOOL *aCancelable)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    *aCancelable = mCancelable;
+
+    return S_OK;
+}
+
+HRESULT Progress::getPercent(ULONG *aPercent)
+{
+    /* i_checkForAutomaticTimeout requires a write lock. */
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    if (mCompleted && SUCCEEDED(mResultCode))
+        *aPercent = 100;
+    else
+    {
+        ULONG ulPercent = (ULONG)i_calcTotalPercent();
+        // do not report 100% until we're really really done with everything
+        // as the Qt GUI dismisses progress dialogs in that case
+        if (    ulPercent == 100
+             && (    m_ulOperationPercent < 100
+                  || (m_ulCurrentOperation < m_cOperations -1)
+                )
+           )
+            *aPercent = 99;
+        else
+            *aPercent = ulPercent;
+    }
+
+    i_checkForAutomaticTimeout();
+
+    return S_OK;
+}
+
+HRESULT Progress::getTimeRemaining(LONG *aTimeRemaining)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    if (mCompleted)
+        *aTimeRemaining = 0;
+    else
+    {
+        double dPercentDone = i_calcTotalPercent();
+        if (dPercentDone < 1)
+            *aTimeRemaining = -1;       // unreliable, or avoid division by 0 below
+        else
+        {
+            uint64_t ullTimeNow = RTTimeMilliTS();
+            uint64_t ullTimeElapsed = ullTimeNow - m_ullTimestamp;
+            uint64_t ullTimeTotal = (uint64_t)((double)ullTimeElapsed * 100 / dPercentDone);
+            uint64_t ullTimeRemaining = ullTimeTotal - ullTimeElapsed;
+
+//          LogFunc(("dPercentDone = %RI32, ullTimeNow = %RI64, ullTimeElapsed = %RI64, ullTimeTotal = %RI64, ullTimeRemaining = %RI64\n",
+//                   (uint32_t)dPercentDone, ullTimeNow, ullTimeElapsed, ullTimeTotal, ullTimeRemaining));
+
+            *aTimeRemaining = (LONG)(ullTimeRemaining / 1000);
+        }
+    }
+
+    return S_OK;
+}
+
+HRESULT Progress::getCompleted(BOOL *aCompleted)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    *aCompleted = mCompleted;
+
+    return S_OK;
+}
+
+HRESULT Progress::getCanceled(BOOL *aCanceled)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    *aCanceled = mCanceled;
+
+    return S_OK;
+}
+
+HRESULT Progress::getResultCode(LONG *aResultCode)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    if (!mCompleted)
+        return setError(E_FAIL, tr("Result code is not available, operation is still in progress"));
+
+    *aResultCode = mResultCode;
+
+    return S_OK;
+}
+
+HRESULT Progress::getErrorInfo(ComPtr<IVirtualBoxErrorInfo> &aErrorInfo)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    if (!mCompleted)
+        return setError(E_FAIL, tr("Error info is not available, operation is still in progress"));
+
+    mErrorInfo.queryInterfaceTo(aErrorInfo.asOutParam());
+
+    return S_OK;
+}
+
+HRESULT Progress::getOperationCount(ULONG *aOperationCount)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    *aOperationCount = m_cOperations;
+
+    return S_OK;
+}
+
+HRESULT Progress::getOperation(ULONG *aOperation)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    *aOperation = m_ulCurrentOperation;
+
+    return S_OK;
+}
+
+HRESULT Progress::getOperationDescription(com::Utf8Str &aOperationDescription)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    aOperationDescription = m_operationDescription;
+
+    return S_OK;
+}
+
+HRESULT Progress::getOperationPercent(ULONG *aOperationPercent)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    if (mCompleted && SUCCEEDED(mResultCode))
+        *aOperationPercent = 100;
+    else
+        *aOperationPercent = m_ulOperationPercent;
+
+    return S_OK;
+}
+
+HRESULT Progress::getOperationWeight(ULONG *aOperationWeight)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    *aOperationWeight = m_ulCurrentOperationWeight;
+
+    return S_OK;
+}
+
+HRESULT Progress::getTimeout(ULONG *aTimeout)
+{
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    *aTimeout = m_cMsTimeout;
+
+    return S_OK;
+}
+
+HRESULT Progress::setTimeout(ULONG aTimeout)
+{
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    if (!mCancelable)
+        return setError(VBOX_E_INVALID_OBJECT_STATE, tr("Operation cannot be canceled"));
+    m_cMsTimeout = aTimeout;
+
+    return S_OK;
+}
+
+HRESULT Progress::getEventSource(ComPtr<IEventSource> &aEventSource)
+{
+    /* event source is const, no need to lock */
+    pEventSource.queryInterfaceTo(aEventSource.asOutParam());
+    return S_OK;
+}
+
+
+// IProgress methods
+/////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @note XPCOM: when this method is not called on the main XPCOM thread, it
+ *       simply blocks the thread until mCompletedSem is signalled. If the
+ *       thread has its own event queue (hmm, what for?) that it must run, then
+ *       calling this method will definitely freeze event processing.
+ */
+HRESULT Progress::waitForCompletion(LONG aTimeout)
+{
+    LogFlowThisFuncEnter();
+    LogFlowThisFunc(("aTimeout=%d\n", aTimeout));
+
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    /* if we're already completed, take a shortcut */
+    if (!mCompleted)
+    {
+        int vrc = VINF_SUCCESS;
+        bool fForever = aTimeout < 0;
+        int64_t timeLeft = aTimeout;
+        int64_t lastTime = RTTimeMilliTS();
+
+        while (!mCompleted && (fForever || timeLeft > 0))
+        {
+            mWaitersCount++;
+            alock.release();
+            vrc = RTSemEventMultiWait(mCompletedSem,
+                                      fForever ? RT_INDEFINITE_WAIT : (RTMSINTERVAL)timeLeft);
+            alock.acquire();
+            mWaitersCount--;
+
+            /* the last waiter resets the semaphore */
+            if (mWaitersCount == 0)
+                RTSemEventMultiReset(mCompletedSem);
+
+            if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
+                break;
+
+            if (!fForever)
+            {
+                int64_t now = RTTimeMilliTS();
+                timeLeft -= now - lastTime;
+                lastTime = now;
+            }
+        }
+
+        if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
+            return setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Failed to wait for the task completion (%Rrc)"), vrc);
+    }
+
+    LogFlowThisFuncLeave();
+
+    return S_OK;
+}
+
+/**
+ * @note XPCOM: when this method is not called on the main XPCOM thread, it
+ *       simply blocks the thread until mCompletedSem is signalled. If the
+ *       thread has its own event queue (hmm, what for?) that it must run, then
+ *       calling this method will definitely freeze event processing.
+ */
+HRESULT Progress::waitForOperationCompletion(ULONG aOperation, LONG aTimeout)
+
+{
+    LogFlowThisFuncEnter();
+    LogFlowThisFunc(("aOperation=%d, aTimeout=%d\n", aOperation, aTimeout));
+
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    CheckComArgExpr(aOperation, aOperation < m_cOperations);
+
+    /* if we're already completed or if the given operation is already done,
+     * then take a shortcut */
+    if (    !mCompleted
+         && aOperation >= m_ulCurrentOperation)
+    {
+        int vrc = VINF_SUCCESS;
+        bool fForever = aTimeout < 0;
+        int64_t timeLeft = aTimeout;
+        int64_t lastTime = RTTimeMilliTS();
+
+        while (    !mCompleted && aOperation >= m_ulCurrentOperation
+                && (fForever || timeLeft > 0))
+        {
+            mWaitersCount ++;
+            alock.release();
+            vrc = RTSemEventMultiWait(mCompletedSem,
+                                      fForever ? RT_INDEFINITE_WAIT : (unsigned) timeLeft);
+            alock.acquire();
+            mWaitersCount--;
+
+            /* the last waiter resets the semaphore */
+            if (mWaitersCount == 0)
+                RTSemEventMultiReset(mCompletedSem);
+
+            if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
+                break;
+
+            if (!fForever)
+            {
+                int64_t now = RTTimeMilliTS();
+                timeLeft -= now - lastTime;
+                lastTime = now;
+            }
+        }
+
+        if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
+            return setErrorBoth(E_FAIL, vrc, tr("Failed to wait for the operation completion (%Rrc)"), vrc);
+    }
+
+    LogFlowThisFuncLeave();
+
+    return S_OK;
+}
+
+HRESULT Progress::cancel()
+{
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    if (!mCancelable)
+        return setError(VBOX_E_INVALID_OBJECT_STATE, tr("Operation cannot be canceled"));
+
+    if (!mCanceled)
+    {
+        LogThisFunc(("Canceling\n"));
+        mCanceled = TRUE;
+        if (m_pfnCancelCallback)
+            m_pfnCancelCallback(m_pvCancelUserArg);
+
+    }
+    else
+        LogThisFunc(("Already canceled\n"));
+
+    return S_OK;
+}
+
+
+// IInternalProgressControl methods
+/////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Updates the percentage value of the current operation.
+ *
+ * @param aPercent  New percentage value of the operation in progress
+ *                  (in range [0, 100]).
+ */
+HRESULT Progress::setCurrentOperationProgress(ULONG aPercent)
+{
+    AssertMsgReturn(aPercent <= 100, ("%u\n", aPercent), E_INVALIDARG);
+
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    i_checkForAutomaticTimeout();
+    if (mCancelable && mCanceled)
+        AssertReturn(!mCompleted, E_FAIL);
+    AssertReturn(!mCompleted && !mCanceled, E_FAIL);
+
+    if (m_ulOperationPercent != aPercent)
+    {
+        m_ulOperationPercent = aPercent;
+        ULONG actualPercent = 0;
+        getPercent(&actualPercent);
+        fireProgressPercentageChangedEvent(pEventSource, mId.toUtf16().raw(), actualPercent);
+    }
+
+    return S_OK;
+}
+
+HRESULT Progress::waitForOtherProgressCompletion(const ComPtr<IProgress> &aProgressOther,
+                                                 ULONG aTimeoutMS)
 {
     LogFlowThisFuncEnter();
@@ -483,4 +890,8 @@
     rc = aProgressOther->COMGETTER(Cancelable)(&fCancelable);
     if (FAILED(rc)) return rc;
+
+    uint64_t u64StopTime = UINT64_MAX;
+    if (aTimeoutMS > 0)
+        u64StopTime = RTTimeMilliTS() + aTimeoutMS;
     /* Loop as long as the sync process isn't completed. */
     while (SUCCEEDED(aProgressOther->COMGETTER(Completed(&fCompleted))))
@@ -541,7 +952,25 @@
             break;
 
-        /* Make sure the loop is not too tight */
-        rc = aProgressOther->WaitForCompletion(100);
-        if (FAILED(rc)) return rc;
+        if (aTimeoutMS != 0)
+        {
+            /* Make sure the loop is not too tight */
+            uint64_t u64Now = RTTimeMilliTS();
+            uint64_t u64RemainingMS = u64StopTime - u64Now;
+            if (u64RemainingMS < 10)
+                u64RemainingMS = 10;
+            else if (u64RemainingMS > 200)
+                u64RemainingMS = 200;
+            rc = aProgressOther->WaitForCompletion((LONG)u64RemainingMS);
+            if (FAILED(rc)) return rc;
+
+            if (RTTimeMilliTS() >= u64StopTime)
+                return VBOX_E_TIMEOUT;
+        }
+        else
+        {
+            /* Make sure the loop is not too tight */
+            rc = aProgressOther->WaitForCompletion(200);
+            if (FAILED(rc)) return rc;
+        }
     }
 
@@ -562,4 +991,43 @@
 
 /**
+ * Signals that the current operation is successfully completed and advances to
+ * the next operation. The operation percentage is reset to 0.
+ *
+ * @param aNextOperationDescription  Description of the next operation.
+ * @param aNextOperationsWeight     Weight of the next operation.
+ *
+ * @note The current operation must not be the last one.
+ */
+HRESULT Progress::setNextOperation(const com::Utf8Str &aNextOperationDescription, ULONG aNextOperationsWeight)
+{
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    if (mCanceled)
+        return E_FAIL;
+    AssertReturn(!mCompleted, E_FAIL);
+    AssertReturn(m_ulCurrentOperation + 1 < m_cOperations, E_FAIL);
+
+    ++m_ulCurrentOperation;
+    m_ulOperationsCompletedWeight += m_ulCurrentOperationWeight;
+
+    m_operationDescription = aNextOperationDescription;
+    m_ulCurrentOperationWeight = aNextOperationsWeight;
+    m_ulOperationPercent = 0;
+
+    LogThisFunc(("%s: aNextOperationsWeight = %d; m_ulCurrentOperation is now %d, m_ulOperationsCompletedWeight is now %d\n",
+                 m_operationDescription.c_str(), aNextOperationsWeight, m_ulCurrentOperation, m_ulOperationsCompletedWeight));
+
+    /* wake up all waiting threads */
+    if (mWaitersCount > 0)
+        RTSemEventMultiSignal(mCompletedSem);
+
+    ULONG actualPercent = 0;
+    getPercent(&actualPercent);
+    fireProgressPercentageChangedEvent(pEventSource, mId.toUtf16().raw(), actualPercent);
+
+    return S_OK;
+}
+
+/**
  * Notify the progress object that we're almost at the point of no return.
  *
@@ -570,363 +1038,61 @@
  * user believe it was rolled back.
  *
- * @returns Success indicator.
- * @retval  true on success.
- * @retval  false if the progress object has already been canceled or is in an
+ * @returns COM error status.
+ * @retval  S_OK on success.
+ * @retval  E_FAIL if the progress object has already been canceled or is in an
  *          invalid state
  */
-bool Progress::i_notifyPointOfNoReturn(void)
-{
-    AutoCaller autoCaller(this);
-    AssertComRCReturn(autoCaller.rc(), false);
-
+HRESULT Progress::notifyPointOfNoReturn(void)
+{
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
     if (mCanceled)
     {
-        LogThisFunc(("returns false\n"));
-        return false;
+        LogThisFunc(("returns failure\n"));
+        return E_FAIL;
     }
 
     mCancelable = FALSE;
-    LogThisFunc(("returns true\n"));
-    return true;
-}
-
-/**
- * Sets the cancelation callback, checking for cancelation first.
- *
- * @returns Success indicator.
- * @retval  true on success.
- * @retval  false if the progress object has already been canceled or is in an
- *          invalid state
- *
- * @param   pfnCallback     The function to be called upon cancelation.
- * @param   pvUser          The callback argument.
- */
-bool Progress::i_setCancelCallback(void (*pfnCallback)(void *), void *pvUser)
-{
-    AutoCaller autoCaller(this);
-    AssertComRCReturn(autoCaller.rc(), false);
+    LogThisFunc(("returns success\n"));
+    return S_OK;
+}
+
+/**
+ * Marks the operation as complete and attaches full error info.
+ *
+ * This is where the actual work is done, the related methods all end up here.
+ *
+ * @param aResultCode   Operation result (error) code, must not be S_OK.
+ * @param aErrorInfo            List of arguments for the format string.
+ */
+HRESULT Progress::notifyComplete(LONG aResultCode, const ComPtr<IVirtualBoxErrorInfo> &aErrorInfo)
+{
+    LogThisFunc(("aResultCode=%d\n", aResultCode));
+    /* on failure we expect error info, on success there must be none */
+    AssertMsg(FAILED(aResultCode) ^ aErrorInfo.isNull(),
+              ("No error info but trying to set a failed result (%08X)!\n",
+               aResultCode));
 
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    i_checkForAutomaticTimeout();
-    if (mCanceled)
-        return false;
-
-    m_pvCancelUserArg   = pvUser;
-    m_pfnCancelCallback = pfnCallback;
-    return true;
-}
-
-/**
- * @callback_method_impl{FNRTPROGRESS,
- *      Works the progress of the current operation.}
- */
-/*static*/ DECLCALLBACK(int) Progress::i_iprtProgressCallback(unsigned uPercentage, void *pvUser)
-{
-    Progress *pThis = (Progress *)pvUser;
-
-    /*
-     * Same as setCurrentOperationProgress, except we don't fail on mCompleted.
-     */
-    AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
-    int vrc = VINF_SUCCESS;
-    if (!pThis->mCompleted)
-    {
-        pThis->i_checkForAutomaticTimeout();
-        if (!pThis->mCanceled)
-        {
-            if (uPercentage > pThis->m_ulOperationPercent)
-                pThis->setCurrentOperationProgress(uPercentage);
-        }
-        else
-        {
-            Assert(pThis->mCancelable);
-            vrc = VERR_CANCELLED;
-        }
-    }
-    /* else ignored */
-    return vrc;
-}
-
-/**
- * @callback_method_impl{FNVDPROGRESS,
- *      Progress::i_iprtProgressCallback with parameters switched around.}
- */
-/*static*/ DECLCALLBACK(int) Progress::i_vdProgressCallback(void *pvUser, unsigned uPercentage)
-{
-    return i_iprtProgressCallback(uPercentage, pvUser);
-}
-
-// IProgress properties
-/////////////////////////////////////////////////////////////////////////////
-
-HRESULT Progress::getId(com::Guid &aId)
-{
-    /* mId is constant during life time, no need to lock */
-    aId = mId;
-
-    return S_OK;
-}
-
-HRESULT Progress::getDescription(com::Utf8Str &aDescription)
-{
-    /* mDescription is constant during life time, no need to lock */
-    aDescription = mDescription;
-
-    return S_OK;
-}
-HRESULT Progress::getInitiator(ComPtr<IUnknown> &aInitiator)
-{
-    /* mInitiator/mParent are constant during life time, no need to lock */
+    AssertReturn(mCompleted == FALSE, E_FAIL);
+
+    if (mCanceled && SUCCEEDED(aResultCode))
+        aResultCode = E_FAIL;
+
+    mCompleted = TRUE;
+    mResultCode = aResultCode;
+    if (SUCCEEDED(aResultCode))
+    {
+        m_ulCurrentOperation = m_cOperations - 1; /* last operation */
+        m_ulOperationPercent = 100;
+    }
+    mErrorInfo = aErrorInfo;
+
 #if !defined(VBOX_COM_INPROC)
-    if (mInitiator)
-        mInitiator.queryInterfaceTo(aInitiator.asOutParam());
-    else
-    {
-        ComObjPtr<VirtualBox> pVirtualBox(mParent);
-        pVirtualBox.queryInterfaceTo(aInitiator.asOutParam());
-    }
-#else
-    mInitiator.queryInterfaceTo(aInitiator.asOutParam());
+    /* remove from the global collection of pending progress operations */
+    if (mParent)
+        mParent->i_removeProgress(mId.ref());
 #endif
-
-    return S_OK;
-}
-
-HRESULT Progress::getCancelable(BOOL *aCancelable)
-{
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    *aCancelable = mCancelable;
-
-    return S_OK;
-}
-
-HRESULT Progress::getPercent(ULONG *aPercent)
-{
-    /* i_checkForAutomaticTimeout requires a write lock. */
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    if (mCompleted && SUCCEEDED(mResultCode))
-        *aPercent = 100;
-    else
-    {
-        ULONG ulPercent = (ULONG)i_calcTotalPercent();
-        // do not report 100% until we're really really done with everything
-        // as the Qt GUI dismisses progress dialogs in that case
-        if (    ulPercent == 100
-             && (    m_ulOperationPercent < 100
-                  || (m_ulCurrentOperation < m_cOperations -1)
-                )
-           )
-            *aPercent = 99;
-        else
-            *aPercent = ulPercent;
-    }
-
-    i_checkForAutomaticTimeout();
-
-    return S_OK;
-}
-
-HRESULT Progress::getTimeRemaining(LONG *aTimeRemaining)
-{
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    if (mCompleted)
-        *aTimeRemaining = 0;
-    else
-    {
-        double dPercentDone = i_calcTotalPercent();
-        if (dPercentDone < 1)
-            *aTimeRemaining = -1;       // unreliable, or avoid division by 0 below
-        else
-        {
-            uint64_t ullTimeNow = RTTimeMilliTS();
-            uint64_t ullTimeElapsed = ullTimeNow - m_ullTimestamp;
-            uint64_t ullTimeTotal = (uint64_t)((double)ullTimeElapsed * 100 / dPercentDone);
-            uint64_t ullTimeRemaining = ullTimeTotal - ullTimeElapsed;
-
-//          LogFunc(("dPercentDone = %RI32, ullTimeNow = %RI64, ullTimeElapsed = %RI64, ullTimeTotal = %RI64, ullTimeRemaining = %RI64\n",
-//                   (uint32_t)dPercentDone, ullTimeNow, ullTimeElapsed, ullTimeTotal, ullTimeRemaining));
-
-            *aTimeRemaining = (LONG)(ullTimeRemaining / 1000);
-        }
-    }
-
-    return S_OK;
-}
-
-HRESULT Progress::getCompleted(BOOL *aCompleted)
-{
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    *aCompleted = mCompleted;
-
-    return S_OK;
-}
-
-HRESULT Progress::getCanceled(BOOL *aCanceled)
-{
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    *aCanceled = mCanceled;
-
-    return S_OK;
-}
-
-HRESULT Progress::getResultCode(LONG *aResultCode)
-{
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    if (!mCompleted)
-        return setError(E_FAIL, tr("Result code is not available, operation is still in progress"));
-
-    *aResultCode = mResultCode;
-
-    return S_OK;
-}
-
-HRESULT Progress::getErrorInfo(ComPtr<IVirtualBoxErrorInfo> &aErrorInfo)
-{
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    if (!mCompleted)
-        return setError(E_FAIL, tr("Error info is not available, operation is still in progress"));
-
-    mErrorInfo.queryInterfaceTo(aErrorInfo.asOutParam());
-
-    return S_OK;
-}
-
-HRESULT Progress::getOperationCount(ULONG *aOperationCount)
-{
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    *aOperationCount = m_cOperations;
-
-    return S_OK;
-}
-
-HRESULT Progress::getOperation(ULONG *aOperation)
-{
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    *aOperation = m_ulCurrentOperation;
-
-    return S_OK;
-}
-
-HRESULT Progress::getOperationDescription(com::Utf8Str &aOperationDescription)
-{
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    aOperationDescription = m_operationDescription;
-
-    return S_OK;
-}
-
-HRESULT Progress::getOperationPercent(ULONG *aOperationPercent)
-{
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    if (mCompleted && SUCCEEDED(mResultCode))
-        *aOperationPercent = 100;
-    else
-        *aOperationPercent = m_ulOperationPercent;
-
-    return S_OK;
-}
-
-HRESULT Progress::getOperationWeight(ULONG *aOperationWeight)
-{
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    *aOperationWeight = m_ulCurrentOperationWeight;
-
-    return S_OK;
-}
-
-HRESULT Progress::getTimeout(ULONG *aTimeout)
-{
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    *aTimeout = m_cMsTimeout;
-
-    return S_OK;
-}
-
-HRESULT Progress::setTimeout(ULONG aTimeout)
-{
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    if (!mCancelable)
-        return setError(VBOX_E_INVALID_OBJECT_STATE, tr("Operation cannot be canceled"));
-    m_cMsTimeout = aTimeout;
-
-    return S_OK;
-}
-
-
-// IProgress methods
-/////////////////////////////////////////////////////////////////////////////
-
-/**
- * Updates the percentage value of the current operation.
- *
- * @param aPercent  New percentage value of the operation in progress
- *                  (in range [0, 100]).
- */
-HRESULT Progress::setCurrentOperationProgress(ULONG aPercent)
-{
-    AssertMsgReturn(aPercent <= 100, ("%u\n", aPercent), E_INVALIDARG);
-
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    i_checkForAutomaticTimeout();
-    if (mCancelable && mCanceled)
-        AssertReturn(!mCompleted, E_FAIL);
-    AssertReturn(!mCompleted && !mCanceled, E_FAIL);
-
-    if (m_ulOperationPercent != aPercent)
-    {
-        m_ulOperationPercent = aPercent;
-        ULONG actualPercent = 0;
-        getPercent(&actualPercent);
-        fireProgressPercentageChangedEvent(pEventSource, mId.toUtf16().raw(), actualPercent);
-    }
-
-    return S_OK;
-}
-
-/**
- * Signals that the current operation is successfully completed and advances to
- * the next operation. The operation percentage is reset to 0.
- *
- * @param aNextOperationDescription  Description of the next operation.
- * @param aNextOperationsWeight     Weight of the next operation.
- *
- * @note The current operation must not be the last one.
- */
-HRESULT Progress::setNextOperation(const com::Utf8Str &aNextOperationDescription, ULONG aNextOperationsWeight)
-{
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    if (mCanceled)
-        return E_FAIL;
-    AssertReturn(!mCompleted, E_FAIL);
-    AssertReturn(m_ulCurrentOperation + 1 < m_cOperations, E_FAIL);
-
-    ++m_ulCurrentOperation;
-    m_ulOperationsCompletedWeight += m_ulCurrentOperationWeight;
-
-    m_operationDescription = aNextOperationDescription;
-    m_ulCurrentOperationWeight = aNextOperationsWeight;
-    m_ulOperationPercent = 0;
-
-    LogThisFunc(("%s: aNextOperationsWeight = %d; m_ulCurrentOperation is now %d, m_ulOperationsCompletedWeight is now %d\n",
-                 m_operationDescription.c_str(), aNextOperationsWeight, m_ulCurrentOperation, m_ulOperationsCompletedWeight));
 
     /* wake up all waiting threads */
@@ -934,152 +1100,9 @@
         RTSemEventMultiSignal(mCompletedSem);
 
-    ULONG actualPercent = 0;
-    getPercent(&actualPercent);
-    fireProgressPercentageChangedEvent(pEventSource, mId.toUtf16().raw(), actualPercent);
-
-    return S_OK;
-}
-
-/**
- * @note XPCOM: when this method is not called on the main XPCOM thread, it
- *       simply blocks the thread until mCompletedSem is signalled. If the
- *       thread has its own event queue (hmm, what for?) that it must run, then
- *       calling this method will definitely freeze event processing.
- */
-HRESULT Progress::waitForCompletion(LONG aTimeout)
-{
-    LogFlowThisFuncEnter();
-    LogFlowThisFunc(("aTimeout=%d\n", aTimeout));
-
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    /* if we're already completed, take a shortcut */
-    if (!mCompleted)
-    {
-        int vrc = VINF_SUCCESS;
-        bool fForever = aTimeout < 0;
-        int64_t timeLeft = aTimeout;
-        int64_t lastTime = RTTimeMilliTS();
-
-        while (!mCompleted && (fForever || timeLeft > 0))
-        {
-            mWaitersCount++;
-            alock.release();
-            vrc = RTSemEventMultiWait(mCompletedSem,
-                                      fForever ? RT_INDEFINITE_WAIT : (RTMSINTERVAL)timeLeft);
-            alock.acquire();
-            mWaitersCount--;
-
-            /* the last waiter resets the semaphore */
-            if (mWaitersCount == 0)
-                RTSemEventMultiReset(mCompletedSem);
-
-            if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
-                break;
-
-            if (!fForever)
-            {
-                int64_t now = RTTimeMilliTS();
-                timeLeft -= now - lastTime;
-                lastTime = now;
-            }
-        }
-
-        if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
-            return setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Failed to wait for the task completion (%Rrc)"), vrc);
-    }
-
-    LogFlowThisFuncLeave();
-
-    return S_OK;
-}
-
-/**
- * @note XPCOM: when this method is not called on the main XPCOM thread, it
- *       simply blocks the thread until mCompletedSem is signalled. If the
- *       thread has its own event queue (hmm, what for?) that it must run, then
- *       calling this method will definitely freeze event processing.
- */
-HRESULT Progress::waitForOperationCompletion(ULONG aOperation, LONG aTimeout)
-
-{
-    LogFlowThisFuncEnter();
-    LogFlowThisFunc(("aOperation=%d, aTimeout=%d\n", aOperation, aTimeout));
-
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    CheckComArgExpr(aOperation, aOperation < m_cOperations);
-
-    /* if we're already completed or if the given operation is already done,
-     * then take a shortcut */
-    if (    !mCompleted
-         && aOperation >= m_ulCurrentOperation)
-    {
-        int vrc = VINF_SUCCESS;
-        bool fForever = aTimeout < 0;
-        int64_t timeLeft = aTimeout;
-        int64_t lastTime = RTTimeMilliTS();
-
-        while (    !mCompleted && aOperation >= m_ulCurrentOperation
-                && (fForever || timeLeft > 0))
-        {
-            mWaitersCount ++;
-            alock.release();
-            vrc = RTSemEventMultiWait(mCompletedSem,
-                                      fForever ? RT_INDEFINITE_WAIT : (unsigned) timeLeft);
-            alock.acquire();
-            mWaitersCount--;
-
-            /* the last waiter resets the semaphore */
-            if (mWaitersCount == 0)
-                RTSemEventMultiReset(mCompletedSem);
-
-            if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
-                break;
-
-            if (!fForever)
-            {
-                int64_t now = RTTimeMilliTS();
-                timeLeft -= now - lastTime;
-                lastTime = now;
-            }
-        }
-
-        if (RT_FAILURE(vrc) && vrc != VERR_TIMEOUT)
-            return setErrorBoth(E_FAIL, vrc, tr("Failed to wait for the operation completion (%Rrc)"), vrc);
-    }
-
-    LogFlowThisFuncLeave();
-
-    return S_OK;
-}
-
-HRESULT Progress::cancel()
-{
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    if (!mCancelable)
-        return setError(VBOX_E_INVALID_OBJECT_STATE, tr("Operation cannot be canceled"));
-
-    if (!mCanceled)
-    {
-        LogThisFunc(("Canceling\n"));
-        mCanceled = TRUE;
-        if (m_pfnCancelCallback)
-            m_pfnCancelCallback(m_pvCancelUserArg);
-
-    }
-    else
-        LogThisFunc(("Already canceled\n"));
-
-    return S_OK;
-}
-
-HRESULT Progress::getEventSource(ComPtr<IEventSource> &aEventSource)
-{
-    /* event source is const, no need to lock */
-    pEventSource.queryInterfaceTo(aEventSource.asOutParam());
-    return S_OK;
-}
+    fireProgressTaskCompletedEvent(pEventSource, mId.toUtf16().raw());
+
+    return S_OK;
+}
+
 
 // private internal helpers
Index: /trunk/src/VBox/Main/src-client/ConsoleImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/ConsoleImpl.cpp	(revision 74803)
+++ /trunk/src/VBox/Main/src-client/ConsoleImpl.cpp	(revision 74804)
@@ -6239,5 +6239,9 @@
     IProgress *pProgress = static_cast<IProgress *>(pvUser);
     if (pProgress)
-        rc = pProgress->SetCurrentOperationProgress(uPercentage);
+    {
+        ComPtr<IInternalProgressControl> pProgressControl(pProgress);
+        AssertReturn(!!pProgressControl, VERR_INVALID_PARAMETER);
+        rc = pProgressControl->SetCurrentOperationProgress(uPercentage);
+    }
     return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
 }
@@ -7855,4 +7859,6 @@
     AssertComRCReturnRC(autoCaller.rc());
 
+    ComPtr<IInternalProgressControl> pProgressControl(aProgress);
+
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
@@ -7947,6 +7953,6 @@
 
     /* advance percent count */
-    if (aProgress)
-        aProgress->SetCurrentOperationProgress(99 * (++step) / StepCount );
+    if (pProgressControl)
+        pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
 
 
@@ -7976,6 +7982,6 @@
 
     /* advance percent count */
-    if (aProgress)
-        aProgress->SetCurrentOperationProgress(99 * (++step) / StepCount );
+    if (pProgressControl)
+        pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
 
     vrc = VINF_SUCCESS;
@@ -8001,6 +8007,6 @@
 
     /* advance percent count */
-    if (aProgress)
-        aProgress->SetCurrentOperationProgress(99 * (++step) / StepCount );
+    if (pProgressControl)
+        pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
 
 #ifdef VBOX_WITH_HGCM
@@ -8019,6 +8025,6 @@
 
     /* advance percent count */
-    if (aProgress)
-        aProgress->SetCurrentOperationProgress(99 * (++step) / StepCount);
+    if (pProgressControl)
+        pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
 
 #endif /* VBOX_WITH_HGCM */
@@ -8061,6 +8067,6 @@
 
         /* advance percent count */
-        if (aProgress)
-            aProgress->SetCurrentOperationProgress(99 * (++step) / StepCount);
+        if (pProgressControl)
+            pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
 
         if (RT_SUCCESS(vrc))
@@ -8093,6 +8099,6 @@
 
         /* advance percent count */
-        if (aProgress)
-            aProgress->SetCurrentOperationProgress(99 * (++step) / StepCount);
+        if (pProgressControl)
+            pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
     }
     else
@@ -9504,5 +9510,9 @@
     /* update the progress object */
     if (pProgress)
-        pProgress->SetCurrentOperationProgress(uPercent);
+    {
+        ComPtr<IInternalProgressControl> pProgressControl(pProgress);
+        AssertReturn(!!pProgressControl, VERR_INVALID_PARAMETER);
+        pProgressControl->SetCurrentOperationProgress(uPercent);
+    }
 
     NOREF(pUVM);
Index: /trunk/src/VBox/Main/src-client/ConsoleImplTeleporter.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/ConsoleImplTeleporter.cpp	(revision 74803)
+++ /trunk/src/VBox/Main/src-client/ConsoleImplTeleporter.cpp	(revision 74804)
@@ -718,5 +718,5 @@
      * We're at the point of no return.
      */
-    if (!pState->mptrProgress->i_notifyPointOfNoReturn())
+    if (FAILED(pState->mptrProgress->NotifyPointOfNoReturn()))
     {
         i_teleporterSrcSubmitCommand(pState, "cancel", false /*fWaitForAck*/);
@@ -1414,5 +1414,5 @@
              *       make it possible to recover from some VMR3Resume failures.
              */
-            if (   pState->mptrProgress->i_notifyPointOfNoReturn()
+            if (   SUCCEEDED(pState->mptrProgress->NotifyPointOfNoReturn())
                 && pState->mfLockedMedia)
             {
Index: /trunk/src/VBox/Main/src-server/ApplianceImplImport.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/ApplianceImplImport.cpp	(revision 74803)
+++ /trunk/src/VBox/Main/src-server/ApplianceImplImport.cpp	(revision 74804)
@@ -2656,5 +2656,5 @@
                 /* Now wait for the background import operation to complete; this throws
                  * HRESULTs on error. */
-                stack.pProgress->i_waitForOtherProgressCompletion(pProgressImport);
+                stack.pProgress->WaitForOtherProgressCompletion(pProgressImport, 0 /* indefinite wait */);
             }
         }
Index: /trunk/src/VBox/Main/src-server/MachineImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/MachineImpl.cpp	(revision 74803)
+++ /trunk/src/VBox/Main/src-server/MachineImpl.cpp	(revision 74804)
@@ -5498,5 +5498,5 @@
                 rc = pMedium->DeleteStorage(pProgress2.asOutParam());
                 if (FAILED(rc)) throw rc;
-                rc = task.m_pProgress->i_waitForOtherProgressCompletion(pProgress2);
+                rc = task.m_pProgress->WaitForOtherProgressCompletion(pProgress2, 0 /* indefinite wait */);
                 if (FAILED(rc)) throw rc;
             }
@@ -10943,4 +10943,7 @@
     LogFlowThisFunc(("aOnline=%d\n", aOnline));
 
+    ComPtr<IInternalProgressControl> pProgressControl(aProgress);
+    AssertReturn(!!pProgressControl, E_INVALIDARG);
+
     AutoCaller autoCaller(this);
     AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
@@ -11048,10 +11051,10 @@
                 {
                     if (pMedium == NULL)
-                        aProgress->SetNextOperation(Bstr(tr("Skipping attachment without medium")).raw(),
-                                                    aWeight);        // weight
+                        pProgressControl->SetNextOperation(Bstr(tr("Skipping attachment without medium")).raw(),
+                                                           aWeight);        // weight
                     else
-                        aProgress->SetNextOperation(BstrFmt(tr("Skipping medium '%s'"),
-                                                            pMedium->i_getBase()->i_getName().c_str()).raw(),
-                                                    aWeight);        // weight
+                        pProgressControl->SetNextOperation(BstrFmt(tr("Skipping medium '%s'"),
+                                                                   pMedium->i_getBase()->i_getName().c_str()).raw(),
+                                                           aWeight);        // weight
                 }
 
@@ -11061,7 +11064,7 @@
 
             /* need a diff */
-            aProgress->SetNextOperation(BstrFmt(tr("Creating differencing hard disk for '%s'"),
-                                                pMedium->i_getBase()->i_getName().c_str()).raw(),
-                                        aWeight);        // weight
+            pProgressControl->SetNextOperation(BstrFmt(tr("Creating differencing hard disk for '%s'"),
+                                                       pMedium->i_getBase()->i_getName().c_str()).raw(),
+                                               aWeight);        // weight
 
             Utf8Str strFullSnapshotFolder;
Index: /trunk/src/VBox/Main/src-server/MachineImplCloneVM.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/MachineImplCloneVM.cpp	(revision 74803)
+++ /trunk/src/VBox/Main/src-server/MachineImplCloneVM.cpp	(revision 74804)
@@ -1290,5 +1290,5 @@
                         /* Wait until the async process has finished. */
                         srcLock.release();
-                        rc = d->pProgress->i_waitForOtherProgressCompletion(progress2);
+                        rc = d->pProgress->WaitForOtherProgressCompletion(progress2, 0 /* indefinite wait */);
                         srcLock.acquire();
                         if (FAILED(rc)) throw rc;
Index: /trunk/src/VBox/Main/src-server/MachineImplMoveVM.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/MachineImplMoveVM.cpp	(revision 74803)
+++ /trunk/src/VBox/Main/src-server/MachineImplMoveVM.cpp	(revision 74804)
@@ -1114,5 +1114,5 @@
                  */
                 /* Wait until the other process has finished. */
-                rc = m_pProgress->i_waitForOtherProgressCompletion(moveDiskProgress);
+                rc = m_pProgress->WaitForOtherProgressCompletion(moveDiskProgress, 0 /* indefinite wait */);
             }
 
Index: /trunk/src/VBox/Main/src-server/SnapshotImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/SnapshotImpl.cpp	(revision 74803)
+++ /trunk/src/VBox/Main/src-server/SnapshotImpl.cpp	(revision 74804)
@@ -1747,5 +1747,5 @@
                 LogRel(("Machine: skipped saving state as part of online snapshot\n"));
 
-            if (!task.m_pProgress->i_notifyPointOfNoReturn())
+            if (FAILED(task.m_pProgress->NotifyPointOfNoReturn()))
                 throw setError(E_FAIL, tr("Canceled"));
 
