VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/ProgressProxyImpl.cpp

Last change on this file was 106061, checked in by vboxsync, 7 weeks ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.4 KB
Line 
1/* $Id: ProgressProxyImpl.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * IProgress implementation for Machine::openRemoteSession in VBoxSVC.
4 */
5
6/*
7 * Copyright (C) 2010-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#define LOG_GROUP LOG_GROUP_MAIN_PROGRESS
29#include <iprt/types.h>
30
31#include "ProgressProxyImpl.h"
32
33#include "VirtualBoxImpl.h"
34#include "VirtualBoxErrorInfoImpl.h"
35
36#include "LoggingNew.h"
37
38#include <iprt/time.h>
39#include <iprt/semaphore.h>
40#include <iprt/errcore.h>
41
42////////////////////////////////////////////////////////////////////////////////
43// ProgressProxy class
44////////////////////////////////////////////////////////////////////////////////
45
46// constructor / destructor / uninitializer
47////////////////////////////////////////////////////////////////////////////////
48
49
50HRESULT ProgressProxy::FinalConstruct()
51{
52 mfMultiOperation = false;
53 muOtherProgressStartWeight = 0;
54 muOtherProgressWeight = 0;
55 muOtherProgressStartOperation = 0;
56
57 return Progress::FinalConstruct();
58}
59
60/**
61 * Initialize it as a one operation Progress object.
62 *
63 * This is used by SessionMachine::OnSessionEnd.
64 */
65HRESULT ProgressProxy::init(
66#if !defined (VBOX_COM_INPROC)
67 VirtualBox *pParent,
68#endif
69 IUnknown *pInitiator,
70 Utf8Str strDescription,
71 BOOL fCancelable)
72{
73 mfMultiOperation = false;
74 muOtherProgressStartWeight = 1;
75 muOtherProgressWeight = 1;
76 muOtherProgressStartOperation = 1;
77
78 return Progress::init(
79#if !defined (VBOX_COM_INPROC)
80 pParent,
81#endif
82 pInitiator,
83 strDescription,
84 fCancelable,
85 1 /* cOperations */,
86 1 /* ulTotalOperationsWeight */,
87 strDescription /* strFirstOperationDescription */,
88 1 /* ulFirstOperationWeight */);
89}
90
91/**
92 * Initialize for proxying one other progress object.
93 *
94 * This is tailored explicitly for the openRemoteSession code, so we start out
95 * with one operation where we don't have any remote object (powerUp). Then a
96 * remote object is added and stays with us till the end.
97 *
98 * The user must do normal completion notification or risk leave the threads
99 * waiting forever!
100 */
101HRESULT ProgressProxy::init(
102#if !defined (VBOX_COM_INPROC)
103 VirtualBox *pParent,
104#endif
105 IUnknown *pInitiator,
106 Utf8Str strDescription,
107 BOOL fCancelable,
108 ULONG uTotalOperationsWeight,
109 Utf8Str strFirstOperationDescription,
110 ULONG uFirstOperationWeight,
111 ULONG cOtherProgressObjectOperations)
112{
113 mfMultiOperation = false;
114 muOtherProgressStartWeight = uFirstOperationWeight;
115 muOtherProgressWeight = uTotalOperationsWeight - uFirstOperationWeight;
116 muOtherProgressStartOperation = 1;
117
118 return Progress::init(
119#if !defined (VBOX_COM_INPROC)
120 pParent,
121#endif
122 pInitiator,
123 strDescription,
124 fCancelable,
125 1 + cOtherProgressObjectOperations /* cOperations */,
126 uTotalOperationsWeight,
127 strFirstOperationDescription,
128 uFirstOperationWeight);
129}
130
131void ProgressProxy::FinalRelease()
132{
133 uninit();
134 mfMultiOperation = false;
135 muOtherProgressStartWeight = 0;
136 muOtherProgressWeight = 0;
137 muOtherProgressStartOperation = 0;
138
139 BaseFinalRelease();
140}
141
142void ProgressProxy::uninit()
143{
144 LogFlowThisFunc(("\n"));
145
146 mptrOtherProgress.setNull();
147 Progress::uninit();
148}
149
150// Public methods
151////////////////////////////////////////////////////////////////////////////////
152
153/** Just a wrapper so we can automatically do the handover before setting
154 * the result locally. */
155HRESULT ProgressProxy::notifyComplete(HRESULT aResultCode)
156{
157 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
158 clearOtherProgressObjectInternal(true /* fEarly */);
159 HRESULT hrc = S_OK;
160 if (!mCompleted)
161 hrc = Progress::i_notifyComplete(aResultCode);
162 return hrc;
163}
164
165/** Just a wrapper so we can automatically do the handover before setting
166 * the result locally. */
167HRESULT ProgressProxy::notifyComplete(HRESULT aResultCode,
168 const GUID &aIID,
169 const char *pcszComponent,
170 const char *aText,
171 ...)
172{
173 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
174 clearOtherProgressObjectInternal(true /* fEarly */);
175
176 HRESULT hrc = S_OK;
177 if (!mCompleted)
178 {
179 va_list va;
180 va_start(va, aText);
181 hrc = Progress::i_notifyCompleteV(aResultCode, aIID, pcszComponent, aText, va);
182 va_end(va);
183 }
184 return hrc;
185}
186
187/**
188 * Sets the other progress object unless the operation has been completed /
189 * canceled already.
190 *
191 * @returns false if failed/canceled, true if not.
192 * @param pOtherProgress The other progress object. Must not be NULL.
193 */
194bool ProgressProxy::setOtherProgressObject(IProgress *pOtherProgress)
195{
196 LogFlowThisFunc(("setOtherProgressObject: %p\n", pOtherProgress));
197 ComPtr<IProgress> ptrOtherProgress = pOtherProgress;
198
199 /*
200 * Query information from the other progress object before we grab the
201 * lock.
202 */
203 ULONG cOperations;
204 HRESULT hrc = pOtherProgress->COMGETTER(OperationCount)(&cOperations);
205 if (FAILED(hrc))
206 cOperations = 1;
207
208 Bstr bstrOperationDescription;
209 hrc = pOtherProgress->COMGETTER(Description)(bstrOperationDescription.asOutParam());
210 if (FAILED(hrc))
211 bstrOperationDescription = "oops";
212
213
214 /*
215 * Take the lock and check for cancelation, cancel the other object if
216 * we've been canceled already.
217 */
218 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
219
220 BOOL fCompletedOrCanceled = mCompleted || mCanceled;
221 if (!fCompletedOrCanceled)
222 {
223 /*
224 * Advance to the next object and operation. If the other object has
225 * more operations than anticipated, adjust our internal count.
226 */
227 mptrOtherProgress = ptrOtherProgress;
228 mfMultiOperation = cOperations > 1;
229
230 muOtherProgressStartWeight = m_ulOperationsCompletedWeight + m_ulCurrentOperationWeight;
231 muOtherProgressWeight = m_ulTotalOperationsWeight - muOtherProgressStartWeight;
232 Progress::SetNextOperation(bstrOperationDescription.raw(), muOtherProgressWeight);
233
234 muOtherProgressStartOperation = m_ulCurrentOperation;
235 m_cOperations = cOperations + m_ulCurrentOperation;
236
237 /*
238 * Check for cancelation and completion.
239 */
240 BOOL f;
241 hrc = ptrOtherProgress->COMGETTER(Completed)(&f);
242 fCompletedOrCanceled = FAILED(hrc) || f;
243
244 if (!fCompletedOrCanceled)
245 {
246 hrc = ptrOtherProgress->COMGETTER(Canceled)(&f);
247 fCompletedOrCanceled = SUCCEEDED(hrc) && f;
248 }
249
250 if (fCompletedOrCanceled)
251 {
252 LogFlowThisFunc(("Other object completed or canceled, clearing...\n"));
253 clearOtherProgressObjectInternal(false /*fEarly*/);
254 }
255 else
256 {
257 /*
258 * Finally, mirror the cancelable property.
259 * Note! Note necessary if we do passthru!
260 */
261 if (mCancelable)
262 {
263 hrc = ptrOtherProgress->COMGETTER(Cancelable)(&f);
264 if (SUCCEEDED(hrc) && !f)
265 {
266 LogFlowThisFunc(("The other progress object is not cancelable\n"));
267 mCancelable = FALSE;
268 }
269 }
270 }
271 }
272 else
273 {
274 LogFlowThisFunc(("mCompleted=%RTbool mCanceled=%RTbool - Canceling the other progress object!\n",
275 mCompleted, mCanceled));
276 hrc = ptrOtherProgress->Cancel();
277 LogFlowThisFunc(("Cancel -> %Rhrc", hrc));
278 }
279
280 LogFlowThisFunc(("Returns %RTbool\n", !fCompletedOrCanceled));
281 return !fCompletedOrCanceled;
282}
283
284// Internal methods.
285////////////////////////////////////////////////////////////////////////////////
286
287
288/**
289 * Clear the other progress object reference, first copying over its state.
290 *
291 * This is used internally when completion is signalled one way or another.
292 *
293 * @param fEarly Early clearing or not.
294 */
295void ProgressProxy::clearOtherProgressObjectInternal(bool fEarly)
296{
297 if (!mptrOtherProgress.isNull())
298 {
299 ComPtr<IProgress> ptrOtherProgress = mptrOtherProgress;
300 mptrOtherProgress.setNull();
301 copyProgressInfo(ptrOtherProgress, fEarly);
302 }
303}
304
305/**
306 * Called to copy over the progress information from @a pOtherProgress.
307 *
308 * @param pOtherProgress The source of the information.
309 * @param fEarly Early copy.
310 *
311 * @note The caller owns the write lock and as cleared mptrOtherProgress
312 * already (or we might recurse forever)!
313 */
314void ProgressProxy::copyProgressInfo(IProgress *pOtherProgress, bool fEarly)
315{
316 HRESULT hrc;
317 LogFlowThisFunc(("\n"));
318
319 NOREF(fEarly);
320
321 /*
322 * No point in doing this if the progress object was canceled already.
323 */
324 if (!mCanceled)
325 {
326 /* Detect if the other progress object was canceled. */
327 BOOL fCanceled;
328 hrc = pOtherProgress->COMGETTER(Canceled)(&fCanceled);
329 if (FAILED(hrc))
330 fCanceled = FALSE;
331 if (fCanceled)
332 {
333 LogFlowThisFunc(("Canceled\n"));
334 mCanceled = TRUE;
335 if (m_pfnCancelCallback)
336 m_pfnCancelCallback(m_pvCancelUserArg);
337 }
338 else
339 {
340 /* Has it completed? */
341 BOOL fCompleted;
342 hrc = pOtherProgress->COMGETTER(Completed)(&fCompleted);
343 if (FAILED(hrc))
344 fCompleted = TRUE;
345 Assert(fCompleted || fEarly);
346 if (fCompleted)
347 {
348 /* Check the result. */
349 LONG lResult;
350 hrc = pOtherProgress->COMGETTER(ResultCode)(&lResult);
351 if (FAILED(hrc))
352 lResult = (LONG)hrc;
353 if (SUCCEEDED((HRESULT)lResult))
354 LogFlowThisFunc(("Succeeded\n"));
355 else
356 {
357 /* Get the error information. */
358 ComPtr<IVirtualBoxErrorInfo> ptrErrorInfo;
359 hrc = pOtherProgress->COMGETTER(ErrorInfo)(ptrErrorInfo.asOutParam());
360 if (SUCCEEDED(hrc) && !ptrErrorInfo.isNull())
361 {
362 Bstr bstrIID;
363 hrc = ptrErrorInfo->COMGETTER(InterfaceID)(bstrIID.asOutParam()); AssertComRC(hrc);
364 if (FAILED(hrc))
365 bstrIID.setNull();
366
367 Bstr bstrComponent;
368 hrc = ptrErrorInfo->COMGETTER(Component)(bstrComponent.asOutParam()); AssertComRC(hrc);
369 if (FAILED(hrc))
370 bstrComponent = "failed";
371
372 Bstr bstrText;
373 hrc = ptrErrorInfo->COMGETTER(Text)(bstrText.asOutParam()); AssertComRC(hrc);
374 if (FAILED(hrc))
375 bstrText = "<failed>";
376
377 Utf8Str strText(bstrText);
378 LogFlowThisFunc(("Got ErrorInfo(%s); hrcResult=%Rhrc\n", strText.c_str(), (HRESULT)lResult));
379 Progress::i_notifyComplete((HRESULT)lResult,
380 Guid(bstrIID).ref(),
381 Utf8Str(bstrComponent).c_str(),
382 "%s", strText.c_str());
383 }
384 else
385 {
386 LogFlowThisFunc(("ErrorInfo failed with hrc=%Rhrc; hrcResult=%Rhrc\n", hrc, (HRESULT)lResult));
387 Progress::i_notifyComplete((HRESULT)lResult,
388 COM_IIDOF(IProgress),
389 "ProgressProxy",
390 tr("No error info"));
391 }
392 }
393 }
394 else
395 LogFlowThisFunc(("Not completed\n"));
396 }
397 }
398 else
399 LogFlowThisFunc(("Already canceled\n"));
400
401 /*
402 * Did cancelable state change (point of no return)?
403 */
404 if (mCancelable && !mCompleted && !mCanceled)
405 {
406 BOOL fCancelable;
407 hrc = pOtherProgress->COMGETTER(Cancelable)(&fCancelable); AssertComRC(hrc);
408 if (SUCCEEDED(hrc) && !fCancelable)
409 {
410 LogFlowThisFunc(("point-of-no-return reached\n"));
411 mCancelable = FALSE;
412 }
413 }
414}
415
416
417// IProgress properties
418////////////////////////////////////////////////////////////////////////////////
419
420STDMETHODIMP ProgressProxy::COMGETTER(Cancelable)(BOOL *aCancelable)
421{
422 CheckComArgOutPointerValid(aCancelable);
423
424 AutoCaller autoCaller(this);
425 HRESULT hrc = autoCaller.hrc();
426 if (SUCCEEDED(hrc))
427 {
428 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
429
430 /* ASSUME: The cancelable property can only change to FALSE. */
431 if (!mCancelable || mptrOtherProgress.isNull())
432 *aCancelable = mCancelable;
433 else
434 {
435 hrc = mptrOtherProgress->COMGETTER(Cancelable)(aCancelable);
436 if (SUCCEEDED(hrc) && !*aCancelable)
437 {
438 LogFlowThisFunc(("point-of-no-return reached\n"));
439 mCancelable = FALSE;
440 }
441 }
442 }
443 return hrc;
444}
445
446STDMETHODIMP ProgressProxy::COMGETTER(Percent)(ULONG *aPercent)
447{
448 CheckComArgOutPointerValid(aPercent);
449
450 AutoCaller autoCaller(this);
451 HRESULT hrc = autoCaller.hrc();
452 if (SUCCEEDED(hrc))
453 {
454 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
455
456 if (mptrOtherProgress.isNull())
457 hrc = Progress::COMGETTER(Percent)(aPercent);
458 else
459 {
460 /*
461 * Get the overall percent of the other object and adjust it with
462 * the weighting given to the period before proxying started.
463 */
464 ULONG uPct;
465 hrc = mptrOtherProgress->COMGETTER(Percent)(&uPct);
466 if (SUCCEEDED(hrc))
467 {
468 double rdPercent = ((double)uPct / 100 * muOtherProgressWeight + muOtherProgressStartWeight)
469 / m_ulTotalOperationsWeight * 100;
470 *aPercent = RT_MIN((ULONG)rdPercent, 99); /* mptrOtherProgress is cleared when its completed,
471 so we can never return 100%. */
472 }
473 }
474 }
475 return hrc;
476}
477
478STDMETHODIMP ProgressProxy::COMGETTER(TimeRemaining)(LONG *aTimeRemaining)
479{
480 CheckComArgOutPointerValid(aTimeRemaining);
481
482 AutoCaller autoCaller(this);
483 HRESULT hrc = autoCaller.hrc();
484 if (SUCCEEDED(hrc))
485 {
486 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
487
488 if (mptrOtherProgress.isNull())
489 hrc = Progress::COMGETTER(TimeRemaining)(aTimeRemaining);
490 else
491 hrc = mptrOtherProgress->COMGETTER(TimeRemaining)(aTimeRemaining);
492 }
493 return hrc;
494}
495
496STDMETHODIMP ProgressProxy::COMGETTER(Completed)(BOOL *aCompleted)
497{
498 /* Not proxied since we EXPECT a normal completion notification call. */
499 return Progress::COMGETTER(Completed)(aCompleted);
500}
501
502STDMETHODIMP ProgressProxy::COMGETTER(Canceled)(BOOL *aCanceled)
503{
504 CheckComArgOutPointerValid(aCanceled);
505
506 AutoCaller autoCaller(this);
507 HRESULT hrc = autoCaller.hrc();
508 if (SUCCEEDED(hrc))
509 {
510 /* Check the local data first, then the other object. */
511 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
512 hrc = Progress::COMGETTER(Canceled)(aCanceled);
513 if ( SUCCEEDED(hrc)
514 && !*aCanceled
515 && !mptrOtherProgress.isNull()
516 && mCancelable)
517 {
518 hrc = mptrOtherProgress->COMGETTER(Canceled)(aCanceled);
519 if (SUCCEEDED(hrc) && *aCanceled)
520 /* This will not complete the object, only mark it as canceled. */
521 clearOtherProgressObjectInternal(false /*fEarly*/);
522 }
523 }
524 return hrc;
525}
526
527STDMETHODIMP ProgressProxy::COMGETTER(ResultCode)(LONG *aResultCode)
528{
529 /* Not proxied since we EXPECT a normal completion notification call. */
530 return Progress::COMGETTER(ResultCode)(aResultCode);
531}
532
533STDMETHODIMP ProgressProxy::COMGETTER(ErrorInfo)(IVirtualBoxErrorInfo **aErrorInfo)
534{
535 /* Not proxied since we EXPECT a normal completion notification call. */
536 return Progress::COMGETTER(ErrorInfo)(aErrorInfo);
537}
538
539STDMETHODIMP ProgressProxy::COMGETTER(Operation)(ULONG *aOperation)
540{
541 CheckComArgOutPointerValid(aOperation);
542
543 AutoCaller autoCaller(this);
544 HRESULT hrc = autoCaller.hrc();
545 if (SUCCEEDED(hrc))
546 {
547 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
548 if (mptrOtherProgress.isNull())
549 hrc = Progress::COMGETTER(Operation)(aOperation);
550 else
551 {
552 ULONG uCurOtherOperation;
553 hrc = mptrOtherProgress->COMGETTER(Operation)(&uCurOtherOperation);
554 if (SUCCEEDED(hrc))
555 *aOperation = uCurOtherOperation + muOtherProgressStartOperation;
556 }
557 }
558 return hrc;
559}
560
561STDMETHODIMP ProgressProxy::COMGETTER(OperationDescription)(BSTR *aOperationDescription)
562{
563 CheckComArgOutPointerValid(aOperationDescription);
564
565 AutoCaller autoCaller(this);
566 HRESULT hrc = autoCaller.hrc();
567 if (SUCCEEDED(hrc))
568 {
569 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
570 if (mptrOtherProgress.isNull() || !mfMultiOperation)
571 hrc = Progress::COMGETTER(OperationDescription)(aOperationDescription);
572 else
573 hrc = mptrOtherProgress->COMGETTER(OperationDescription)(aOperationDescription);
574 }
575 return hrc;
576}
577
578STDMETHODIMP ProgressProxy::COMGETTER(OperationPercent)(ULONG *aOperationPercent)
579{
580 CheckComArgOutPointerValid(aOperationPercent);
581
582 AutoCaller autoCaller(this);
583 HRESULT hrc = autoCaller.hrc();
584 if (SUCCEEDED(hrc))
585 {
586 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
587 if (mptrOtherProgress.isNull() || !mfMultiOperation)
588 hrc = Progress::COMGETTER(OperationPercent)(aOperationPercent);
589 else
590 hrc = mptrOtherProgress->COMGETTER(OperationPercent)(aOperationPercent);
591 }
592 return hrc;
593}
594
595STDMETHODIMP ProgressProxy::COMSETTER(Timeout)(ULONG aTimeout)
596{
597 /* Not currently supported. */
598 NOREF(aTimeout);
599 AssertFailed();
600 return E_NOTIMPL;
601}
602
603STDMETHODIMP ProgressProxy::COMGETTER(Timeout)(ULONG *aTimeout)
604{
605 /* Not currently supported. */
606 CheckComArgOutPointerValid(aTimeout);
607
608 AssertFailed();
609 return E_NOTIMPL;
610}
611
612// IProgress methods
613/////////////////////////////////////////////////////////////////////////////
614
615STDMETHODIMP ProgressProxy::WaitForCompletion(LONG aTimeout)
616{
617 HRESULT hrc;
618 LogFlowThisFuncEnter();
619 LogFlowThisFunc(("aTimeout=%d\n", aTimeout));
620
621 /* No need to wait on the proxied object for these since we'll get the
622 normal completion notifications. */
623 hrc = Progress::WaitForCompletion(aTimeout);
624
625 LogFlowThisFuncLeave();
626 return hrc;
627}
628
629STDMETHODIMP ProgressProxy::WaitForOperationCompletion(ULONG aOperation, LONG aTimeout)
630{
631 LogFlowThisFuncEnter();
632 LogFlowThisFunc(("aOperation=%d aTimeout=%d\n", aOperation, aTimeout));
633
634 AutoCaller autoCaller(this);
635 HRESULT hrc = autoCaller.hrc();
636 if (SUCCEEDED(hrc))
637 {
638 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
639
640 CheckComArgExpr(aOperation, aOperation < m_cOperations);
641
642 /*
643 * Check if we can wait locally.
644 */
645 if ( aOperation + 1 == m_cOperations /* final operation */
646 || mptrOtherProgress.isNull())
647 {
648 /* ASSUMES that Progress::WaitForOperationCompletion is using
649 AutoWriteLock::leave() as it saves us from duplicating the code! */
650 hrc = Progress::WaitForOperationCompletion(aOperation, aTimeout);
651 }
652 else
653 {
654 LogFlowThisFunc(("calling the other object...\n"));
655 ComPtr<IProgress> ptrOtherProgress = mptrOtherProgress;
656 alock.release();
657
658 hrc = ptrOtherProgress->WaitForOperationCompletion(aOperation, aTimeout);
659 }
660 }
661
662 LogFlowThisFuncLeave();
663 return hrc;
664}
665
666STDMETHODIMP ProgressProxy::Cancel()
667{
668 LogFlowThisFunc(("\n"));
669 AutoCaller autoCaller(this);
670 HRESULT hrc = autoCaller.hrc();
671 if (SUCCEEDED(hrc))
672 {
673 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
674 if (mptrOtherProgress.isNull() || !mCancelable)
675 hrc = Progress::Cancel();
676 else
677 {
678 hrc = mptrOtherProgress->Cancel();
679 if (SUCCEEDED(hrc))
680 clearOtherProgressObjectInternal(false /*fEarly*/);
681 }
682 }
683
684 LogFlowThisFunc(("returns %Rhrc\n", hrc));
685 return hrc;
686}
687
688STDMETHODIMP ProgressProxy::SetCurrentOperationProgress(ULONG aPercent)
689{
690 /* Not supported - why do we actually expose this? */
691 NOREF(aPercent);
692 return E_NOTIMPL;
693}
694
695STDMETHODIMP ProgressProxy::SetNextOperation(IN_BSTR bstrNextOperationDescription, ULONG ulNextOperationsWeight)
696{
697 /* Not supported - why do we actually expose this? */
698 NOREF(bstrNextOperationDescription);
699 NOREF(ulNextOperationsWeight);
700 return E_NOTIMPL;
701}
702
703#ifdef VBOX_WITH_XPCOM
704NS_DECL_CLASSINFO(ProgressProxy)
705NS_IMPL_THREADSAFE_ISUPPORTS1_CI(ProgressProxy, IProgress)
706#endif
707
708/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette