VirtualBox

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

Last change on this file since 107044 was 106878, checked in by vboxsync, 3 months ago

Added global gTrackedObjectsCollector. Added into VirtualBoxBase the members mObjectId, mfTracked and the functions getObjectId(), setTracked(), invalidateTracked().

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