VirtualBox

source: vbox/trunk/src/VBox/Main/include/VirtualBoxBase.h@ 94703

Last change on this file since 94703 was 94703, checked in by vboxsync, 3 years ago

Main: Added VirtualBoxBase::setErrorVrcV().

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.1 KB
Line 
1/* $Id: VirtualBoxBase.h 94703 2022-04-25 10:25:38Z vboxsync $ */
2/** @file
3 * VirtualBox COM base classes definition
4 */
5
6/*
7 * Copyright (C) 2006-2022 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#ifndef MAIN_INCLUDED_VirtualBoxBase_h
19#define MAIN_INCLUDED_VirtualBoxBase_h
20#ifndef RT_WITHOUT_PRAGMA_ONCE
21# pragma once
22#endif
23
24#include <iprt/cdefs.h>
25#include <iprt/thread.h>
26
27#include <list>
28#include <map>
29
30#include "ObjectState.h"
31
32#include "VBox/com/AutoLock.h"
33#include "VBox/com/string.h"
34#include "VBox/com/Guid.h"
35
36#include "VBox/com/VirtualBox.h"
37
38#include "VirtualBoxTranslator.h"
39
40// avoid including VBox/settings.h and VBox/xml.h; only declare the classes
41namespace xml
42{
43class File;
44}
45
46namespace com
47{
48class ErrorInfo;
49}
50
51using namespace com;
52using namespace util;
53
54class VirtualBox;
55class Machine;
56class Medium;
57class Host;
58typedef std::list<ComObjPtr<Medium> > MediaList;
59typedef std::list<Utf8Str> StringsList;
60
61////////////////////////////////////////////////////////////////////////////////
62//
63// COM helpers
64//
65////////////////////////////////////////////////////////////////////////////////
66
67#if !defined(VBOX_WITH_XPCOM)
68
69/* use a special version of the singleton class factory,
70 * see KB811591 in msdn for more info. */
71
72#undef DECLARE_CLASSFACTORY_SINGLETON
73#define DECLARE_CLASSFACTORY_SINGLETON(obj) DECLARE_CLASSFACTORY_EX(CMyComClassFactorySingleton<obj>)
74
75/**
76 * @todo r=bird: This CMyComClassFactorySingleton stuff is probably obsoleted by
77 * microatl.h? Right?
78 */
79
80template <class T>
81class CMyComClassFactorySingleton : public ATL::CComClassFactory
82{
83public:
84 CMyComClassFactorySingleton() :
85 m_hrCreate(S_OK), m_spObj(NULL)
86 {
87 }
88 virtual ~CMyComClassFactorySingleton()
89 {
90 if (m_spObj)
91 m_spObj->Release();
92 }
93 // IClassFactory
94 STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)
95 {
96 HRESULT hRes = E_POINTER;
97 if (ppvObj != NULL)
98 {
99 *ppvObj = NULL;
100 // no aggregation for singletons
101 AssertReturn(pUnkOuter == NULL, CLASS_E_NOAGGREGATION);
102 if (m_hrCreate == S_OK && m_spObj == NULL)
103 {
104 Lock();
105 __try
106 {
107 // Fix: The following If statement was moved inside the __try statement.
108 // Did another thread arrive here first?
109 if (m_hrCreate == S_OK && m_spObj == NULL)
110 {
111 // lock the module to indicate activity
112 // (necessary for the monitor shutdown thread to correctly
113 // terminate the module in case when CreateInstance() fails)
114 ATL::_pAtlModule->Lock();
115 ATL::CComObjectCached<T> *p;
116 m_hrCreate = ATL::CComObjectCached<T>::CreateInstance(&p);
117 if (SUCCEEDED(m_hrCreate))
118 {
119 m_hrCreate = p->QueryInterface(IID_IUnknown, (void **)&m_spObj);
120 if (FAILED(m_hrCreate))
121 {
122 delete p;
123 }
124 }
125 ATL::_pAtlModule->Unlock();
126 }
127 }
128 __finally
129 {
130 Unlock();
131 }
132 }
133 if (m_hrCreate == S_OK)
134 {
135 hRes = m_spObj->QueryInterface(riid, ppvObj);
136 }
137 else
138 {
139 hRes = m_hrCreate;
140 }
141 }
142 return hRes;
143 }
144 HRESULT m_hrCreate;
145 IUnknown *m_spObj;
146};
147
148#endif /* !defined(VBOX_WITH_XPCOM) */
149
150////////////////////////////////////////////////////////////////////////////////
151//
152// Macros
153//
154////////////////////////////////////////////////////////////////////////////////
155
156/**
157 * Special version of the Assert macro to be used within VirtualBoxBase
158 * subclasses.
159 *
160 * In the debug build, this macro is equivalent to Assert.
161 * In the release build, this macro uses |setError(E_FAIL, ...)| to set the
162 * error info from the asserted expression.
163 *
164 * @see VirtualBoxBase::setError
165 *
166 * @param expr Expression which should be true.
167 */
168#define ComAssert(expr) \
169 do { \
170 if (RT_LIKELY(!!(expr))) \
171 { /* likely */ } \
172 else \
173 { \
174 AssertMsgFailed(("%s\n", #expr)); \
175 setError(E_FAIL, \
176 VirtualBoxBase::tr("Assertion failed: [%s] at '%s' (%d) in %s.\nPlease contact the product vendor!"), \
177 #expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
178 } \
179 } while (0)
180
181/**
182 * Special version of the AssertFailed macro to be used within VirtualBoxBase
183 * subclasses.
184 *
185 * In the debug build, this macro is equivalent to AssertFailed.
186 * In the release build, this macro uses |setError(E_FAIL, ...)| to set the
187 * error info from the asserted expression.
188 *
189 * @see VirtualBoxBase::setError
190 *
191 */
192#define ComAssertFailed() \
193 do { \
194 AssertFailed(); \
195 setError(E_FAIL, \
196 VirtualBoxBase::tr("Assertion failed: at '%s' (%d) in %s.\nPlease contact the product vendor!"), \
197 __FILE__, __LINE__, __PRETTY_FUNCTION__); \
198 } while (0)
199
200/**
201 * Special version of the AssertMsg macro to be used within VirtualBoxBase
202 * subclasses.
203 *
204 * See ComAssert for more info.
205 *
206 * @param expr Expression which should be true.
207 * @param a printf argument list (in parenthesis).
208 */
209#define ComAssertMsg(expr, a) \
210 do { \
211 if (RT_LIKELY(!!(expr))) \
212 { /* likely */ } \
213 else \
214 { \
215 Utf8StrFmt MyAssertMsg a; /* may throw bad_alloc */ \
216 AssertMsgFailed(("%s\n", MyAssertMsg.c_str())); \
217 setError(E_FAIL, \
218 VirtualBoxBase::tr("Assertion failed: [%s] at '%s' (%d) in %s.\n%s.\nPlease contact the product vendor!"), \
219 #expr, __FILE__, __LINE__, __PRETTY_FUNCTION__, MyAssertMsg.c_str()); \
220 } \
221 } while (0)
222
223/**
224 * Special version of the AssertMsgFailed macro to be used within VirtualBoxBase
225 * subclasses.
226 *
227 * See ComAssert for more info.
228 *
229 * @param a printf argument list (in parenthesis).
230 */
231#define ComAssertMsgFailed(a) \
232 do { \
233 Utf8StrFmt MyAssertMsg a; /* may throw bad_alloc */ \
234 AssertMsgFailed(("%s\n", MyAssertMsg.c_str())); \
235 setError(E_FAIL, \
236 VirtualBoxBase::tr("Assertion failed: at '%s' (%d) in %s.\n%s.\nPlease contact the product vendor!"), \
237 __FILE__, __LINE__, __PRETTY_FUNCTION__, MyAssertMsg.c_str()); \
238 } while (0)
239
240/**
241 * Special version of the AssertRC macro to be used within VirtualBoxBase
242 * subclasses.
243 *
244 * See ComAssert for more info.
245 *
246 * @param vrc VBox status code.
247 */
248#define ComAssertRC(vrc) ComAssertMsgRC(vrc, ("%Rra", vrc))
249
250/**
251 * Special version of the AssertMsgRC macro to be used within VirtualBoxBase
252 * subclasses.
253 *
254 * See ComAssert for more info.
255 *
256 * @param vrc VBox status code.
257 * @param msg printf argument list (in parenthesis).
258 */
259#define ComAssertMsgRC(vrc, msg) ComAssertMsg(RT_SUCCESS(vrc), msg)
260
261/**
262 * Special version of the AssertComRC macro to be used within VirtualBoxBase
263 * subclasses.
264 *
265 * See ComAssert for more info.
266 *
267 * @param hrc COM result code
268 */
269#define ComAssertComRC(hrc) ComAssertMsg(SUCCEEDED(hrc), ("COM RC=%Rhrc (0x%08X)", (hrc), (hrc)))
270
271
272/** Special version of ComAssert that returns ret if expr fails */
273#define ComAssertRet(expr, ret) \
274 do { ComAssert(expr); if (!(expr)) return (ret); } while (0)
275/** Special version of ComAssertMsg that returns ret if expr fails */
276#define ComAssertMsgRet(expr, a, ret) \
277 do { ComAssertMsg(expr, a); if (!(expr)) return (ret); } while (0)
278/** Special version of ComAssertRC that returns ret if vrc does not succeed */
279#define ComAssertRCRet(vrc, ret) \
280 do { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) return (ret); } while (0)
281/** Special version of ComAssertComRC that returns ret if rc does not succeed */
282#define ComAssertComRCRet(rc, ret) \
283 do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) return (ret); } while (0)
284/** Special version of ComAssertComRC that returns rc if rc does not succeed */
285#define ComAssertComRCRetRC(rc) \
286 do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) return (rc); } while (0)
287/** Special version of ComAssertFailed that returns ret */
288#define ComAssertFailedRet(ret) \
289 do { ComAssertFailed(); return (ret); } while (0)
290/** Special version of ComAssertMsgFailed that returns ret */
291#define ComAssertMsgFailedRet(msg, ret) \
292 do { ComAssertMsgFailed(msg); return (ret); } while (0)
293
294
295/** Special version of ComAssert that returns void if expr fails */
296#define ComAssertRetVoid(expr) \
297 do { ComAssert(expr); if (!(expr)) return; } while (0)
298/** Special version of ComAssertMsg that returns void if expr fails */
299#define ComAssertMsgRetVoid(expr, a) \
300 do { ComAssertMsg(expr, a); if (!(expr)) return; } while (0)
301/** Special version of ComAssertRC that returns void if vrc does not succeed */
302#define ComAssertRCRetVoid(vrc) \
303 do { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) return; } while (0)
304/** Special version of ComAssertComRC that returns void if rc does not succeed */
305#define ComAssertComRCRetVoid(rc) \
306 do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) return; } while (0)
307/** Special version of ComAssertFailed that returns void */
308#define ComAssertFailedRetVoid() \
309 do { ComAssertFailed(); return; } while (0)
310/** Special version of ComAssertMsgFailed that returns void */
311#define ComAssertMsgFailedRetVoid(msg) \
312 do { ComAssertMsgFailed(msg); return; } while (0)
313
314
315/** Special version of ComAssert that evaluates eval and breaks if expr fails */
316#define ComAssertBreak(expr, eval) \
317 if (1) { ComAssert(expr); if (!(expr)) { eval; break; } } else do {} while (0)
318/** Special version of ComAssertMsg that evaluates eval and breaks if expr fails */
319#define ComAssertMsgBreak(expr, a, eval) \
320 if (1) { ComAssertMsg(expr, a); if (!(expr)) { eval; break; } } else do {} while (0)
321/** Special version of ComAssertRC that evaluates eval and breaks if vrc does not succeed */
322#define ComAssertRCBreak(vrc, eval) \
323 if (1) { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) { eval; break; } } else do {} while (0)
324/** Special version of ComAssertFailed that evaluates eval and breaks */
325#define ComAssertFailedBreak(eval) \
326 if (1) { ComAssertFailed(); { eval; break; } } else do {} while (0)
327/** Special version of ComAssertMsgFailed that evaluates eval and breaks */
328#define ComAssertMsgFailedBreak(msg, eval) \
329 if (1) { ComAssertMsgFailed (msg); { eval; break; } } else do {} while (0)
330/** Special version of ComAssertComRC that evaluates eval and breaks if rc does not succeed */
331#define ComAssertComRCBreak(rc, eval) \
332 if (1) { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { eval; break; } } else do {} while (0)
333/** Special version of ComAssertComRC that just breaks if rc does not succeed */
334#define ComAssertComRCBreakRC(rc) \
335 if (1) { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { break; } } else do {} while (0)
336
337
338/** Special version of ComAssert that evaluates eval and throws it if expr fails */
339#define ComAssertThrow(expr, eval) \
340 do { ComAssert(expr); if (!(expr)) { throw (eval); } } while (0)
341/** Special version of ComAssertRC that evaluates eval and throws it if vrc does not succeed */
342#define ComAssertRCThrow(vrc, eval) \
343 do { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) { throw (eval); } } while (0)
344/** Special version of ComAssertComRC that evaluates eval and throws it if rc does not succeed */
345#define ComAssertComRCThrow(rc, eval) \
346 do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { throw (eval); } } while (0)
347/** Special version of ComAssertComRC that just throws rc if rc does not succeed */
348#define ComAssertComRCThrowRC(rc) \
349 do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { throw rc; } } while (0)
350/** Special version of ComAssert that throws eval */
351#define ComAssertFailedThrow(eval) \
352 do { ComAssertFailed(); { throw (eval); } } while (0)
353
354////////////////////////////////////////////////////////////////////////////////
355
356/**
357 * Checks that the pointer argument is not NULL and returns E_INVALIDARG +
358 * extended error info on failure.
359 * @param arg Input pointer-type argument (strings, interface pointers...)
360 */
361#define CheckComArgNotNull(arg) \
362 do { \
363 if (RT_LIKELY((arg) != NULL)) \
364 { /* likely */ }\
365 else \
366 return setError(E_INVALIDARG, VirtualBoxBase::tr("Argument %s is NULL"), #arg); \
367 } while (0)
368
369/**
370 * Checks that the pointer argument is a valid pointer or NULL and returns
371 * E_INVALIDARG + extended error info on failure.
372 * @param arg Input pointer-type argument (strings, interface pointers...)
373 */
374#define CheckComArgMaybeNull(arg) \
375 do { \
376 if (RT_LIKELY(RT_VALID_PTR(arg) || (arg) == NULL)) \
377 { /* likely */ }\
378 else \
379 return setError(E_INVALIDARG, \
380 VirtualBoxBase::tr("Argument %s is an invalid pointer"), #arg); \
381 } while (0)
382
383/**
384 * Checks that the given pointer to an argument is valid and returns
385 * E_POINTER + extended error info otherwise.
386 * @param arg Pointer argument.
387 */
388#define CheckComArgPointerValid(arg) \
389 do { \
390 if (RT_LIKELY(RT_VALID_PTR(arg))) \
391 { /* likely */ }\
392 else \
393 return setError(E_POINTER, \
394 VirtualBoxBase::tr("Argument %s points to invalid memory location (%p)"), \
395 #arg, (void *)(arg)); \
396 } while (0)
397
398/**
399 * Checks that safe array argument is not NULL and returns E_INVALIDARG +
400 * extended error info on failure.
401 * @param arg Input safe array argument (strings, interface pointers...)
402 */
403#define CheckComArgSafeArrayNotNull(arg) \
404 do { \
405 if (RT_LIKELY(!ComSafeArrayInIsNull(arg))) \
406 { /* likely */ }\
407 else \
408 return setError(E_INVALIDARG, \
409 VirtualBoxBase::tr("Argument %s is NULL"), #arg); \
410 } while (0)
411
412/**
413 * Checks that a string input argument is valid (not NULL or obviously invalid
414 * pointer), returning E_INVALIDARG + extended error info if invalid.
415 * @param a_bstrIn Input string argument (IN_BSTR).
416 */
417#define CheckComArgStr(a_bstrIn) \
418 do { \
419 IN_BSTR const bstrInCheck = (a_bstrIn); /* type check */ \
420 if (RT_LIKELY(RT_VALID_PTR(bstrInCheck))) \
421 { /* likely */ }\
422 else \
423 return setError(E_INVALIDARG, \
424 VirtualBoxBase::tr("Argument %s is an invalid pointer"), #a_bstrIn); \
425 } while (0)
426/**
427 * Checks that the string argument is not a NULL, a invalid pointer or an empty
428 * string, returning E_INVALIDARG + extended error info on failure.
429 * @param a_bstrIn Input string argument (BSTR etc.).
430 */
431#define CheckComArgStrNotEmptyOrNull(a_bstrIn) \
432 do { \
433 IN_BSTR const bstrInCheck = (a_bstrIn); /* type check */ \
434 if (RT_LIKELY(RT_VALID_PTR(bstrInCheck) && *(bstrInCheck) != '\0')) \
435 { /* likely */ }\
436 else \
437 return setError(E_INVALIDARG, \
438 VirtualBoxBase::tr("Argument %s is empty or an invalid pointer"), \
439 #a_bstrIn); \
440 } while (0)
441
442/**
443 * Converts the Guid input argument (string) to a Guid object, returns with
444 * E_INVALIDARG and error message on failure.
445 *
446 * @param a_Arg Argument.
447 * @param a_GuidVar The Guid variable name.
448 */
449#define CheckComArgGuid(a_Arg, a_GuidVar) \
450 do { \
451 Guid tmpGuid(a_Arg); \
452 (a_GuidVar) = tmpGuid; \
453 if (RT_LIKELY((a_GuidVar).isValid())) \
454 { /* likely */ }\
455 else \
456 return setError(E_INVALIDARG, \
457 VirtualBoxBase::tr("GUID argument %s is not valid (\"%ls\")"), \
458 #a_Arg, Bstr(a_Arg).raw()); \
459 } while (0)
460
461/**
462 * Checks that the given expression (that must involve the argument) is true and
463 * returns E_INVALIDARG + extended error info on failure.
464 * @param arg Argument.
465 * @param expr Expression to evaluate.
466 */
467#define CheckComArgExpr(arg, expr) \
468 do { \
469 if (RT_LIKELY(!!(expr))) \
470 { /* likely */ }\
471 else \
472 return setError(E_INVALIDARG, \
473 VirtualBoxBase::tr("Argument %s is invalid (must be %s)"), \
474 #arg, #expr); \
475 } while (0)
476
477/**
478 * Checks that the given expression (that must involve the argument) is true and
479 * returns E_INVALIDARG + extended error info on failure. The error message must
480 * be customized.
481 * @param arg Argument.
482 * @param expr Expression to evaluate.
483 * @param msg Parenthesized printf-like expression (must start with a verb,
484 * like "must be one of...", "is not within...").
485 */
486#define CheckComArgExprMsg(arg, expr, msg) \
487 do { \
488 if (RT_LIKELY(!!(expr))) \
489 { /* likely */ }\
490 else \
491 return setError(E_INVALIDARG, VirtualBoxBase::tr("Argument %s %s"), \
492 #arg, Utf8StrFmt msg .c_str()); \
493 } while (0)
494
495/**
496 * Checks that the given pointer to an output argument is valid and returns
497 * E_POINTER + extended error info otherwise.
498 * @param arg Pointer argument.
499 */
500#define CheckComArgOutPointerValid(arg) \
501 do { \
502 if (RT_LIKELY(RT_VALID_PTR(arg))) \
503 { /* likely */ }\
504 else \
505 return setError(E_POINTER, \
506 VirtualBoxBase::tr("Output argument %s points to invalid memory location (%p)"), \
507 #arg, (void *)(arg)); \
508 } while (0)
509
510/**
511 * Checks that the given pointer to an output safe array argument is valid and
512 * returns E_POINTER + extended error info otherwise.
513 * @param arg Safe array argument.
514 */
515#define CheckComArgOutSafeArrayPointerValid(arg) \
516 do { \
517 if (RT_LIKELY(!ComSafeArrayOutIsNull(arg))) \
518 { /* likely */ }\
519 else \
520 return setError(E_POINTER, \
521 VirtualBoxBase::tr("Output argument %s points to invalid memory location (%p)"), \
522 #arg, (void*)(arg)); \
523 } while (0)
524
525/**
526 * Sets the extended error info and returns E_NOTIMPL.
527 */
528#define ReturnComNotImplemented() \
529 do { \
530 return setError(E_NOTIMPL, VirtualBoxBase::tr("Method %s is not implemented"), __FUNCTION__); \
531 } while (0)
532
533/**
534 * Declares an empty constructor and destructor for the given class.
535 * This is useful to prevent the compiler from generating the default
536 * ctor and dtor, which in turn allows to use forward class statements
537 * (instead of including their header files) when declaring data members of
538 * non-fundamental types with constructors (which are always called implicitly
539 * by constructors and by the destructor of the class).
540 *
541 * This macro is to be placed within (the public section of) the class
542 * declaration. Its counterpart, DEFINE_EMPTY_CTOR_DTOR, must be placed
543 * somewhere in one of the translation units (usually .cpp source files).
544 *
545 * @param cls class to declare a ctor and dtor for
546 */
547#define DECLARE_EMPTY_CTOR_DTOR(cls) cls(); virtual ~cls();
548
549/**
550 * Defines an empty constructor and destructor for the given class.
551 * See DECLARE_EMPTY_CTOR_DTOR for more info.
552 */
553#define DEFINE_EMPTY_CTOR_DTOR(cls) \
554 cls::cls() { /*empty*/ } \
555 cls::~cls() { /*empty*/ }
556
557/**
558 * A variant of 'throw' that hits a debug breakpoint first to make
559 * finding the actual thrower possible.
560 */
561#ifdef DEBUG
562# define DebugBreakThrow(a) \
563 do { \
564 RTAssertDebugBreak(); \
565 throw (a); \
566 } while (0)
567#else
568# define DebugBreakThrow(a) throw (a)
569#endif
570
571////////////////////////////////////////////////////////////////////////////////
572//
573// VirtualBoxBase
574//
575////////////////////////////////////////////////////////////////////////////////
576
577#ifdef VBOX_WITH_MAIN_NLS
578# define DECLARE_TRANSLATE_METHODS(cls) \
579 static inline const char *tr(const char *aSourceText, \
580 const char *aComment = NULL, \
581 const size_t aNum = ~(size_t)0) \
582 { \
583 return VirtualBoxTranslator::translate(NULL, #cls, aSourceText, aComment, aNum); \
584 }
585#else
586# define DECLARE_TRANSLATE_METHODS(cls) \
587 static inline const char *tr(const char *aSourceText, \
588 const char *aComment = NULL, \
589 const size_t aNum = ~(size_t)0) \
590 { \
591 RT_NOREF(aComment, aNum); \
592 return aSourceText; \
593 }
594#endif
595
596#define DECLARE_COMMON_CLASS_METHODS(cls) \
597 DECLARE_EMPTY_CTOR_DTOR(cls) \
598 DECLARE_TRANSLATE_METHODS(cls)
599
600#define VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface) \
601 virtual const IID& getClassIID() const \
602 { \
603 return cls::getStaticClassIID(); \
604 } \
605 static const IID& getStaticClassIID() \
606 { \
607 return COM_IIDOF(iface); \
608 } \
609 virtual const char* getComponentName() const \
610 { \
611 return cls::getStaticComponentName(); \
612 } \
613 static const char* getStaticComponentName() \
614 { \
615 return #cls; \
616 }
617
618/**
619 * VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT:
620 * This macro must be used once in the declaration of any class derived
621 * from VirtualBoxBase. It implements the pure virtual getClassIID() and
622 * getComponentName() methods. If this macro is not present, instances
623 * of a class derived from VirtualBoxBase cannot be instantiated.
624 *
625 * @param cls The class name, e.g. "Class".
626 * @param iface The interface name which this class implements, e.g. "IClass".
627 */
628#ifdef VBOX_WITH_XPCOM
629 #define VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(cls, iface) \
630 VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface)
631#else // !VBOX_WITH_XPCOM
632 #define VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(cls, iface) \
633 VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface) \
634 STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid) \
635 { \
636 const ATL::_ATL_INTMAP_ENTRY* pEntries = cls::_GetEntries(); \
637 Assert(pEntries); \
638 if (!pEntries) \
639 return S_FALSE; \
640 BOOL bSupports = FALSE; \
641 BOOL bISupportErrorInfoFound = FALSE; \
642 while (pEntries->pFunc != NULL && !bSupports) \
643 { \
644 if (!bISupportErrorInfoFound) \
645 bISupportErrorInfoFound = InlineIsEqualGUID(*(pEntries->piid), IID_ISupportErrorInfo); \
646 else \
647 bSupports = InlineIsEqualGUID(*(pEntries->piid), riid); \
648 pEntries++; \
649 } \
650 Assert(bISupportErrorInfoFound); \
651 return bSupports ? S_OK : S_FALSE; \
652 }
653#endif // !VBOX_WITH_XPCOM
654
655/**
656 * VBOX_TWEAK_INTERFACE_ENTRY:
657 * Macro for defining magic interface entries needed for all interfaces
658 * implemented by any subclass of VirtualBoxBase.
659 */
660#ifdef VBOX_WITH_XPCOM
661#define VBOX_TWEAK_INTERFACE_ENTRY(iface)
662#else // !VBOX_WITH_XPCOM
663#define VBOX_TWEAK_INTERFACE_ENTRY(iface) \
664 COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pUnkMarshaler.m_p)
665#endif // !VBOX_WITH_XPCOM
666
667
668/**
669 * Abstract base class for all component classes implementing COM
670 * interfaces of the VirtualBox COM library.
671 *
672 * Declares functionality that should be available in all components.
673 *
674 * The object state logic is documented in ObjectState.h.
675 */
676class ATL_NO_VTABLE VirtualBoxBase
677 : public Lockable
678 , public ATL::CComObjectRootEx<ATL::CComMultiThreadModel>
679#if !defined (VBOX_WITH_XPCOM)
680 , public ISupportErrorInfo
681#endif
682{
683protected:
684#ifdef RT_OS_WINDOWS
685 ComPtr<IUnknown> m_pUnkMarshaler;
686#endif
687
688 HRESULT BaseFinalConstruct();
689 void BaseFinalRelease();
690
691public:
692 DECLARE_COMMON_CLASS_METHODS(VirtualBoxBase)
693
694 /**
695 * Uninitialization method.
696 *
697 * Must be called by all final implementations (component classes) when the
698 * last reference to the object is released, before calling the destructor.
699 *
700 * @note Never call this method the AutoCaller scope or after the
701 * ObjectState::addCaller() call not paired by
702 * ObjectState::releaseCaller() because it is a guaranteed deadlock.
703 * See AutoUninitSpan and AutoCaller.h/ObjectState.h for details.
704 */
705 virtual void uninit()
706 { }
707
708 /**
709 */
710 ObjectState &getObjectState()
711 {
712 return mState;
713 }
714
715 /**
716 * Pure virtual method for simple run-time type identification without
717 * having to enable C++ RTTI.
718 *
719 * This *must* be implemented by every subclass deriving from VirtualBoxBase;
720 * use the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro to do that most easily.
721 */
722 virtual const IID& getClassIID() const = 0;
723
724 /**
725 * Pure virtual method for simple run-time type identification without
726 * having to enable C++ RTTI.
727 *
728 * This *must* be implemented by every subclass deriving from VirtualBoxBase;
729 * use the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro to do that most easily.
730 */
731 virtual const char* getComponentName() const = 0;
732
733 /**
734 * Virtual method which determines the locking class to be used for validating
735 * lock order with the standard member lock handle. This method is overridden
736 * in a number of subclasses.
737 */
738 virtual VBoxLockingClass getLockingClass() const
739 {
740 return LOCKCLASS_OTHEROBJECT;
741 }
742
743 virtual RWLockHandle *lockHandle() const;
744
745 static HRESULT handleUnexpectedExceptions(VirtualBoxBase *const aThis, RT_SRC_POS_DECL);
746
747 static HRESULT setErrorInternalF(HRESULT aResultCode,
748 const GUID &aIID,
749 const char *aComponent,
750 bool aWarning,
751 bool aLogIt,
752 LONG aResultDetail,
753 const char *aText, ...);
754 static HRESULT setErrorInternalV(HRESULT aResultCode,
755 const GUID &aIID,
756 const char *aComponent,
757 const char *aText,
758 va_list aArgs,
759 bool aWarning,
760 bool aLogIt,
761 LONG aResultDetail = 0);
762 static void clearError(void);
763
764 HRESULT setError(HRESULT aResultCode);
765 HRESULT setError(HRESULT aResultCode, const char *pcsz, ...);
766 HRESULT setError(const ErrorInfo &ei);
767 HRESULT setErrorVrcV(int vrc, const char *pcszMsgFmt, va_list va_args);
768 HRESULT setErrorVrc(int vrc);
769 HRESULT setErrorVrc(int vrc, const char *pcszMsgFmt, ...);
770 HRESULT setErrorBoth(HRESULT hrc, int vrc);
771 HRESULT setErrorBoth(HRESULT hrc, int vrc, const char *pcszMsgFmt, ...);
772 HRESULT setWarning(HRESULT aResultCode, const char *pcsz, ...);
773 HRESULT setErrorNoLog(HRESULT aResultCode, const char *pcsz, ...);
774
775
776 /** Initialize COM for a new thread. */
777 static HRESULT initializeComForThread(void)
778 {
779#ifndef VBOX_WITH_XPCOM
780 HRESULT hrc = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE | COINIT_SPEED_OVER_MEMORY);
781 AssertComRCReturn(hrc, hrc);
782#endif
783 return S_OK;
784 }
785
786 /** Uninitializes COM for a dying thread. */
787 static void uninitializeComForThread(void)
788 {
789#ifndef VBOX_WITH_XPCOM
790 CoUninitialize();
791#endif
792 }
793
794
795private:
796 /** Object for representing object state */
797 ObjectState mState;
798
799 /** User-level object lock for subclasses */
800 RWLockHandle *mObjectLock;
801
802 /** Slot of this object in the g_aClassFactoryStats array */
803 uint32_t iFactoryStat;
804
805private:
806 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(VirtualBoxBase); /* Shuts up MSC warning C4625. */
807};
808
809/** Structure for counting the currently existing and ever created objects
810 * for each component name. */
811typedef struct CLASSFACTORY_STAT
812{
813 const char *psz;
814 uint64_t current;
815 uint64_t overall;
816} CLASSFACTORY_STAT;
817
818/** Maximum number of component names to deal with. There will be debug
819 * assertions if the value is too low. Since the table is global and its
820 * entries are reasonably small, it's not worth squeezing out the last bit. */
821#define CLASSFACTORYSTATS_MAX 128
822
823/* global variables (defined in VirtualBoxBase.cpp) */
824extern CLASSFACTORY_STAT g_aClassFactoryStats[CLASSFACTORYSTATS_MAX];
825extern RWLockHandle *g_pClassFactoryStatsLock;
826
827extern void APIDumpComponentFactoryStats();
828
829/**
830 * Dummy macro that is used to shut down Qt's lupdate tool warnings in some
831 * situations. This macro needs to be present inside (better at the very
832 * beginning) of the declaration of the class that uses translation, to make
833 * lupdate happy.
834 */
835#define Q_OBJECT
836
837////////////////////////////////////////////////////////////////////////////////
838
839////////////////////////////////////////////////////////////////////////////////
840
841
842/**
843 * Simple template that manages data structure allocation/deallocation
844 * and supports data pointer sharing (the instance that shares the pointer is
845 * not responsible for memory deallocation as opposed to the instance that
846 * owns it).
847 */
848template <class D>
849class Shareable
850{
851public:
852
853 Shareable() : mData(NULL), mIsShared(FALSE) {}
854 virtual ~Shareable() { free(); }
855
856 void allocate() { attach(new D); }
857
858 virtual void free() {
859 if (mData) {
860 if (!mIsShared)
861 delete mData;
862 mData = NULL;
863 mIsShared = false;
864 }
865 }
866
867 void attach(D *d) {
868 AssertMsg(d, ("new data must not be NULL"));
869 if (d && mData != d) {
870 if (mData && !mIsShared)
871 delete mData;
872 mData = d;
873 mIsShared = false;
874 }
875 }
876
877 void attach(Shareable &d) {
878 AssertMsg(
879 d.mData == mData || !d.mIsShared,
880 ("new data must not be shared")
881 );
882 if (this != &d && !d.mIsShared) {
883 attach(d.mData);
884 d.mIsShared = true;
885 }
886 }
887
888 void share(D *d) {
889 AssertMsg(d, ("new data must not be NULL"));
890 if (mData != d) {
891 if (mData && !mIsShared)
892 delete mData;
893 mData = d;
894 mIsShared = true;
895 }
896 }
897
898 void share(const Shareable &d) { share(d.mData); }
899
900 void attachCopy(const D *d) {
901 AssertMsg(d, ("data to copy must not be NULL"));
902 if (d)
903 attach(new D(*d));
904 }
905
906 void attachCopy(const Shareable &d) {
907 attachCopy(d.mData);
908 }
909
910 virtual D *detach() {
911 D *d = mData;
912 mData = NULL;
913 mIsShared = false;
914 return d;
915 }
916
917 D *data() const {
918 return mData;
919 }
920
921 D *operator->() const {
922 AssertMsg(mData, ("data must not be NULL"));
923 return mData;
924 }
925
926 bool isNull() const { return mData == NULL; }
927 bool operator!() const { return isNull(); }
928
929 bool isShared() const { return mIsShared; }
930
931protected:
932
933 D *mData;
934 bool mIsShared;
935};
936
937/**
938 * Simple template that enhances Shareable<> and supports data
939 * backup/rollback/commit (using the copy constructor of the managed data
940 * structure).
941 */
942template<class D>
943class Backupable : public Shareable<D>
944{
945public:
946
947 Backupable() : Shareable<D>(), mBackupData(NULL) {}
948
949 void free()
950 {
951 AssertMsg(this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
952 rollback();
953 Shareable<D>::free();
954 }
955
956 D *detach()
957 {
958 AssertMsg(this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
959 rollback();
960 return Shareable<D>::detach();
961 }
962
963 void share(const Backupable &d)
964 {
965 AssertMsg(!d.isBackedUp(), ("data to share must not be backed up"));
966 if (!d.isBackedUp())
967 Shareable<D>::share(d.mData);
968 }
969
970 /**
971 * Stores the current data pointer in the backup area, allocates new data
972 * using the copy constructor on current data and makes new data active.
973 *
974 * @deprecated Use backupEx to avoid throwing wild out-of-memory exceptions.
975 */
976 void backup()
977 {
978 AssertMsg(this->mData, ("data must not be NULL"));
979 if (this->mData && !mBackupData)
980 {
981 D *pNewData = new D(*this->mData);
982 mBackupData = this->mData;
983 this->mData = pNewData;
984 }
985 }
986
987 /**
988 * Stores the current data pointer in the backup area, allocates new data
989 * using the copy constructor on current data and makes new data active.
990 *
991 * @returns S_OK, E_OUTOFMEMORY or E_FAIL (internal error).
992 */
993 HRESULT backupEx()
994 {
995 AssertMsgReturn(this->mData, ("data must not be NULL"), E_FAIL);
996 if (this->mData && !mBackupData)
997 {
998 try
999 {
1000 D *pNewData = new D(*this->mData);
1001 mBackupData = this->mData;
1002 this->mData = pNewData;
1003 }
1004 catch (std::bad_alloc &)
1005 {
1006 return E_OUTOFMEMORY;
1007 }
1008 }
1009 return S_OK;
1010 }
1011
1012 /**
1013 * Deletes new data created by #backup() and restores previous data pointer
1014 * stored in the backup area, making it active again.
1015 */
1016 void rollback()
1017 {
1018 if (this->mData && mBackupData)
1019 {
1020 delete this->mData;
1021 this->mData = mBackupData;
1022 mBackupData = NULL;
1023 }
1024 }
1025
1026 /**
1027 * Commits current changes by deleting backed up data and clearing up the
1028 * backup area. The new data pointer created by #backup() remains active
1029 * and becomes the only managed pointer.
1030 *
1031 * This method is much faster than #commitCopy() (just a single pointer
1032 * assignment operation), but makes the previous data pointer invalid
1033 * (because it is freed). For this reason, this method must not be
1034 * used if it's possible that data managed by this instance is shared with
1035 * some other Shareable instance. See #commitCopy().
1036 */
1037 void commit()
1038 {
1039 if (this->mData && mBackupData)
1040 {
1041 if (!this->mIsShared)
1042 delete mBackupData;
1043 mBackupData = NULL;
1044 this->mIsShared = false;
1045 }
1046 }
1047
1048 /**
1049 * Commits current changes by assigning new data to the previous data
1050 * pointer stored in the backup area using the assignment operator.
1051 * New data is deleted, the backup area is cleared and the previous data
1052 * pointer becomes active and the only managed pointer.
1053 *
1054 * This method is slower than #commit(), but it keeps the previous data
1055 * pointer valid (i.e. new data is copied to the same memory location).
1056 * For that reason it's safe to use this method on instances that share
1057 * managed data with other Shareable instances.
1058 */
1059 void commitCopy()
1060 {
1061 if (this->mData && mBackupData)
1062 {
1063 *mBackupData = *(this->mData);
1064 delete this->mData;
1065 this->mData = mBackupData;
1066 mBackupData = NULL;
1067 }
1068 }
1069
1070 void assignCopy(const D *pData)
1071 {
1072 AssertMsg(this->mData, ("data must not be NULL"));
1073 AssertMsg(pData, ("data to copy must not be NULL"));
1074 if (this->mData && pData)
1075 {
1076 if (!mBackupData)
1077 {
1078 D *pNewData = new D(*pData);
1079 mBackupData = this->mData;
1080 this->mData = pNewData;
1081 }
1082 else
1083 *this->mData = *pData;
1084 }
1085 }
1086
1087 void assignCopy(const Backupable &d)
1088 {
1089 assignCopy(d.mData);
1090 }
1091
1092 bool isBackedUp() const
1093 {
1094 return mBackupData != NULL;
1095 }
1096
1097 D *backedUpData() const
1098 {
1099 return mBackupData;
1100 }
1101
1102protected:
1103
1104 D *mBackupData;
1105};
1106
1107#endif /* !MAIN_INCLUDED_VirtualBoxBase_h */
1108
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