VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.5 KB
Line 
1/* $Id: VirtualBoxBase.h 106061 2024-09-16 14:03:52Z 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/**
679 * Abstract base class for all component classes implementing COM
680 * interfaces of the VirtualBox COM library.
681 *
682 * Declares functionality that should be available in all components.
683 *
684 * The object state logic is documented in ObjectState.h.
685 */
686class ATL_NO_VTABLE VirtualBoxBase
687 : public Lockable
688 , public ATL::CComObjectRootEx<ATL::CComMultiThreadModel>
689#if !defined (VBOX_WITH_XPCOM)
690 , public ISupportErrorInfo
691#endif
692{
693protected:
694#ifdef RT_OS_WINDOWS
695 ComPtr<IUnknown> m_pUnkMarshaler;
696#endif
697
698 HRESULT BaseFinalConstruct();
699 void BaseFinalRelease();
700
701public:
702 DECLARE_COMMON_CLASS_METHODS(VirtualBoxBase)
703
704 /**
705 * Uninitialization method.
706 *
707 * Must be called by all final implementations (component classes) when the
708 * last reference to the object is released, before calling the destructor.
709 *
710 * @note Never call this method the AutoCaller scope or after the
711 * ObjectState::addCaller() call not paired by
712 * ObjectState::releaseCaller() because it is a guaranteed deadlock.
713 * See AutoUninitSpan and AutoCaller.h/ObjectState.h for details.
714 */
715 virtual void uninit()
716 { }
717
718 /**
719 */
720 ObjectState &getObjectState()
721 {
722 return mState;
723 }
724
725 /**
726 * Pure virtual method for simple run-time type identification without
727 * having to enable C++ RTTI.
728 *
729 * This *must* be implemented by every subclass deriving from VirtualBoxBase;
730 * use the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro to do that most easily.
731 */
732 virtual const IID& getClassIID() const = 0;
733
734 /**
735 * Pure virtual method for simple run-time type identification without
736 * having to enable C++ RTTI.
737 *
738 * This *must* be implemented by every subclass deriving from VirtualBoxBase;
739 * use the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro to do that most easily.
740 */
741 virtual const char* getComponentName() const = 0;
742
743 /**
744 * Virtual method which determines the locking class to be used for validating
745 * lock order with the standard member lock handle. This method is overridden
746 * in a number of subclasses.
747 */
748 virtual VBoxLockingClass getLockingClass() const
749 {
750 return LOCKCLASS_OTHEROBJECT;
751 }
752
753 virtual RWLockHandle *lockHandle() const;
754
755 static HRESULT handleUnexpectedExceptions(VirtualBoxBase *const aThis, RT_SRC_POS_DECL);
756
757 static HRESULT setErrorInternalF(HRESULT aResultCode,
758 const GUID &aIID,
759 const char *aComponent,
760 bool aWarning,
761 bool aLogIt,
762 LONG aResultDetail,
763 const char *aText, ...);
764 static HRESULT setErrorInternalV(HRESULT aResultCode,
765 const GUID &aIID,
766 const char *aComponent,
767 const char *aText,
768 va_list aArgs,
769 bool aWarning,
770 bool aLogIt,
771 LONG aResultDetail = 0);
772 static void clearError(void);
773
774 HRESULT setError(HRESULT aResultCode);
775 HRESULT setError(HRESULT aResultCode, const char *pcsz, ...);
776 HRESULT setError(const ErrorInfo &ei);
777 HRESULT setErrorVrcV(int vrc, const char *pcszMsgFmt, va_list va_args);
778 HRESULT setErrorVrc(int vrc);
779 HRESULT setErrorVrc(int vrc, const char *pcszMsgFmt, ...);
780 HRESULT setErrorBoth(HRESULT hrc, int vrc);
781 HRESULT setErrorBoth(HRESULT hrc, int vrc, const char *pcszMsgFmt, ...);
782 HRESULT setWarning(HRESULT aResultCode, const char *pcsz, ...);
783 HRESULT setErrorNoLog(HRESULT aResultCode, const char *pcsz, ...);
784 HRESULT setErrorBothNoLog(HRESULT hrc, int vrc, const char *pcszMsgFmt, ...);
785
786
787 /** Initialize COM for a new thread. */
788 static HRESULT initializeComForThread(void)
789 {
790#ifndef VBOX_WITH_XPCOM
791 HRESULT hrc = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE | COINIT_SPEED_OVER_MEMORY);
792 AssertComRCReturn(hrc, hrc);
793#endif
794 return S_OK;
795 }
796
797 /** Uninitializes COM for a dying thread. */
798 static void uninitializeComForThread(void)
799 {
800#ifndef VBOX_WITH_XPCOM
801 CoUninitialize();
802#endif
803 }
804
805
806private:
807 /** Object for representing object state */
808 ObjectState mState;
809
810 /** User-level object lock for subclasses */
811 RWLockHandle *mObjectLock;
812
813 /** Slot of this object in the g_aClassFactoryStats array */
814 uint32_t iFactoryStat;
815
816private:
817 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(VirtualBoxBase); /* Shuts up MSC warning C4625. */
818};
819
820/** Structure for counting the currently existing and ever created objects
821 * for each component name. */
822typedef struct CLASSFACTORY_STAT
823{
824 const char *psz;
825 uint64_t current;
826 uint64_t overall;
827} CLASSFACTORY_STAT;
828
829/** Maximum number of component names to deal with. There will be debug
830 * assertions if the value is too low. Since the table is global and its
831 * entries are reasonably small, it's not worth squeezing out the last bit. */
832#define CLASSFACTORYSTATS_MAX 128
833
834/* global variables (defined in VirtualBoxBase.cpp) */
835extern CLASSFACTORY_STAT g_aClassFactoryStats[CLASSFACTORYSTATS_MAX];
836extern RWLockHandle *g_pClassFactoryStatsLock;
837
838extern void APIDumpComponentFactoryStats();
839
840/**
841 * Dummy macro that is used to shut down Qt's lupdate tool warnings in some
842 * situations. This macro needs to be present inside (better at the very
843 * beginning) of the declaration of the class that uses translation, to make
844 * lupdate happy.
845 */
846#define Q_OBJECT
847
848////////////////////////////////////////////////////////////////////////////////
849
850////////////////////////////////////////////////////////////////////////////////
851
852
853/**
854 * Simple template that manages data structure allocation/deallocation
855 * and supports data pointer sharing (the instance that shares the pointer is
856 * not responsible for memory deallocation as opposed to the instance that
857 * owns it).
858 */
859template <class D>
860class Shareable
861{
862public:
863
864 Shareable() : mData(NULL), mIsShared(FALSE) {}
865 virtual ~Shareable() { free(); }
866
867 void allocate() { attach(new D); }
868
869 virtual void free() {
870 if (mData) {
871 if (!mIsShared)
872 delete mData;
873 mData = NULL;
874 mIsShared = false;
875 }
876 }
877
878 void attach(D *d) {
879 AssertMsg(d, ("new data must not be NULL"));
880 if (d && mData != d) {
881 if (mData && !mIsShared)
882 delete mData;
883 mData = d;
884 mIsShared = false;
885 }
886 }
887
888 void attach(Shareable &d) {
889 AssertMsg(
890 d.mData == mData || !d.mIsShared,
891 ("new data must not be shared")
892 );
893 if (this != &d && !d.mIsShared) {
894 attach(d.mData);
895 d.mIsShared = true;
896 }
897 }
898
899 void share(D *d) {
900 AssertMsg(d, ("new data must not be NULL"));
901 if (mData != d) {
902 if (mData && !mIsShared)
903 delete mData;
904 mData = d;
905 mIsShared = true;
906 }
907 }
908
909 void share(const Shareable &d) { share(d.mData); }
910
911 void attachCopy(const D *d) {
912 AssertMsg(d, ("data to copy must not be NULL"));
913 if (d)
914 attach(new D(*d));
915 }
916
917 void attachCopy(const Shareable &d) {
918 attachCopy(d.mData);
919 }
920
921 virtual D *detach() {
922 D *d = mData;
923 mData = NULL;
924 mIsShared = false;
925 return d;
926 }
927
928 D *data() const {
929 return mData;
930 }
931
932 D *operator->() const {
933 AssertMsg(mData, ("data must not be NULL"));
934 return mData;
935 }
936
937 bool isNull() const { return mData == NULL; }
938 bool operator!() const { return isNull(); }
939
940 bool isShared() const { return mIsShared; }
941
942protected:
943
944 D *mData;
945 bool mIsShared;
946};
947
948/**
949 * Simple template that enhances Shareable<> and supports data
950 * backup/rollback/commit (using the copy constructor of the managed data
951 * structure).
952 */
953template<class D>
954class Backupable : public Shareable<D>
955{
956public:
957
958 Backupable() : Shareable<D>(), mBackupData(NULL) {}
959
960 void free()
961 {
962 AssertMsg(this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
963 rollback();
964 Shareable<D>::free();
965 }
966
967 D *detach()
968 {
969 AssertMsg(this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
970 rollback();
971 return Shareable<D>::detach();
972 }
973
974 void share(const Backupable &d)
975 {
976 AssertMsg(!d.isBackedUp(), ("data to share must not be backed up"));
977 if (!d.isBackedUp())
978 Shareable<D>::share(d.mData);
979 }
980
981 /**
982 * Stores the current data pointer in the backup area, allocates new data
983 * using the copy constructor on current data and makes new data active.
984 *
985 * @deprecated Use backupEx to avoid throwing wild out-of-memory exceptions.
986 */
987 void backup()
988 {
989 AssertMsg(this->mData, ("data must not be NULL"));
990 if (this->mData && !mBackupData)
991 {
992 D *pNewData = new D(*this->mData);
993 mBackupData = this->mData;
994 this->mData = pNewData;
995 }
996 }
997
998 /**
999 * Stores the current data pointer in the backup area, allocates new data
1000 * using the copy constructor on current data and makes new data active.
1001 *
1002 * @returns S_OK, E_OUTOFMEMORY or E_FAIL (internal error).
1003 */
1004 HRESULT backupEx()
1005 {
1006 AssertMsgReturn(this->mData, ("data must not be NULL"), E_FAIL);
1007 if (this->mData && !mBackupData)
1008 {
1009 try
1010 {
1011 D *pNewData = new D(*this->mData);
1012 mBackupData = this->mData;
1013 this->mData = pNewData;
1014 }
1015 catch (std::bad_alloc &)
1016 {
1017 return E_OUTOFMEMORY;
1018 }
1019 }
1020 return S_OK;
1021 }
1022
1023 /**
1024 * Deletes new data created by #backup() and restores previous data pointer
1025 * stored in the backup area, making it active again.
1026 */
1027 void rollback()
1028 {
1029 if (this->mData && mBackupData)
1030 {
1031 delete this->mData;
1032 this->mData = mBackupData;
1033 mBackupData = NULL;
1034 }
1035 }
1036
1037 /**
1038 * Commits current changes by deleting backed up data and clearing up the
1039 * backup area. The new data pointer created by #backup() remains active
1040 * and becomes the only managed pointer.
1041 *
1042 * This method is much faster than #commitCopy() (just a single pointer
1043 * assignment operation), but makes the previous data pointer invalid
1044 * (because it is freed). For this reason, this method must not be
1045 * used if it's possible that data managed by this instance is shared with
1046 * some other Shareable instance. See #commitCopy().
1047 */
1048 void commit()
1049 {
1050 if (this->mData && mBackupData)
1051 {
1052 if (!this->mIsShared)
1053 delete mBackupData;
1054 mBackupData = NULL;
1055 this->mIsShared = false;
1056 }
1057 }
1058
1059 /**
1060 * Commits current changes by assigning new data to the previous data
1061 * pointer stored in the backup area using the assignment operator.
1062 * New data is deleted, the backup area is cleared and the previous data
1063 * pointer becomes active and the only managed pointer.
1064 *
1065 * This method is slower than #commit(), but it keeps the previous data
1066 * pointer valid (i.e. new data is copied to the same memory location).
1067 * For that reason it's safe to use this method on instances that share
1068 * managed data with other Shareable instances.
1069 */
1070 void commitCopy()
1071 {
1072 if (this->mData && mBackupData)
1073 {
1074 *mBackupData = *(this->mData);
1075 delete this->mData;
1076 this->mData = mBackupData;
1077 mBackupData = NULL;
1078 }
1079 }
1080
1081 void assignCopy(const D *pData)
1082 {
1083 AssertMsg(this->mData, ("data must not be NULL"));
1084 AssertMsg(pData, ("data to copy must not be NULL"));
1085 if (this->mData && pData)
1086 {
1087 if (!mBackupData)
1088 {
1089 D *pNewData = new D(*pData);
1090 mBackupData = this->mData;
1091 this->mData = pNewData;
1092 }
1093 else
1094 *this->mData = *pData;
1095 }
1096 }
1097
1098 void assignCopy(const Backupable &d)
1099 {
1100 assignCopy(d.mData);
1101 }
1102
1103 bool isBackedUp() const
1104 {
1105 return mBackupData != NULL;
1106 }
1107
1108 D *backedUpData() const
1109 {
1110 return mBackupData;
1111 }
1112
1113protected:
1114
1115 D *mBackupData;
1116};
1117
1118#endif /* !MAIN_INCLUDED_VirtualBoxBase_h */
1119
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