VirtualBox

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

Last change on this file since 90828 was 90828, checked in by vboxsync, 4 years ago

Main: bugref:1909: Added API localization

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

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