VirtualBox

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

Last change on this file since 56574 was 56574, checked in by vboxsync, 9 years ago

Main/ProgressProxy: eliminate unnecessary includes

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