VirtualBox

source: vbox/trunk/src/VBox/Main/ProgressProxyImpl.cpp@ 30430

Last change on this file since 30430 was 29948, checked in by vboxsync, 15 years ago

ProgressProxy: Handle a dead other progress object a bit more gracefully.

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