VirtualBox

source: vbox/trunk/src/VBox/Main/src-all/VirtualBoxBase.cpp@ 108014

Last change on this file since 108014 was 107588, checked in by vboxsync, 7 weeks ago

Main,Puel: Made the object tracker code a compile time option (VBOX_WITH_MAIN_OBJECT_TRACKER) and disabled it since it causes VBoxSVC to crash during uninit. It is also badly in need of a review + style-cleanup (did some). Making it optional eliminates the need for Puel to include the object tracker code which it won't need (neither does VBoxC/Client.dll). bugref:10806

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.7 KB
Line 
1/* $Id: VirtualBoxBase.cpp 107588 2025-01-09 11:04:40Z vboxsync $ */
2/** @file
3 * VirtualBox COM base classes implementation
4 */
5
6/*
7 * Copyright (C) 2006-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
29#include <iprt/semaphore.h>
30#include <iprt/asm.h>
31#include <iprt/cpp/exception.h>
32#include <iprt/cpp/utils.h>
33
34#include <typeinfo>
35
36#if !defined(VBOX_WITH_XPCOM)
37# include <iprt/win/windows.h>
38#else /* !defined(VBOX_WITH_XPCOM) */
39/// @todo remove when VirtualBoxErrorInfo goes away from here
40# include <nsIServiceManager.h>
41# include <nsIExceptionService.h>
42#endif /* !defined(VBOX_WITH_XPCOM) */
43
44#include "VirtualBoxBase.h"
45#include "AutoCaller.h"
46#include "VirtualBoxErrorInfoImpl.h"
47#include "VirtualBoxTranslator.h"
48#include "Global.h"
49#include "LoggingNew.h"
50#ifdef VBOX_WITH_MAIN_OBJECT_TRACKER
51# include "ObjectsTracker.h"
52#endif
53
54#include "VBox/com/ErrorInfo.h"
55#include "VBox/com/MultiResult.h"
56
57////////////////////////////////////////////////////////////////////////////////
58//
59// VirtualBoxBase
60//
61////////////////////////////////////////////////////////////////////////////////
62
63CLASSFACTORY_STAT g_aClassFactoryStats[CLASSFACTORYSTATS_MAX] =
64{
65 { "--- totals ---", 0 },
66 { NULL, 0 }
67};
68
69RWLockHandle *g_pClassFactoryStatsLock = NULL;
70
71
72VirtualBoxBase::VirtualBoxBase() :
73 mState(this),
74 iFactoryStat(~0U)
75{
76 mObjectLock = NULL;
77
78 if (!g_pClassFactoryStatsLock)
79 {
80 RWLockHandle *lock = new RWLockHandle(LOCKCLASS_OBJECTSTATE);
81 if (!ASMAtomicCmpXchgPtr(&g_pClassFactoryStatsLock, lock, NULL))
82 delete lock;
83 }
84 Assert(g_pClassFactoryStatsLock);
85
86 RTUUID uuid;
87 RTUuidCreate(&uuid);
88 unconst(mObjectId) = uuid;
89}
90
91VirtualBoxBase::~VirtualBoxBase()
92{
93 Assert(iFactoryStat == ~0U);
94 if (mObjectLock)
95 delete mObjectLock;
96}
97
98HRESULT VirtualBoxBase::BaseFinalConstruct()
99{
100 Assert(iFactoryStat == ~0U);
101 if (g_pClassFactoryStatsLock)
102 {
103 AutoWriteLock alock(g_pClassFactoryStatsLock COMMA_LOCKVAL_SRC_POS);
104 g_aClassFactoryStats[0].current++;
105 g_aClassFactoryStats[0].overall++;
106 const char *pszName = getComponentName();
107 uint32_t i = 1;
108 while (i < CLASSFACTORYSTATS_MAX && g_aClassFactoryStats[i].psz)
109 {
110 if (g_aClassFactoryStats[i].psz == pszName)
111 break;
112 i++;
113 }
114 if (i < CLASSFACTORYSTATS_MAX)
115 {
116 if (!g_aClassFactoryStats[i].psz)
117 {
118 g_aClassFactoryStats[i].psz = pszName;
119 g_aClassFactoryStats[i].current = 0;
120 g_aClassFactoryStats[i].overall = 0;
121 }
122 iFactoryStat = i;
123 g_aClassFactoryStats[i].current++;
124 g_aClassFactoryStats[i].overall++;
125 }
126 else
127 AssertMsg(i < CLASSFACTORYSTATS_MAX, ("%u exhausts size of factory housekeeping array\n", i));
128 }
129 else
130 Assert(g_pClassFactoryStatsLock);
131
132#ifdef RT_OS_WINDOWS
133 return CoCreateFreeThreadedMarshaler(this, //GetControllingUnknown(),
134 m_pUnkMarshaler.asOutParam());
135#else
136 return S_OK;
137#endif
138}
139
140void VirtualBoxBase::BaseFinalRelease()
141{
142 if (g_pClassFactoryStatsLock)
143 {
144 AutoWriteLock alock(g_pClassFactoryStatsLock COMMA_LOCKVAL_SRC_POS);
145 g_aClassFactoryStats[0].current--;
146 const char *pszName = getComponentName();
147 if (iFactoryStat < CLASSFACTORYSTATS_MAX)
148 {
149 if (g_aClassFactoryStats[iFactoryStat].psz == pszName)
150 {
151 g_aClassFactoryStats[iFactoryStat].current--;
152 iFactoryStat = ~0U;
153 }
154 else
155 AssertMsgFailed(("could not find factory housekeeping array entry for %s (index %u contains %s)\n", pszName, iFactoryStat, g_aClassFactoryStats[iFactoryStat].psz));
156 }
157 else
158 AssertMsgFailed(("factory housekeeping array corruption, index %u is too large\n", iFactoryStat));
159 }
160 else
161 Assert(g_pClassFactoryStatsLock);
162
163#ifdef RT_OS_WINDOWS
164 m_pUnkMarshaler.setNull();
165#endif
166}
167
168void APIDumpComponentFactoryStats()
169{
170 if (g_pClassFactoryStatsLock)
171 {
172 AutoReadLock alock(g_pClassFactoryStatsLock COMMA_LOCKVAL_SRC_POS);
173 for (uint32_t i = 0; i < CLASSFACTORYSTATS_MAX && g_aClassFactoryStats[i].psz; i++)
174 LogRel(("CFS: component %-30s current %-10u total %-10u\n",
175 g_aClassFactoryStats[i].psz, g_aClassFactoryStats[i].current,
176 g_aClassFactoryStats[i].overall));
177 }
178 else
179 Assert(g_pClassFactoryStatsLock);
180}
181
182#ifdef VBOX_WITH_MAIN_OBJECT_TRACKER
183TrackedObjectsCollector gTrackedObjectsCollector;
184#endif
185
186HRESULT VirtualBoxBase::getObjectId(com::Guid &aId)
187{
188 aId = mObjectId;
189 return S_OK;
190}
191
192HRESULT VirtualBoxBase::setTracked(uint64_t aLifeTime, uint64_t afterLifeTime)
193{
194#ifdef VBOX_WITH_MAIN_OBJECT_TRACKER
195 Utf8Str strObjId = mObjectId.toString();
196 Utf8Str strClassIID = Guid(getClassIID()).toString();
197 HRESULT hrc = gTrackedObjectsCollector.setObj(strObjId,
198 strClassIID,
199 aLifeTime,
200 afterLifeTime,
201 /*ptrVirtualBoxBase,*/
202 this);
203 Log2(("VirtualBoxBase::setTracked: inserted the Id %s for component %s with IID %s.\n",
204 strObjId.c_str(), getComponentName(), strClassIID.c_str()));
205
206 return hrc;
207#else
208 RT_NOREF(aLifeTime, afterLifeTime);
209 return S_OK;
210#endif
211}
212
213HRESULT VirtualBoxBase::invalidateTracked()
214{
215#ifdef VBOX_WITH_MAIN_OBJECT_TRACKER
216 Utf8Str strObjId = mObjectId.toString();
217 HRESULT hrc = gTrackedObjectsCollector.invalidateObj(strObjId);
218
219 return hrc;
220#else
221 return S_OK;
222#endif
223}
224
225/**
226 * This virtual method returns an RWLockHandle that can be used to
227 * protect instance data. This RWLockHandle is generally referred to
228 * as the "object lock"; its locking class (for lock order validation)
229 * must be returned by another virtual method, getLockingClass(), which
230 * by default returns LOCKCLASS_OTHEROBJECT but is overridden by several
231 * subclasses such as VirtualBox, Host, Machine and others.
232 *
233 * On the first call this method lazily creates the RWLockHandle.
234 *
235 * @return
236 */
237/* virtual */
238RWLockHandle *VirtualBoxBase::lockHandle() const
239{
240 /* lazy initialization */
241 if (RT_LIKELY(mObjectLock))
242 return mObjectLock;
243
244 AssertCompile(sizeof(RWLockHandle *) == sizeof(void *));
245
246 // getLockingClass() is overridden by many subclasses to return
247 // one of the locking classes listed at the top of AutoLock.h
248 // getComponentName() returns the class name by default.
249 RWLockHandle *objLock = new RWLockHandle(getLockingClass(), getComponentName());
250 if (!ASMAtomicCmpXchgPtr(&mObjectLock, objLock, NULL))
251 {
252 delete objLock;
253 objLock = ASMAtomicReadPtrT(&mObjectLock, RWLockHandle *);
254 }
255 return objLock;
256}
257
258/**
259 * Handles unexpected exceptions by turning them into COM errors in release
260 * builds or by hitting a breakpoint in the release builds.
261 *
262 * Usage pattern:
263 * @code
264 try
265 {
266 // ...
267 }
268 catch (LaLalA)
269 {
270 // ...
271 }
272 catch (...)
273 {
274 hrc = VirtualBox::handleUnexpectedExceptions(this, RT_SRC_POS);
275 }
276 * @endcode
277 *
278 * @param aThis object where the exception happened
279 * @param SRC_POS "RT_SRC_POS" macro instantiation.
280 * */
281/* static */
282HRESULT VirtualBoxBase::handleUnexpectedExceptions(VirtualBoxBase *const aThis, RT_SRC_POS_DECL)
283{
284 try
285 {
286 /* re-throw the current exception */
287 throw;
288 }
289 catch (const RTCError &err) // includes all XML exceptions
290 {
291 return setErrorInternalF(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
292 false /* aWarning */,
293 true /* aLogIt */,
294 0 /* aResultDetail */,
295 "%s.\n%s[%d] (%s)",
296 err.what(), pszFile, iLine, pszFunction);
297 }
298 catch (const std::exception &err)
299 {
300 return setErrorInternalF(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
301 false /* aWarning */,
302 true /* aLogIt */,
303 0 /* aResultDetail */,
304 tr("Unexpected exception: %s [%s]\n%s[%d] (%s)"),
305 err.what(), typeid(err).name(), pszFile, iLine, pszFunction);
306 }
307 catch (...)
308 {
309 return setErrorInternalF(E_FAIL, aThis->getClassIID(), aThis->getComponentName(),
310 false /* aWarning */,
311 true /* aLogIt */,
312 0 /* aResultDetail */,
313 tr("Unknown exception\n%s[%d] (%s)"),
314 pszFile, iLine, pszFunction);
315 }
316
317#ifndef _MSC_VER /* (unreachable) */
318 /* should not get here */
319 AssertFailed();
320 return E_FAIL;
321#endif
322}
323
324
325/**
326 * Sets error info for the current thread. This is an internal function that
327 * gets eventually called by all public variants. If @a aWarning is
328 * @c true, then the highest (31) bit in the @a aResultCode value which
329 * indicates the error severity is reset to zero to make sure the receiver will
330 * recognize that the created error info object represents a warning rather
331 * than an error.
332 */
333/* static */
334HRESULT VirtualBoxBase::setErrorInternalF(HRESULT aResultCode,
335 const GUID &aIID,
336 const char *aComponent,
337 bool aWarning,
338 bool aLogIt,
339 LONG aResultDetail,
340 const char *aText, ...)
341{
342 va_list va;
343 va_start(va, aText);
344 HRESULT hres = setErrorInternalV(aResultCode, aIID, aComponent, aText, va,
345 aWarning, aLogIt, aResultDetail);
346 va_end(va);
347 return hres;
348}
349
350/**
351 * Sets error info for the current thread. This is an internal function that
352 * gets eventually called by all public variants. If @a aWarning is
353 * @c true, then the highest (31) bit in the @a aResultCode value which
354 * indicates the error severity is reset to zero to make sure the receiver will
355 * recognize that the created error info object represents a warning rather
356 * than an error.
357 */
358/* static */
359HRESULT VirtualBoxBase::setErrorInternalV(HRESULT aResultCode,
360 const GUID &aIID,
361 const char *aComponent,
362 const char *aText,
363 va_list aArgs,
364 bool aWarning,
365 bool aLogIt,
366 LONG aResultDetail /* = 0*/)
367{
368 /* whether multi-error mode is turned on */
369 bool preserve = MultiResult::isMultiEnabled();
370
371 com::Utf8Str strText;
372 if (aLogIt)
373 {
374#ifdef VBOX_WITH_MAIN_NLS
375 strText = VirtualBoxTranslator::trSource(aText);
376#else
377 strText = aText;
378#endif
379 va_list va2;
380 va_copy(va2, aArgs);
381 LogRel(("%s [COM]: aRC=%Rhrc (%#08x) aIID={%RTuuid} aComponent={%s} aText={%N}, preserve=%RTbool aResultDetail=%d\n",
382 aWarning ? "WARNING" : "ERROR",
383 aResultCode,
384 aResultCode,
385 &aIID,
386 aComponent,
387 strText.c_str(),
388 &va2,
389 preserve,
390 aResultDetail));
391 va_end(va2);
392 }
393
394 /* these are mandatory, others -- not */
395 AssertReturn((!aWarning && FAILED(aResultCode)) ||
396 (aWarning && aResultCode != S_OK),
397 E_FAIL);
398
399 /* reset the error severity bit if it's a warning */
400 if (aWarning)
401 aResultCode &= ~0x80000000;
402
403 HRESULT hrc = S_OK;
404
405 if (aText == NULL || aText[0] == '\0')
406 {
407 /* Some default info */
408 switch (aResultCode)
409 {
410 case E_INVALIDARG: strText = tr("A parameter has an invalid value"); break;
411 case E_POINTER: strText = tr("A parameter is an invalid pointer"); break;
412 case E_UNEXPECTED: strText = tr("The result of the operation is unexpected"); break;
413 case E_ACCESSDENIED: strText = tr("The access to an object is not allowed"); break;
414 case E_OUTOFMEMORY: strText = tr("The allocation of new memory failed"); break;
415 case E_NOTIMPL: strText = tr("The requested operation is not implemented"); break;
416 case E_NOINTERFACE: strText = tr("The requested interface is not implemented"); break;
417 case E_FAIL: strText = tr("A general error occurred"); break;
418 case E_ABORT: strText = tr("The operation was canceled"); break;
419 case VBOX_E_OBJECT_NOT_FOUND: strText = tr("Object corresponding to the supplied arguments does not exist"); break;
420 case VBOX_E_INVALID_VM_STATE: strText = tr("Current virtual machine state prevents the operation"); break;
421 case VBOX_E_VM_ERROR: strText = tr("Virtual machine error occurred attempting the operation"); break;
422 case VBOX_E_FILE_ERROR: strText = tr("File not accessible or erroneous file contents"); break;
423 case VBOX_E_IPRT_ERROR: strText = tr("Runtime subsystem error"); break;
424 case VBOX_E_PDM_ERROR: strText = tr("Pluggable Device Manager error"); break;
425 case VBOX_E_INVALID_OBJECT_STATE: strText = tr("Current object state prohibits operation"); break;
426 case VBOX_E_HOST_ERROR: strText = tr("Host operating system related error"); break;
427 case VBOX_E_NOT_SUPPORTED: strText = tr("Requested operation is not supported"); break;
428 case VBOX_E_XML_ERROR: strText = tr("Invalid XML found"); break;
429 case VBOX_E_INVALID_SESSION_STATE: strText = tr("Current session state prohibits operation"); break;
430 case VBOX_E_OBJECT_IN_USE: strText = tr("Object being in use prohibits operation"); break;
431 case VBOX_E_PASSWORD_INCORRECT: strText = tr("Incorrect password provided"); break;
432 default: strText = tr("Unknown error"); break;
433 }
434 }
435 else
436 {
437 va_list va2;
438 va_copy(va2, aArgs);
439 strText = com::Utf8StrFmt("%N", aText, &va2);
440 va_end(va2);
441 }
442
443 do
444 {
445 ComObjPtr<VirtualBoxErrorInfo> info;
446 hrc = info.createObject();
447 if (FAILED(hrc)) break;
448
449#if !defined(VBOX_WITH_XPCOM)
450
451 ComPtr<IVirtualBoxErrorInfo> curInfo;
452 if (preserve)
453 {
454 /* get the current error info if any */
455 ComPtr<IErrorInfo> err;
456 hrc = ::GetErrorInfo(0, err.asOutParam());
457 if (FAILED(hrc)) break;
458 hrc = err.queryInterfaceTo(curInfo.asOutParam());
459 if (FAILED(hrc))
460 {
461 /* create a IVirtualBoxErrorInfo wrapper for the native
462 * IErrorInfo object */
463 ComObjPtr<VirtualBoxErrorInfo> wrapper;
464 hrc = wrapper.createObject();
465 if (SUCCEEDED(hrc))
466 {
467 hrc = wrapper->init(err);
468 if (SUCCEEDED(hrc))
469 curInfo = wrapper;
470 }
471 }
472 }
473 /* On failure, curInfo will stay null */
474 Assert(SUCCEEDED(hrc) || curInfo.isNull());
475
476 /* set the current error info and preserve the previous one if any */
477 hrc = info->initEx(aResultCode, aResultDetail, aIID, aComponent, strText, curInfo);
478 if (FAILED(hrc)) break;
479
480 ComPtr<IErrorInfo> err;
481 hrc = info.queryInterfaceTo(err.asOutParam());
482 if (SUCCEEDED(hrc))
483 hrc = ::SetErrorInfo(0, err);
484
485#else // !defined(VBOX_WITH_XPCOM)
486
487 nsCOMPtr <nsIExceptionService> es;
488 es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &hrc);
489 if (NS_SUCCEEDED(hrc))
490 {
491 nsCOMPtr <nsIExceptionManager> em;
492 hrc = es->GetCurrentExceptionManager(getter_AddRefs(em));
493 if (FAILED(hrc)) break;
494
495 ComPtr<IVirtualBoxErrorInfo> curInfo;
496 if (preserve)
497 {
498 /* get the current error info if any */
499 ComPtr<nsIException> ex;
500 hrc = em->GetCurrentException(ex.asOutParam());
501 if (FAILED(hrc)) break;
502 hrc = ex.queryInterfaceTo(curInfo.asOutParam());
503 if (FAILED(hrc))
504 {
505 /* create a IVirtualBoxErrorInfo wrapper for the native
506 * nsIException object */
507 ComObjPtr<VirtualBoxErrorInfo> wrapper;
508 hrc = wrapper.createObject();
509 if (SUCCEEDED(hrc))
510 {
511 hrc = wrapper->init(ex);
512 if (SUCCEEDED(hrc))
513 curInfo = wrapper;
514 }
515 }
516 }
517 /* On failure, curInfo will stay null */
518 Assert(SUCCEEDED(hrc) || curInfo.isNull());
519
520 /* set the current error info and preserve the previous one if any */
521 hrc = info->initEx(aResultCode, aResultDetail, aIID, aComponent, Bstr(strText), curInfo);
522 if (FAILED(hrc)) break;
523
524 ComPtr<nsIException> ex;
525 hrc = info.queryInterfaceTo(ex.asOutParam());
526 if (SUCCEEDED(hrc))
527 hrc = em->SetCurrentException(ex);
528 }
529 else if (hrc == NS_ERROR_UNEXPECTED)
530 {
531 /*
532 * It is possible that setError() is being called by the object
533 * after the XPCOM shutdown sequence has been initiated
534 * (for example, when XPCOM releases all instances it internally
535 * references, which can cause object's FinalConstruct() and then
536 * uninit()). In this case, do_GetService() above will return
537 * NS_ERROR_UNEXPECTED and it doesn't actually make sense to
538 * set the exception (nobody will be able to read it).
539 */
540 Log1WarningFunc(("Will not set an exception because nsIExceptionService is not available (NS_ERROR_UNEXPECTED). XPCOM is being shutdown?\n"));
541 hrc = NS_OK;
542 }
543
544#endif // !defined(VBOX_WITH_XPCOM)
545 }
546 while (0);
547
548 AssertComRC(hrc);
549
550 return SUCCEEDED(hrc) ? aResultCode : hrc;
551}
552
553/**
554 * Shortcut instance method to calling the static setErrorInternal with the
555 * class interface ID and component name inserted correctly. This uses the
556 * virtual getClassIID() and getComponentName() methods which are automatically
557 * defined by the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro.
558 * @param aResultCode
559 * @return
560 */
561HRESULT VirtualBoxBase::setError(HRESULT aResultCode)
562{
563 return setErrorInternalF(aResultCode,
564 this->getClassIID(),
565 this->getComponentName(),
566 false /* aWarning */,
567 true /* aLogIt */,
568 0 /* aResultDetail */,
569 NULL);
570}
571
572/**
573 * Shortcut instance method to calling the static setErrorInternal with the
574 * class interface ID and component name inserted correctly. This uses the
575 * virtual getClassIID() and getComponentName() methods which are automatically
576 * defined by the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro.
577 * @param aResultCode
578 * @param pcsz
579 * @return
580 */
581HRESULT VirtualBoxBase::setError(HRESULT aResultCode, const char *pcsz, ...)
582{
583 va_list args;
584 va_start(args, pcsz);
585 HRESULT hrc = setErrorInternalV(aResultCode,
586 this->getClassIID(),
587 this->getComponentName(),
588 pcsz, args,
589 false /* aWarning */,
590 true /* aLogIt */);
591 va_end(args);
592 return hrc;
593}
594
595/**
596 * Shortcut instance method to calling the static setErrorInternal with the
597 * class interface ID and component name inserted correctly. This uses the
598 * virtual getClassIID() and getComponentName() methods which are automatically
599 * defined by the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro.
600 * @param ei
601 * @return
602 */
603HRESULT VirtualBoxBase::setError(const com::ErrorInfo &ei)
604{
605 /* whether multi-error mode is turned on */
606 bool preserve = MultiResult::isMultiEnabled();
607
608 HRESULT hrc = S_OK;
609
610 do
611 {
612 ComObjPtr<VirtualBoxErrorInfo> info;
613 hrc = info.createObject();
614 if (FAILED(hrc)) break;
615
616#if !defined(VBOX_WITH_XPCOM)
617
618 ComPtr<IVirtualBoxErrorInfo> curInfo;
619 if (preserve)
620 {
621 /* get the current error info if any */
622 ComPtr<IErrorInfo> err;
623 hrc = ::GetErrorInfo(0, err.asOutParam());
624 if (FAILED(hrc)) break;
625 hrc = err.queryInterfaceTo(curInfo.asOutParam());
626 if (FAILED(hrc))
627 {
628 /* create a IVirtualBoxErrorInfo wrapper for the native
629 * IErrorInfo object */
630 ComObjPtr<VirtualBoxErrorInfo> wrapper;
631 hrc = wrapper.createObject();
632 if (SUCCEEDED(hrc))
633 {
634 hrc = wrapper->init(err);
635 if (SUCCEEDED(hrc))
636 curInfo = wrapper;
637 }
638 }
639 }
640 /* On failure, curInfo will stay null */
641 Assert(SUCCEEDED(hrc) || curInfo.isNull());
642
643 /* set the current error info and preserve the previous one if any */
644 hrc = info->init(ei, curInfo);
645 if (FAILED(hrc)) break;
646
647 ComPtr<IErrorInfo> err;
648 hrc = info.queryInterfaceTo(err.asOutParam());
649 if (SUCCEEDED(hrc))
650 hrc = ::SetErrorInfo(0, err);
651
652#else // !defined(VBOX_WITH_XPCOM)
653
654 nsCOMPtr <nsIExceptionService> es;
655 es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &hrc);
656 if (NS_SUCCEEDED(hrc))
657 {
658 nsCOMPtr <nsIExceptionManager> em;
659 hrc = es->GetCurrentExceptionManager(getter_AddRefs(em));
660 if (FAILED(hrc)) break;
661
662 ComPtr<IVirtualBoxErrorInfo> curInfo;
663 if (preserve)
664 {
665 /* get the current error info if any */
666 ComPtr<nsIException> ex;
667 hrc = em->GetCurrentException(ex.asOutParam());
668 if (FAILED(hrc)) break;
669 hrc = ex.queryInterfaceTo(curInfo.asOutParam());
670 if (FAILED(hrc))
671 {
672 /* create a IVirtualBoxErrorInfo wrapper for the native
673 * nsIException object */
674 ComObjPtr<VirtualBoxErrorInfo> wrapper;
675 hrc = wrapper.createObject();
676 if (SUCCEEDED(hrc))
677 {
678 hrc = wrapper->init(ex);
679 if (SUCCEEDED(hrc))
680 curInfo = wrapper;
681 }
682 }
683 }
684 /* On failure, curInfo will stay null */
685 Assert(SUCCEEDED(hrc) || curInfo.isNull());
686
687 /* set the current error info and preserve the previous one if any */
688 hrc = info->init(ei, curInfo);
689 if (FAILED(hrc)) break;
690
691 ComPtr<nsIException> ex;
692 hrc = info.queryInterfaceTo(ex.asOutParam());
693 if (SUCCEEDED(hrc))
694 hrc = em->SetCurrentException(ex);
695 }
696 else if (hrc == NS_ERROR_UNEXPECTED)
697 {
698 /*
699 * It is possible that setError() is being called by the object
700 * after the XPCOM shutdown sequence has been initiated
701 * (for example, when XPCOM releases all instances it internally
702 * references, which can cause object's FinalConstruct() and then
703 * uninit()). In this case, do_GetService() above will return
704 * NS_ERROR_UNEXPECTED and it doesn't actually make sense to
705 * set the exception (nobody will be able to read it).
706 */
707 Log1WarningFunc(("Will not set an exception because nsIExceptionService is not available (NS_ERROR_UNEXPECTED). XPCOM is being shutdown?\n"));
708 hrc = NS_OK;
709 }
710
711#endif // !defined(VBOX_WITH_XPCOM)
712 }
713 while (0);
714
715 AssertComRC(hrc);
716
717 return SUCCEEDED(hrc) ? ei.getResultCode() : hrc;
718}
719
720/**
721 * Converts the VBox status code a COM one and sets the error info.
722 *
723 * The VBox status code is made available to the API user via
724 * IVirtualBoxErrorInfo::resultDetail attribute.
725 *
726 * @param vrc The VBox status code.
727 * @return COM status code appropriate for @a vrc.
728 *
729 * @sa VirtualBoxBase::setError(HRESULT)
730 */
731HRESULT VirtualBoxBase::setErrorVrc(int vrc)
732{
733 return setErrorInternalF(Global::vboxStatusCodeToCOM(vrc),
734 this->getClassIID(),
735 this->getComponentName(),
736 false /* aWarning */,
737 true /* aLogIt */,
738 vrc /* aResultDetail */,
739 Utf8StrFmt("%Rrc", vrc).c_str());
740}
741
742/**
743 * Converts the VBox status code a COM one and sets the error info.
744 *
745 * @param vrc The VBox status code.
746 * @param pcszMsgFmt Error message format string.
747 * @param va_args Error message format string.
748 * @return COM status code appropriate for @a vrc.
749 *
750 * @sa VirtualBoxBase::setError(HRESULT, const char *, ...)
751 */
752HRESULT VirtualBoxBase::setErrorVrcV(int vrc, const char *pcszMsgFmt, va_list va_args)
753{
754 return setErrorInternalV(Global::vboxStatusCodeToCOM(vrc),
755 this->getClassIID(),
756 this->getComponentName(),
757 pcszMsgFmt, va_args,
758 false /* aWarning */,
759 true /* aLogIt */,
760 vrc /* aResultDetail */);
761}
762
763/**
764 * Converts the VBox status code a COM one and sets the error info.
765 *
766 * @param vrc The VBox status code.
767 * @param pcszMsgFmt Error message format string.
768 * @param ... Argument specified in the @a pcszMsgFmt
769 * @return COM status code appropriate for @a vrc.
770 *
771 * @sa VirtualBoxBase::setError(HRESULT, const char *, ...)
772 */
773HRESULT VirtualBoxBase::setErrorVrc(int vrc, const char *pcszMsgFmt, ...)
774{
775 va_list va;
776 va_start(va, pcszMsgFmt);
777 HRESULT hrc = setErrorVrcV(vrc, pcszMsgFmt, va);
778 va_end(va);
779 return hrc;
780}
781
782/**
783 * Sets error info with both a COM status and an VBox status code.
784 *
785 * The VBox status code is made available to the API user via
786 * IVirtualBoxErrorInfo::resultDetail attribute.
787 *
788 * @param hrc The COM status code to return.
789 * @param vrc The VBox status code.
790 * @return Most likely @a hrc, see setErrorInternal.
791 *
792 * @sa VirtualBoxBase::setError(HRESULT)
793 */
794HRESULT VirtualBoxBase::setErrorBoth(HRESULT hrc, int vrc)
795{
796 return setErrorInternalF(hrc,
797 this->getClassIID(),
798 this->getComponentName(),
799 false /* aWarning */,
800 true /* aLogIt */,
801 vrc /* aResultDetail */,
802 Utf8StrFmt("%Rrc", vrc).c_str());
803}
804
805/**
806 * Sets error info with a message and both a COM status and an VBox status code.
807 *
808 * The VBox status code is made available to the API user via
809 * IVirtualBoxErrorInfo::resultDetail attribute.
810 *
811 * @param hrc The COM status code to return.
812 * @param vrc The VBox status code.
813 * @param pcszMsgFmt Error message format string.
814 * @param ... Argument specified in the @a pcszMsgFmt
815 * @return Most likely @a hrc, see setErrorInternal.
816 *
817 * @sa VirtualBoxBase::setError(HRESULT, const char *, ...)
818 */
819HRESULT VirtualBoxBase::setErrorBoth(HRESULT hrc, int vrc, const char *pcszMsgFmt, ...)
820{
821 va_list va;
822 va_start(va, pcszMsgFmt);
823 hrc = setErrorInternalV(hrc,
824 this->getClassIID(),
825 this->getComponentName(),
826 pcszMsgFmt, va,
827 false /* aWarning */,
828 true /* aLogIt */,
829 vrc /* aResultDetail */);
830 va_end(va);
831 return hrc;
832}
833
834/**
835 * Like setError(), but sets the "warning" bit in the call to setErrorInternal().
836 * @param aResultCode
837 * @param pcsz
838 * @return
839 */
840HRESULT VirtualBoxBase::setWarning(HRESULT aResultCode, const char *pcsz, ...)
841{
842 va_list args;
843 va_start(args, pcsz);
844 HRESULT hrc = setErrorInternalV(aResultCode,
845 this->getClassIID(),
846 this->getComponentName(),
847 pcsz, args,
848 true /* aWarning */,
849 true /* aLogIt */);
850 va_end(args);
851 return hrc;
852}
853
854/**
855 * Like setError(), but disables the "log" flag in the call to setErrorInternal().
856 * @param aResultCode
857 * @param pcsz
858 * @return
859 */
860HRESULT VirtualBoxBase::setErrorNoLog(HRESULT aResultCode, const char *pcsz, ...)
861{
862 va_list args;
863 va_start(args, pcsz);
864 HRESULT hrc = setErrorInternalV(aResultCode,
865 this->getClassIID(),
866 this->getComponentName(),
867 pcsz, args,
868 false /* aWarning */,
869 false /* aLogIt */);
870 va_end(args);
871 return hrc;
872}
873
874/**
875 * Like setErrorBoth(), but disables the "log" flag in the call to setErrorInternal().
876 * @param hrc
877 * @param vrc
878 * @param pcszMsgFmt
879 * @param ...
880 * @return
881 */
882HRESULT VirtualBoxBase::setErrorBothNoLog(HRESULT hrc, int vrc, const char *pcszMsgFmt, ...)
883{
884 va_list va;
885 va_start(va, pcszMsgFmt);
886 hrc = setErrorInternalV(hrc,
887 this->getClassIID(),
888 this->getComponentName(),
889 pcszMsgFmt, va,
890 false /* aWarning */,
891 false /* aLogIt */,
892 vrc /* aResultDetail */);
893 va_end(va);
894 return hrc;
895}
896
897/**
898 * Clear the current error information.
899 */
900/*static*/
901void VirtualBoxBase::clearError(void)
902{
903#if !defined(VBOX_WITH_XPCOM)
904 ::SetErrorInfo(0, NULL);
905#else
906 HRESULT hrc = S_OK;
907 nsCOMPtr <nsIExceptionService> es;
908 es = do_GetService(NS_EXCEPTIONSERVICE_CONTRACTID, &hrc);
909 if (NS_SUCCEEDED(hrc))
910 {
911 nsCOMPtr <nsIExceptionManager> em;
912 hrc = es->GetCurrentExceptionManager(getter_AddRefs(em));
913 if (SUCCEEDED(hrc))
914 em->SetCurrentException(NULL);
915 }
916#endif
917}
918
919
920////////////////////////////////////////////////////////////////////////////////
921//
922// MultiResult methods
923//
924////////////////////////////////////////////////////////////////////////////////
925
926RTTLS MultiResult::sCounter = NIL_RTTLS;
927
928/*static*/
929void MultiResult::incCounter()
930{
931 if (sCounter == NIL_RTTLS)
932 {
933 sCounter = RTTlsAlloc();
934 AssertReturnVoid(sCounter != NIL_RTTLS);
935 }
936
937 uintptr_t counter = (uintptr_t)RTTlsGet(sCounter);
938 ++counter;
939 RTTlsSet(sCounter, (void*)counter);
940}
941
942/*static*/
943void MultiResult::decCounter()
944{
945 uintptr_t counter = (uintptr_t)RTTlsGet(sCounter);
946 AssertReturnVoid(counter != 0);
947 --counter;
948 RTTlsSet(sCounter, (void*)counter);
949}
950
951/*static*/
952bool MultiResult::isMultiEnabled()
953{
954 if (sCounter == NIL_RTTLS)
955 return false;
956
957 return ((uintptr_t)RTTlsGet(MultiResult::sCounter)) > 0;
958}
959
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