ProgressImpl.cpp revision c7406a0a49c0faf05ed735c67c128fd09a0360b0
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * VirtualBox Progress COM class implementation
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Copyright (C) 2006-2013 Oracle Corporation
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * available from http://www.virtualbox.org. This file is free software;
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif /* defined(VBOX_WITH_XPCOM) */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync// IProgress properties
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/////////////////////////////////////////////////////////////////////////////
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* mId is constant during life time, no need to lock */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncHRESULT Progress::getDescription(com::Utf8Str &aDescription)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* mDescription is constant during life time, no need to lock */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncHRESULT Progress::getInitiator(ComPtr<IUnknown> &aInitiator)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* mInitiator/mParent are constant during life time, no need to lock */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync mInitiator.queryInterfaceTo(aInitiator.asOutParam());
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVirtualBox.queryInterfaceTo(aInitiator.asOutParam());
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync mInitiator.queryInterfaceTo(aInitiator.asOutParam());
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Internal helper to compute the total percent value based on the member values and
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * returns it as a "double". This is used both by GetPercent (which returns it as a
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * rounded ULONG) and GetTimeRemaining().
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Requires locking by the caller!
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @return fractional percentage as a double value.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync // avoid division by zero
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync double dPercent = ( (double)m_ulOperationsCompletedWeight // weight of operations that have been completed
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync (double)m_ulCurrentOperationWeight / (double)100) // plus partial weight of the current operation
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync ) * (double)100 / (double)m_ulTotalOperationsWeight;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Internal helper for automatically timing out the operation.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * The caller should hold the object write lock.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncHRESULT Progress::getTimeRemaining(LONG *aTimeRemaining)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *aTimeRemaining = -1; // unreliable, or avoid division by 0 below
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint64_t ullTimeElapsed = ullTimeNow - m_ullTimestamp;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint64_t ullTimeTotal = (uint64_t)(ullTimeElapsed * 100 / dPercentDone);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync uint64_t ullTimeRemaining = ullTimeTotal - ullTimeElapsed;
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync// Log(("Progress::GetTimeRemaining: dPercentDone %RI32, ullTimeNow = %RI64, ullTimeElapsed = %RI64, ullTimeTotal = %RI64, ullTimeRemaining = %RI64\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync// (uint32_t)dPercentDone, ullTimeNow, ullTimeElapsed, ullTimeTotal, ullTimeRemaining));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* checkForAutomaticTimeout requires a write lock. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync // do not report 100% until we're really really done with everything as the Qt GUI dismisses progress dialogs in that case
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync tr("Result code is not available, operation is still in progress"));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncHRESULT Progress::getErrorInfo(ComPtr<IVirtualBoxErrorInfo> &aErrorInfo)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync tr("Error info is not available, operation is still in progress"));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync mErrorInfo.queryInterfaceTo(aErrorInfo.asOutParam());
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncHRESULT Progress::getOperationCount(ULONG *aOperationCount)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncHRESULT Progress::getOperationDescription(com::Utf8Str &aOperationDescription)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncHRESULT Progress::getOperationPercent(ULONG *aOperationPercent)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncHRESULT Progress::getOperationWeight(ULONG *aOperationWeight)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogThisFunc(("%#x => %#x\n", m_cMsTimeout, aTimeout));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync// public methods only for internal purposes
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync////////////////////////////////////////////////////////////////////////////////
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Sets the cancelation callback, checking for cancelation first.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns Success indicator.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @retval true on success.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @retval false if the progress object has already been canceled or is in an
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * invalid state
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pfnCallback The function to be called upon cancelation.
61283d6341bac43f73cf33c9ec754a59f674fa19vboxsync * @param pvUser The callback argument.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncbool Progress::i_setCancelCallback(void (*pfnCallback)(void *), void *pvUser)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return false;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return true;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync // get creation timestamp
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync// public initializer/uninitializer for internal purposes only
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync////////////////////////////////////////////////////////////////////////////////
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Initializes the normal progress object. With this variant, one can have
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * an arbitrary number of sub-operation which IProgress can analyze to
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * have a weighted progress computed.
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync * For example, say that one IProgress is supposed to track the cloning
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * of two hard disk images, which are 100 MB and 1000 MB in size, respectively,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * and each of these hard disks should be one sub-operation of the IProgress.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Obviously the progress would be misleading if the progress displayed 50%
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * after the smaller image was cloned and would then take much longer for
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * the second half.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * With weighted progress, one can invoke the following calls:
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * 1) create progress object with cOperations = 2 and ulTotalOperationsWeight =
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * 1100 (100 MB plus 1100, but really the weights can be any ULONG); pass
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * in ulFirstOperationWeight = 100 for the first sub-operation
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * 2) Then keep calling setCurrentOperationProgress() with a percentage
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * for the first image; the total progress will increase up to a value
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * of 9% (100MB / 1100MB * 100%).
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * 3) Then call setNextOperation with the second weight (1000 for the megabytes
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * of the second disk).
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * 4) Then keep calling setCurrentOperationProgress() with a percentage for
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync * the second image, where 100% of the operation will then yield a 100%
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * progress of the entire task.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Weighting is optional; you can simply assign a weight of 1 to each operation
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * and pass ulTotalOperationsWeight == cOperations to this constructor (but
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * for that variant and for backwards-compatibility a simpler constructor exists
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * in ProgressImpl.h as well).
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Even simpler, if you need no sub-operations at all, pass in cOperations =
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * ulTotalOperationsWeight = ulFirstOperationWeight = 1.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param aParent See Progress::init().
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param aInitiator See Progress::init().
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param aDescription See Progress::init().
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param aCancelable Flag whether the task maybe canceled.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cOperations Number of operations within this task (at least 1).
61283d6341bac43f73cf33c9ec754a59f674fa19vboxsync * @param ulTotalOperationsWeight Total weight of operations; must be the sum of ulFirstOperationWeight and
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * what is later passed with each subsequent setNextOperation() call.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param bstrFirstOperationDescription Description of the first operation.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param ulFirstOperationWeight Weight of first sub-operation.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param aId See Progress::init().
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync LogFlowThisFunc(("aDescription=\"%ls\", cOperations=%d, ulTotalOperationsWeight=%d, bstrFirstOperationDescription=\"%ls\", ulFirstOperationWeight=%d\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertReturn(ulTotalOperationsWeight >= 1, E_INVALIDARG);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Enclose the state transition NotReady->InInit->Ready */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync// rc = Progress::init(
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync//#if !defined(VBOX_COM_INPROC)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync// aInitiator, aDescription, FALSE, aId);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* share parent weakly */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* assign (and therefore addref) initiator only if it is not VirtualBox
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * * (to avoid cycling); otherwise mInitiator will remain null which means
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * * that it is the same as the parent */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* add to the global collection of progress operations (note: after
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * * creating mId) */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync// end of assertion
571525c203930230b3ae9badba7c2d2d12f21d05vboxsync m_ulTotalOperationsWeight = ulTotalOperationsWeight;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync m_operationDescription = aFirstOperationDescription;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync m_ulCurrentOperationWeight = ulFirstOperationWeight;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Confirm a successful initialization when it's the case */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Initializes the sub-progress object that represents a specific operation of
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * the whole task.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Objects initialized with this method are then combined together into the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * single task using a Progress instance, so it doesn't require the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * parent, initiator, description and doesn't create an ID. Note that calling
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * respective getter methods on an object initialized with this method is
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * useless. Such objects are used only to provide a separate wait semaphore and
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * store individual operation descriptions.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param aCancelable Flag whether the task maybe canceled.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param aOperationCount Number of sub-operations within this task (at least 1).
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param aOperationDescription Description of the individual operation.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlowThisFunc(("aOperationDescription=\"%s\"\n", aOperationDescription.c_str()));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Enclose the state transition NotReady->InInit->Ready */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Guarantees subclasses call this method at the proper time */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync // for this variant we assume for now that all operations are weighed "1"
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync // and equal total weight = operation count
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync /* Confirm a successful initialization when it's the case */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Uninitializes the instance and sets the ready flag to FALSE.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Called either from FinalRelease() or by the parent when it gets destroyed.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Enclose the state transition Ready->InUninit->NotReady */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* wake up all threads still waiting on occasion */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("WARNING: There are still %d threads waiting for '%s' completion!\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* release initiator (effective only if mInitiator has been assigned in
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * * init()) */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* remove the added progress on failure to complete the initialization */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (autoUninitSpan.initFailed() && mId.isValid() && !mId.isZero())
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync// IProgress properties
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/////////////////////////////////////////////////////////////////////////////
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync// IProgress methods
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/////////////////////////////////////////////////////////////////////////////
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @note XPCOM: when this method is not called on the main XPCOM thread, it
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * simply blocks the thread until mCompletedSem is signalled. If the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * thread has its own event queue (hmm, what for?) that it must run, then
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * calling this method will definitely freeze event processing.
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync /* if we're already completed, take a shortcut */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync fForever ? RT_INDEFINITE_WAIT : (RTMSINTERVAL)timeLeft);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* the last waiter resets the semaphore */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync tr("Failed to wait for the task completion (%Rrc)"),
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @note XPCOM: when this method is not called on the main XPCOM thread, it
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * simply blocks the thread until mCompletedSem is signalled. If the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * thread has its own event queue (hmm, what for?) that it must run, then
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * calling this method will definitely freeze event processing.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncHRESULT Progress::waitForOperationCompletion(ULONG aOperation, LONG aTimeout)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlowThisFunc(("aOperation=%d, aTimeout=%d\n", aOperation, aTimeout));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync CheckComArgExpr(aOperation, aOperation < m_cOperations);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* if we're already completed or if the given operation is already done,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * then take a shortcut */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync while ( !mCompleted && aOperation >= m_ulCurrentOperation
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync fForever ? RT_INDEFINITE_WAIT : (unsigned) timeLeft);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* the last waiter resets the semaphore */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync tr("Failed to wait for the operation completion (%Rrc)"),
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncHRESULT Progress::waitForAsyncProgressCompletion(const ComPtr<IProgress> &aPProgressAsync)
a44cdd0b29504e3de7b8aa87f839ad62b6e66f51vboxsync /* Note: we don't lock here, cause we just using public methods. */
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync /* Is the async process cancelable? */
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync rc = aPProgressAsync->COMGETTER(Cancelable)(&fCancelable);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Loop as long as the sync process isn't completed. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync while (SUCCEEDED(aPProgressAsync->COMGETTER(Completed(&fCompleted))))
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync /* We can forward any cancel request to the async process only when
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * it is cancelable. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Even if the user canceled the process, we have to wait until the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync async task has finished his work (cleanup and such). Otherwise there
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync will be sync trouble (still wrong state, dead locks, ...) on the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync used objects. So just do nothing, but wait for the complete
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync notification. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Check if the current operation has changed. It is also possible that
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync * in the meantime more than one async operation was finished. So we
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * have to loop as long as we reached the same operation count. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = aPProgressAsync->COMGETTER(Operation(&curOp));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = aPProgressAsync->COMGETTER(OperationDescription(bstr.asOutParam()));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = aPProgressAsync->COMGETTER(OperationWeight(¤tWeight));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = aPProgressAsync->COMGETTER(OperationPercent(¤tPercent));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* Make sure the loop is not too tight */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Updates the percentage value of the current operation.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param aPercent New percentage value of the operation in progress
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * (in range [0, 100]).
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncHRESULT Progress::setCurrentOperationProgress(ULONG aPercent)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsgReturn(aPercent <= 100, ("%u\n", aPercent), E_INVALIDARG);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Signals that the current operation is successfully completed and advances to
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * the next operation. The operation percentage is reset to 0.
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync * @param aOperationDescription Description of the next operation.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @note The current operation must not be the last one.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncHRESULT Progress::setNextOperation(const com::Utf8Str &aNextOperationDescription, ULONG aNextOperationsWeight)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertReturn(m_ulCurrentOperation + 1 < m_cOperations, E_FAIL);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync m_ulOperationsCompletedWeight += m_ulCurrentOperationWeight;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync m_operationDescription = aNextOperationDescription;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync m_ulCurrentOperationWeight = aNextOperationsWeight;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("Progress::setNextOperation(%s): aNextOperationsWeight = %d; m_ulCurrentOperation is now %d, m_ulOperationsCompletedWeight is now %d\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync m_operationDescription.c_str(), aNextOperationsWeight, m_ulCurrentOperation, m_ulOperationsCompletedWeight));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* wake up all waiting threads */
61283d6341bac43f73cf33c9ec754a59f674fa19vboxsync// public methods only for internal purposes
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/////////////////////////////////////////////////////////////////////////////
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Sets the internal result code and attempts to retrieve additional error
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * info from the current thread. Gets called from Progress::notifyComplete(),
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * but can be called again to override a previous result set with
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * notifyComplete().
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param aResultCode
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsyncHRESULT Progress::i_setResultCode(HRESULT aResultCode)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* try to import error info from the current thread */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = err.queryInterfaceTo(mErrorInfo.asOutParam());
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#else /* !defined(VBOX_WITH_XPCOM) */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &rc);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = es->GetCurrentExceptionManager(getter_AddRefs(em));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif /* !defined(VBOX_WITH_XPCOM) */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsg(rc == S_OK, ("Couldn't get error info (rc=%08X) while trying to set a failed result (%08X)!\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Marks the whole task as complete and sets the result code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * If the result code indicates a failure (|FAILED(@a aResultCode)|) then this
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * method will import the error info from the current thread and assign it to
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync * the errorInfo attribute (it will return an error if no info is available in
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * such case).
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * If the result code indicates a success (|SUCCEEDED(@a aResultCode)|) then
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * the current operation is set to the last.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Note that this method may be called only once for the given Progress object.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Subsequent calls will assert.
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync * @param aResultCode Operation result code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncHRESULT Progress::i_notifyComplete(HRESULT aResultCode)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync m_ulCurrentOperation = m_cOperations - 1; /* last operation */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* remove from the global collection of pending progress operations */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* wake up all waiting threads */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Wrapper around Progress:notifyCompleteV.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncHRESULT Progress::i_notifyComplete(HRESULT aResultCode,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync const char *aText,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync HRESULT hrc = i_notifyCompleteV(aResultCode, aIID, pcszComponent, aText, va);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Marks the operation as complete and attaches full error info.
61283d6341bac43f73cf33c9ec754a59f674fa19vboxsync * See VirtualBoxBase::setError(HRESULT, const GUID &, const wchar_t
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * *, const char *, ...) for more info.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param aResultCode Operation result (error) code, must not be S_OK.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param aIID IID of the interface that defines the error.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param aComponent Name of the component that generates the error.
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync * @param aText Error message (must not be null), an RTStrPrintf-like
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * format string in UTF-8 encoding.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param va List of arguments for the format string.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncHRESULT Progress::i_notifyCompleteV(HRESULT aResultCode,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync const char *aText,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync errorInfo->init(aResultCode, aIID, pcszComponent, text);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync errorInfo.queryInterfaceTo(mErrorInfo.asOutParam());
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* remove from the global collection of pending progress operations */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* wake up all waiting threads */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Notify the progress object that we're almost at the point of no return.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * This atomically checks for and disables cancelation. Calls to
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * IProgress::Cancel() made after a successful call to this method will fail
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * and the user can be told. While this isn't entirely clean behavior, it
61283d6341bac43f73cf33c9ec754a59f674fa19vboxsync * prevents issues with an irreversible actually operation succeeding while the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * user believe it was rolled back.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns Success indicator.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @retval true on success.
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync * @retval false if the progress object has already been canceled or is in an
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * invalid state
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return false;
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync return true;