VirtualBox

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

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

Apply RT_OVERRIDE/NS_OVERRIDE where required to shut up clang.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.4 KB
RevLine 
[55401]1/* $Id: VirtualBoxBase.h 103977 2024-03-21 02:04:52Z vboxsync $ */
[1]2/** @file
3 * VirtualBox COM base classes definition
4 */
5
6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[1]8 *
[96407]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
[1]26 */
27
[76562]28#ifndef MAIN_INCLUDED_VirtualBoxBase_h
29#define MAIN_INCLUDED_VirtualBoxBase_h
[76487]30#ifndef RT_WITHOUT_PRAGMA_ONCE
31# pragma once
32#endif
[1]33
[16560]34#include <iprt/cdefs.h>
[25288]35#include <iprt/thread.h>
[16560]36
37#include <list>
38#include <map>
39
[51903]40#include "ObjectState.h"
41
[25813]42#include "VBox/com/AutoLock.h"
[30739]43#include "VBox/com/string.h"
44#include "VBox/com/Guid.h"
[1]45
46#include "VBox/com/VirtualBox.h"
47
[91373]48#include "VirtualBoxTranslator.h"
[90828]49
[51903]50// avoid including VBox/settings.h and VBox/xml.h; only declare the classes
[16560]51namespace xml
52{
[30764]53class File;
[16560]54}
55
[38533]56namespace com
57{
58class ErrorInfo;
59}
60
[1]61using namespace com;
[7992]62using namespace util;
[1]63
[30764]64class VirtualBox;
[26044]65class Machine;
66class Medium;
[30764]67class Host;
[42129]68typedef std::list<ComObjPtr<Medium> > MediaList;
69typedef std::list<Utf8Str> StringsList;
[26044]70
[25859]71////////////////////////////////////////////////////////////////////////////////
72//
73// COM helpers
74//
75////////////////////////////////////////////////////////////////////////////////
76
[41187]77#if !defined(VBOX_WITH_XPCOM)
[1]78
[13580]79/* use a special version of the singleton class factory,
80 * see KB811591 in msdn for more info. */
[1]81
82#undef DECLARE_CLASSFACTORY_SINGLETON
83#define DECLARE_CLASSFACTORY_SINGLETON(obj) DECLARE_CLASSFACTORY_EX(CMyComClassFactorySingleton<obj>)
84
[63643]85/**
86 * @todo r=bird: This CMyComClassFactorySingleton stuff is probably obsoleted by
87 * microatl.h? Right?
88 */
89
[1]90template <class T>
[60765]91class CMyComClassFactorySingleton : public ATL::CComClassFactory
[1]92{
93public:
[60765]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 }
[14944]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;
[60765]110 // no aggregation for singletons
111 AssertReturn(pUnkOuter == NULL, CLASS_E_NOAGGREGATION);
112 if (m_hrCreate == S_OK && m_spObj == NULL)
[14944]113 {
[60765]114 Lock();
115 __try
[14944]116 {
[60765]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)
[14944]120 {
[60765]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))
[14944]128 {
[60765]129 m_hrCreate = p->QueryInterface(IID_IUnknown, (void **)&m_spObj);
130 if (FAILED(m_hrCreate))
[14944]131 {
[60765]132 delete p;
[14944]133 }
134 }
[60765]135 ATL::_pAtlModule->Unlock();
[14944]136 }
137 }
[60765]138 __finally
[14944]139 {
[60765]140 Unlock();
[14944]141 }
142 }
[60765]143 if (m_hrCreate == S_OK)
144 {
145 hRes = m_spObj->QueryInterface(riid, ppvObj);
146 }
147 else
148 {
149 hRes = m_hrCreate;
150 }
[14944]151 }
152 return hRes;
153 }
154 HRESULT m_hrCreate;
[60765]155 IUnknown *m_spObj;
[1]156};
157
[41187]158#endif /* !defined(VBOX_WITH_XPCOM) */
[1]159
160////////////////////////////////////////////////////////////////////////////////
[25859]161//
162// Macros
163//
164////////////////////////////////////////////////////////////////////////////////
[1]165
166/**
[6076]167 * Special version of the Assert macro to be used within VirtualBoxBase
[41184]168 * subclasses.
[1]169 *
170 * In the debug build, this macro is equivalent to Assert.
[26186]171 * In the release build, this macro uses |setError(E_FAIL, ...)| to set the
[1]172 * error info from the asserted expression.
173 *
[41184]174 * @see VirtualBoxBase::setError
[1]175 *
176 * @param expr Expression which should be true.
177 */
[55945]178#define ComAssert(expr) \
[1]179 do { \
[55944]180 if (RT_LIKELY(!!(expr))) \
181 { /* likely */ } \
182 else \
[55945]183 { \
184 AssertMsgFailed(("%s\n", #expr)); \
[30716]185 setError(E_FAIL, \
[91503]186 VirtualBoxBase::tr("Assertion failed: [%s] at '%s' (%d) in %s.\nPlease contact the product vendor!"), \
[30716]187 #expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
[55945]188 } \
[1]189 } while (0)
190
191/**
[33524]192 * Special version of the AssertFailed macro to be used within VirtualBoxBase
[41184]193 * subclasses.
[33524]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 *
[41184]199 * @see VirtualBoxBase::setError
[33524]200 *
201 */
[55945]202#define ComAssertFailed() \
[33524]203 do { \
[55945]204 AssertFailed(); \
[33524]205 setError(E_FAIL, \
[91503]206 VirtualBoxBase::tr("Assertion failed: at '%s' (%d) in %s.\nPlease contact the product vendor!"), \
[33524]207 __FILE__, __LINE__, __PRETTY_FUNCTION__); \
208 } while (0)
209
210/**
[6076]211 * Special version of the AssertMsg macro to be used within VirtualBoxBase
[41184]212 * subclasses.
[1]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 */
[55945]219#define ComAssertMsg(expr, a) \
[1]220 do { \
[55944]221 if (RT_LIKELY(!!(expr))) \
222 { /* likely */ } \
223 else \
[55945]224 { \
225 Utf8StrFmt MyAssertMsg a; /* may throw bad_alloc */ \
226 AssertMsgFailed(("%s\n", MyAssertMsg.c_str())); \
[30716]227 setError(E_FAIL, \
[91503]228 VirtualBoxBase::tr("Assertion failed: [%s] at '%s' (%d) in %s.\n%s.\nPlease contact the product vendor!"), \
[55945]229 #expr, __FILE__, __LINE__, __PRETTY_FUNCTION__, MyAssertMsg.c_str()); \
230 } \
[1]231 } while (0)
232
233/**
[47386]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 */
[55945]241#define ComAssertMsgFailed(a) \
[47386]242 do { \
[55945]243 Utf8StrFmt MyAssertMsg a; /* may throw bad_alloc */ \
244 AssertMsgFailed(("%s\n", MyAssertMsg.c_str())); \
[47386]245 setError(E_FAIL, \
[91503]246 VirtualBoxBase::tr("Assertion failed: at '%s' (%d) in %s.\n%s.\nPlease contact the product vendor!"), \
[55945]247 __FILE__, __LINE__, __PRETTY_FUNCTION__, MyAssertMsg.c_str()); \
[47386]248 } while (0)
249
250/**
[6076]251 * Special version of the AssertRC macro to be used within VirtualBoxBase
[41184]252 * subclasses.
[1]253 *
254 * See ComAssert for more info.
255 *
256 * @param vrc VBox status code.
257 */
[55945]258#define ComAssertRC(vrc) ComAssertMsgRC(vrc, ("%Rra", vrc))
[1]259
260/**
[6076]261 * Special version of the AssertMsgRC macro to be used within VirtualBoxBase
[41184]262 * subclasses.
[1]263 *
264 * See ComAssert for more info.
265 *
266 * @param vrc VBox status code.
267 * @param msg printf argument list (in parenthesis).
268 */
[55945]269#define ComAssertMsgRC(vrc, msg) ComAssertMsg(RT_SUCCESS(vrc), msg)
[1]270
271/**
[6076]272 * Special version of the AssertComRC macro to be used within VirtualBoxBase
[41184]273 * subclasses.
[1]274 *
275 * See ComAssert for more info.
276 *
[55945]277 * @param hrc COM result code
[1]278 */
[55945]279#define ComAssertComRC(hrc) ComAssertMsg(SUCCEEDED(hrc), ("COM RC=%Rhrc (0x%08X)", (hrc), (hrc)))
[1]280
281
282/** Special version of ComAssert that returns ret if expr fails */
283#define ComAssertRet(expr, ret) \
[23636]284 do { ComAssert(expr); if (!(expr)) return (ret); } while (0)
[1]285/** Special version of ComAssertMsg that returns ret if expr fails */
286#define ComAssertMsgRet(expr, a, ret) \
[23636]287 do { ComAssertMsg(expr, a); if (!(expr)) return (ret); } while (0)
[1]288/** Special version of ComAssertRC that returns ret if vrc does not succeed */
289#define ComAssertRCRet(vrc, ret) \
[23636]290 do { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) return (ret); } while (0)
[1]291/** Special version of ComAssertComRC that returns ret if rc does not succeed */
292#define ComAssertComRCRet(rc, ret) \
[23636]293 do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) return (ret); } while (0)
[1]294/** Special version of ComAssertComRC that returns rc if rc does not succeed */
295#define ComAssertComRCRetRC(rc) \
[23636]296 do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) return (rc); } while (0)
[47386]297/** Special version of ComAssertFailed that returns ret */
298#define ComAssertFailedRet(ret) \
[41187]299 do { ComAssertFailed(); return (ret); } while (0)
[47386]300/** Special version of ComAssertMsgFailed that returns ret */
301#define ComAssertMsgFailedRet(msg, ret) \
302 do { ComAssertMsgFailed(msg); return (ret); } while (0)
[1]303
304
[47386]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
[14624]325/** Special version of ComAssert that evaluates eval and breaks if expr fails */
[1]326#define ComAssertBreak(expr, eval) \
[23636]327 if (1) { ComAssert(expr); if (!(expr)) { eval; break; } } else do {} while (0)
[14624]328/** Special version of ComAssertMsg that evaluates eval and breaks if expr fails */
[1]329#define ComAssertMsgBreak(expr, a, eval) \
[41187]330 if (1) { ComAssertMsg(expr, a); if (!(expr)) { eval; break; } } else do {} while (0)
[14624]331/** Special version of ComAssertRC that evaluates eval and breaks if vrc does not succeed */
[1]332#define ComAssertRCBreak(vrc, eval) \
[41187]333 if (1) { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) { eval; break; } } else do {} while (0)
[14624]334/** Special version of ComAssertFailed that evaluates eval and breaks */
[1]335#define ComAssertFailedBreak(eval) \
[41187]336 if (1) { ComAssertFailed(); { eval; break; } } else do {} while (0)
[14624]337/** Special version of ComAssertMsgFailed that evaluates eval and breaks */
[1]338#define ComAssertMsgFailedBreak(msg, eval) \
[41187]339 if (1) { ComAssertMsgFailed (msg); { eval; break; } } else do {} while (0)
[14624]340/** Special version of ComAssertComRC that evaluates eval and breaks if rc does not succeed */
[1]341#define ComAssertComRCBreak(rc, eval) \
[41187]342 if (1) { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { eval; break; } } else do {} while (0)
[1]343/** Special version of ComAssertComRC that just breaks if rc does not succeed */
344#define ComAssertComRCBreakRC(rc) \
[41187]345 if (1) { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { break; } } else do {} while (0)
[1]346
[6076]347
[14624]348/** Special version of ComAssert that evaluates eval and throws it if expr fails */
[6076]349#define ComAssertThrow(expr, eval) \
[41187]350 do { ComAssert(expr); if (!(expr)) { throw (eval); } } while (0)
[14624]351/** Special version of ComAssertRC that evaluates eval and throws it if vrc does not succeed */
[6076]352#define ComAssertRCThrow(vrc, eval) \
[41187]353 do { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) { throw (eval); } } while (0)
[14624]354/** Special version of ComAssertComRC that evaluates eval and throws it if rc does not succeed */
[6076]355#define ComAssertComRCThrow(rc, eval) \
[41187]356 do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { throw (eval); } } while (0)
[6076]357/** Special version of ComAssertComRC that just throws rc if rc does not succeed */
358#define ComAssertComRCThrowRC(rc) \
[41187]359 do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { throw rc; } } while (0)
[33524]360/** Special version of ComAssert that throws eval */
361#define ComAssertFailedThrow(eval) \
[41187]362 do { ComAssertFailed(); { throw (eval); } } while (0)
[6076]363
[14588]364////////////////////////////////////////////////////////////////////////////////
[6076]365
[14588]366/**
367 * Checks that the pointer argument is not NULL and returns E_INVALIDARG +
368 * extended error info on failure.
[14624]369 * @param arg Input pointer-type argument (strings, interface pointers...)
[14588]370 */
371#define CheckComArgNotNull(arg) \
372 do { \
[55960]373 if (RT_LIKELY((arg) != NULL)) \
[55944]374 { /* likely */ }\
375 else \
[91312]376 return setError(E_INVALIDARG, VirtualBoxBase::tr("Argument %s is NULL"), #arg); \
[14588]377 } while (0)
378
379/**
[36411]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 { \
[55944]386 if (RT_LIKELY(RT_VALID_PTR(arg) || (arg) == NULL)) \
387 { /* likely */ }\
388 else \
[91312]389 return setError(E_INVALIDARG, \
390 VirtualBoxBase::tr("Argument %s is an invalid pointer"), #arg); \
[36411]391 } while (0)
392
393/**
[51337]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 { \
[55944]400 if (RT_LIKELY(RT_VALID_PTR(arg))) \
401 { /* likely */ }\
402 else \
[51337]403 return setError(E_POINTER, \
[91312]404 VirtualBoxBase::tr("Argument %s points to invalid memory location (%p)"), \
[51337]405 #arg, (void *)(arg)); \
406 } while (0)
407
408/**
[14588]409 * Checks that safe array argument is not NULL and returns E_INVALIDARG +
410 * extended error info on failure.
[14624]411 * @param arg Input safe array argument (strings, interface pointers...)
[14588]412 */
413#define CheckComArgSafeArrayNotNull(arg) \
414 do { \
[55944]415 if (RT_LIKELY(!ComSafeArrayInIsNull(arg))) \
416 { /* likely */ }\
417 else \
[91312]418 return setError(E_INVALIDARG, \
419 VirtualBoxBase::tr("Argument %s is NULL"), #arg); \
[14588]420 } while (0)
421
422/**
[40418]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).
[14588]426 */
[40418]427#define CheckComArgStr(a_bstrIn) \
[14588]428 do { \
[40418]429 IN_BSTR const bstrInCheck = (a_bstrIn); /* type check */ \
[55944]430 if (RT_LIKELY(RT_VALID_PTR(bstrInCheck))) \
431 { /* likely */ }\
432 else \
[91312]433 return setError(E_INVALIDARG, \
434 VirtualBoxBase::tr("Argument %s is an invalid pointer"), #a_bstrIn); \
[14588]435 } while (0)
[40418]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 */ \
[55944]444 if (RT_LIKELY(RT_VALID_PTR(bstrInCheck) && *(bstrInCheck) != '\0')) \
445 { /* likely */ }\
446 else \
[91312]447 return setError(E_INVALIDARG, \
448 VirtualBoxBase::tr("Argument %s is empty or an invalid pointer"), \
449 #a_bstrIn); \
[40418]450 } while (0)
[14588]451
452/**
[34073]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; \
[55944]463 if (RT_LIKELY((a_GuidVar).isValid())) \
464 { /* likely */ }\
465 else \
[34073]466 return setError(E_INVALIDARG, \
[91312]467 VirtualBoxBase::tr("GUID argument %s is not valid (\"%ls\")"), \
468 #a_Arg, Bstr(a_Arg).raw()); \
[34073]469 } while (0)
470
471/**
[14588]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 { \
[55944]479 if (RT_LIKELY(!!(expr))) \
480 { /* likely */ }\
481 else \
[23636]482 return setError(E_INVALIDARG, \
[91312]483 VirtualBoxBase::tr("Argument %s is invalid (must be %s)"), \
484 #arg, #expr); \
[14588]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 { \
[55944]498 if (RT_LIKELY(!!(expr))) \
499 { /* likely */ }\
500 else \
[91312]501 return setError(E_INVALIDARG, VirtualBoxBase::tr("Argument %s %s"), \
[31539]502 #arg, Utf8StrFmt msg .c_str()); \
[14588]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 { \
[55944]512 if (RT_LIKELY(RT_VALID_PTR(arg))) \
513 { /* likely */ }\
514 else \
[23636]515 return setError(E_POINTER, \
[91312]516 VirtualBoxBase::tr("Output argument %s points to invalid memory location (%p)"), \
517 #arg, (void *)(arg)); \
[14588]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 { \
[55944]527 if (RT_LIKELY(!ComSafeArrayOutIsNull(arg))) \
528 { /* likely */ }\
529 else \
[23636]530 return setError(E_POINTER, \
[91312]531 VirtualBoxBase::tr("Output argument %s points to invalid memory location (%p)"), \
[30714]532 #arg, (void*)(arg)); \
[14588]533 } while (0)
534
535/**
[14624]536 * Sets the extended error info and returns E_NOTIMPL.
[14588]537 */
[14715]538#define ReturnComNotImplemented() \
[14588]539 do { \
[91312]540 return setError(E_NOTIMPL, VirtualBoxBase::tr("Method %s is not implemented"), __FUNCTION__); \
[14588]541 } while (0)
542
[1]543/**
[14624]544 * Declares an empty constructor and destructor for the given class.
[1]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 *
[14624]551 * This macro is to be placed within (the public section of) the class
[1]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 */
[57065]557#define DECLARE_EMPTY_CTOR_DTOR(cls) cls(); virtual ~cls();
[1]558
559/**
[14624]560 * Defines an empty constructor and destructor for the given class.
[1]561 * See DECLARE_EMPTY_CTOR_DTOR for more info.
562 */
563#define DEFINE_EMPTY_CTOR_DTOR(cls) \
[29385]564 cls::cls() { /*empty*/ } \
565 cls::~cls() { /*empty*/ }
[1]566
[30739]567/**
[30763]568 * A variant of 'throw' that hits a debug breakpoint first to make
569 * finding the actual thrower possible.
570 */
[30781]571#ifdef DEBUG
[55944]572# define DebugBreakThrow(a) \
[30763]573 do { \
574 RTAssertDebugBreak(); \
575 throw (a); \
[55945]576 } while (0)
[30781]577#else
[55944]578# define DebugBreakThrow(a) throw (a)
[30782]579#endif
[30763]580
[1]581////////////////////////////////////////////////////////////////////////////////
[25859]582//
583// VirtualBoxBase
584//
585////////////////////////////////////////////////////////////////////////////////
[1]586
[90828]587#ifdef VBOX_WITH_MAIN_NLS
588# define DECLARE_TRANSLATE_METHODS(cls) \
[91718]589 static inline const char *tr(const char *aSourceText, \
590 const char *aComment = NULL, \
[92068]591 const size_t aNum = ~(size_t)0) \
[90828]592 { \
[91312]593 return VirtualBoxTranslator::translate(NULL, #cls, aSourceText, aComment, aNum); \
[90828]594 }
595#else
596# define DECLARE_TRANSLATE_METHODS(cls) \
597 static inline const char *tr(const char *aSourceText, \
598 const char *aComment = NULL, \
[92068]599 const size_t aNum = ~(size_t)0) \
[90828]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
[30714]610#define VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface) \
[103977]611 virtual const IID &getClassIID() const RT_OVERRIDE \
[30714]612 { \
613 return cls::getStaticClassIID(); \
614 } \
[103977]615 static const IID &getStaticClassIID() \
[30714]616 { \
617 return COM_IIDOF(iface); \
618 } \
[103977]619 virtual const char *getComponentName() const RT_OVERRIDE \
[30714]620 { \
621 return cls::getStaticComponentName(); \
622 } \
[103977]623 static const char *getStaticComponentName() \
[30714]624 { \
625 return #cls; \
626 }
627
[25859]628/**
[30714]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 *
[65088]635 * @param cls The class name, e.g. "Class".
636 * @param iface The interface name which this class implements, e.g. "IClass".
[25859]637 */
[30714]638#ifdef VBOX_WITH_XPCOM
639 #define VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(cls, iface) \
640 VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface)
[60765]641#else // !VBOX_WITH_XPCOM
[30714]642 #define VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(cls, iface) \
643 VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface) \
[103977]644 STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid) RT_OVERRIDE \
[30714]645 { \
[60765]646 const ATL::_ATL_INTMAP_ENTRY* pEntries = cls::_GetEntries(); \
[30714]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 }
[60765]663#endif // !VBOX_WITH_XPCOM
[25834]664
[13580]665/**
[60765]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/**
[13580]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 *
[51903]684 * The object state logic is documented in ObjectState.h.
[13580]685 */
[25859]686class ATL_NO_VTABLE VirtualBoxBase
[91312]687 : public Lockable
[90828]688 , public ATL::CComObjectRootEx<ATL::CComMultiThreadModel>
[30714]689#if !defined (VBOX_WITH_XPCOM)
690 , public ISupportErrorInfo
691#endif
[1]692{
[35638]693protected:
694#ifdef RT_OS_WINDOWS
[60765]695 ComPtr<IUnknown> m_pUnkMarshaler;
[35638]696#endif
697
[60977]698 HRESULT BaseFinalConstruct();
699 void BaseFinalRelease();
[35638]700
[1]701public:
[90828]702 DECLARE_COMMON_CLASS_METHODS(VirtualBoxBase)
[1]703
704 /**
[33540]705 * Uninitialization method.
[13580]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
[51903]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.
[1]714 */
[30739]715 virtual void uninit()
716 { }
[1]717
718 /**
719 */
[51903]720 ObjectState &getObjectState()
[1]721 {
[51903]722 return mState;
[1]723 }
[6935]724
[1]725 /**
[30714]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.
[1]731 */
[30714]732 virtual const IID& getClassIID() const = 0;
[1]733
734 /**
[30714]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.
[1]740 */
[30714]741 virtual const char* getComponentName() const = 0;
742
743 /**
[33540]744 * Virtual method which determines the locking class to be used for validating
[30714]745 * lock order with the standard member lock handle. This method is overridden
746 * in a number of subclasses.
747 */
[25859]748 virtual VBoxLockingClass getLockingClass() const
[1]749 {
[25859]750 return LOCKCLASS_OTHEROBJECT;
751 }
[1]752
[25859]753 virtual RWLockHandle *lockHandle() const;
[6935]754
[41214]755 static HRESULT handleUnexpectedExceptions(VirtualBoxBase *const aThis, RT_SRC_POS_DECL);
756
[90828]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);
[36451]772 static void clearError(void);
[30714]773
[38533]774 HRESULT setError(HRESULT aResultCode);
[30714]775 HRESULT setError(HRESULT aResultCode, const char *pcsz, ...);
[38533]776 HRESULT setError(const ErrorInfo &ei);
[94703]777 HRESULT setErrorVrcV(int vrc, const char *pcszMsgFmt, va_list va_args);
[55582]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, ...);
[30714]782 HRESULT setWarning(HRESULT aResultCode, const char *pcsz, ...);
783 HRESULT setErrorNoLog(HRESULT aResultCode, const char *pcsz, ...);
784
[36439]785
786 /** Initialize COM for a new thread. */
787 static HRESULT initializeComForThread(void)
788 {
789#ifndef VBOX_WITH_XPCOM
790 HRESULT hrc = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE | COINIT_SPEED_OVER_MEMORY);
791 AssertComRCReturn(hrc, hrc);
792#endif
793 return S_OK;
794 }
795
796 /** Uninitializes COM for a dying thread. */
797 static void uninitializeComForThread(void)
798 {
799#ifndef VBOX_WITH_XPCOM
800 CoUninitialize();
801#endif
802 }
803
804
[1]805private:
[51903]806 /** Object for representing object state */
807 ObjectState mState;
[1]808
809 /** User-level object lock for subclasses */
[61175]810 RWLockHandle *mObjectLock;
[60977]811
[65886]812 /** Slot of this object in the g_aClassFactoryStats array */
[60977]813 uint32_t iFactoryStat;
[63147]814
815private:
816 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(VirtualBoxBase); /* Shuts up MSC warning C4625. */
[1]817};
818
[60977]819/** Structure for counting the currently existing and ever created objects
820 * for each component name. */
821typedef struct CLASSFACTORY_STAT
822{
823 const char *psz;
824 uint64_t current;
825 uint64_t overall;
826} CLASSFACTORY_STAT;
827
828/** Maximum number of component names to deal with. There will be debug
829 * assertions if the value is too low. Since the table is global and its
830 * entries are reasonably small, it's not worth squeezing out the last bit. */
831#define CLASSFACTORYSTATS_MAX 128
832
833/* global variables (defined in VirtualBoxBase.cpp) */
834extern CLASSFACTORY_STAT g_aClassFactoryStats[CLASSFACTORYSTATS_MAX];
835extern RWLockHandle *g_pClassFactoryStatsLock;
836
837extern void APIDumpComponentFactoryStats();
838
[1]839/**
[13580]840 * Dummy macro that is used to shut down Qt's lupdate tool warnings in some
841 * situations. This macro needs to be present inside (better at the very
[91312]842 * beginning) of the declaration of the class that uses translation, to make
843 * lupdate happy.
[1]844 */
845#define Q_OBJECT
846
847////////////////////////////////////////////////////////////////////////////////
848
849////////////////////////////////////////////////////////////////////////////////
850
[6851]851
[1]852/**
853 * Simple template that manages data structure allocation/deallocation
854 * and supports data pointer sharing (the instance that shares the pointer is
855 * not responsible for memory deallocation as opposed to the instance that
856 * owns it).
857 */
858template <class D>
859class Shareable
860{
861public:
862
[41187]863 Shareable() : mData(NULL), mIsShared(FALSE) {}
[63331]864 virtual ~Shareable() { free(); }
[1]865
[23636]866 void allocate() { attach(new D); }
[1]867
868 virtual void free() {
869 if (mData) {
870 if (!mIsShared)
871 delete mData;
872 mData = NULL;
873 mIsShared = false;
874 }
875 }
876
[24989]877 void attach(D *d) {
878 AssertMsg(d, ("new data must not be NULL"));
879 if (d && mData != d) {
[1]880 if (mData && !mIsShared)
881 delete mData;
[24989]882 mData = d;
[1]883 mIsShared = false;
884 }
885 }
886
[24989]887 void attach(Shareable &d) {
[23636]888 AssertMsg(
[24989]889 d.mData == mData || !d.mIsShared,
[1]890 ("new data must not be shared")
891 );
[24989]892 if (this != &d && !d.mIsShared) {
893 attach(d.mData);
894 d.mIsShared = true;
[1]895 }
896 }
897
[24989]898 void share(D *d) {
899 AssertMsg(d, ("new data must not be NULL"));
900 if (mData != d) {
[1]901 if (mData && !mIsShared)
902 delete mData;
[24989]903 mData = d;
[1]904 mIsShared = true;
905 }
906 }
907
[24989]908 void share(const Shareable &d) { share(d.mData); }
[1]909
[24989]910 void attachCopy(const D *d) {
911 AssertMsg(d, ("data to copy must not be NULL"));
912 if (d)
913 attach(new D(*d));
[1]914 }
915
[24989]916 void attachCopy(const Shareable &d) {
917 attachCopy(d.mData);
[1]918 }
919
920 virtual D *detach() {
921 D *d = mData;
922 mData = NULL;
923 mIsShared = false;
924 return d;
925 }
926
927 D *data() const {
928 return mData;
929 }
930
931 D *operator->() const {
[23636]932 AssertMsg(mData, ("data must not be NULL"));
[1]933 return mData;
934 }
935
936 bool isNull() const { return mData == NULL; }
937 bool operator!() const { return isNull(); }
938
939 bool isShared() const { return mIsShared; }
940
941protected:
942
943 D *mData;
944 bool mIsShared;
945};
946
947/**
948 * Simple template that enhances Shareable<> and supports data
949 * backup/rollback/commit (using the copy constructor of the managed data
950 * structure).
951 */
[23636]952template<class D>
953class Backupable : public Shareable<D>
[1]954{
955public:
956
[41187]957 Backupable() : Shareable<D>(), mBackupData(NULL) {}
[1]958
959 void free()
960 {
[23636]961 AssertMsg(this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
[1]962 rollback();
[23636]963 Shareable<D>::free();
[1]964 }
965
966 D *detach()
967 {
[23636]968 AssertMsg(this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
[1]969 rollback();
[23636]970 return Shareable<D>::detach();
[1]971 }
972
[24989]973 void share(const Backupable &d)
[1]974 {
[24989]975 AssertMsg(!d.isBackedUp(), ("data to share must not be backed up"));
976 if (!d.isBackedUp())
977 Shareable<D>::share(d.mData);
[1]978 }
979
980 /**
981 * Stores the current data pointer in the backup area, allocates new data
982 * using the copy constructor on current data and makes new data active.
[40418]983 *
984 * @deprecated Use backupEx to avoid throwing wild out-of-memory exceptions.
[1]985 */
986 void backup()
987 {
[23636]988 AssertMsg(this->mData, ("data must not be NULL"));
[1]989 if (this->mData && !mBackupData)
990 {
[24655]991 D *pNewData = new D(*this->mData);
[1]992 mBackupData = this->mData;
[24654]993 this->mData = pNewData;
[1]994 }
995 }
996
997 /**
[40418]998 * Stores the current data pointer in the backup area, allocates new data
999 * using the copy constructor on current data and makes new data active.
1000 *
1001 * @returns S_OK, E_OUTOFMEMORY or E_FAIL (internal error).
1002 */
1003 HRESULT backupEx()
1004 {
1005 AssertMsgReturn(this->mData, ("data must not be NULL"), E_FAIL);
1006 if (this->mData && !mBackupData)
1007 {
1008 try
1009 {
1010 D *pNewData = new D(*this->mData);
1011 mBackupData = this->mData;
1012 this->mData = pNewData;
1013 }
1014 catch (std::bad_alloc &)
1015 {
1016 return E_OUTOFMEMORY;
1017 }
1018 }
1019 return S_OK;
1020 }
1021
1022 /**
[1]1023 * Deletes new data created by #backup() and restores previous data pointer
1024 * stored in the backup area, making it active again.
1025 */
1026 void rollback()
1027 {
1028 if (this->mData && mBackupData)
1029 {
1030 delete this->mData;
1031 this->mData = mBackupData;
1032 mBackupData = NULL;
1033 }
1034 }
1035
1036 /**
1037 * Commits current changes by deleting backed up data and clearing up the
1038 * backup area. The new data pointer created by #backup() remains active
1039 * and becomes the only managed pointer.
1040 *
1041 * This method is much faster than #commitCopy() (just a single pointer
1042 * assignment operation), but makes the previous data pointer invalid
1043 * (because it is freed). For this reason, this method must not be
1044 * used if it's possible that data managed by this instance is shared with
1045 * some other Shareable instance. See #commitCopy().
1046 */
1047 void commit()
1048 {
1049 if (this->mData && mBackupData)
1050 {
1051 if (!this->mIsShared)
1052 delete mBackupData;
1053 mBackupData = NULL;
1054 this->mIsShared = false;
1055 }
1056 }
1057
1058 /**
1059 * Commits current changes by assigning new data to the previous data
1060 * pointer stored in the backup area using the assignment operator.
1061 * New data is deleted, the backup area is cleared and the previous data
1062 * pointer becomes active and the only managed pointer.
1063 *
1064 * This method is slower than #commit(), but it keeps the previous data
1065 * pointer valid (i.e. new data is copied to the same memory location).
1066 * For that reason it's safe to use this method on instances that share
1067 * managed data with other Shareable instances.
1068 */
1069 void commitCopy()
1070 {
1071 if (this->mData && mBackupData)
1072 {
1073 *mBackupData = *(this->mData);
1074 delete this->mData;
1075 this->mData = mBackupData;
1076 mBackupData = NULL;
1077 }
1078 }
1079
[24989]1080 void assignCopy(const D *pData)
[1]1081 {
[23636]1082 AssertMsg(this->mData, ("data must not be NULL"));
[24989]1083 AssertMsg(pData, ("data to copy must not be NULL"));
1084 if (this->mData && pData)
[1]1085 {
1086 if (!mBackupData)
1087 {
[24989]1088 D *pNewData = new D(*pData);
[1]1089 mBackupData = this->mData;
[24654]1090 this->mData = pNewData;
[1]1091 }
1092 else
[24989]1093 *this->mData = *pData;
[1]1094 }
1095 }
1096
[24989]1097 void assignCopy(const Backupable &d)
[1]1098 {
[24989]1099 assignCopy(d.mData);
[1]1100 }
1101
1102 bool isBackedUp() const
1103 {
1104 return mBackupData != NULL;
1105 }
1106
1107 D *backedUpData() const
1108 {
1109 return mBackupData;
1110 }
1111
1112protected:
1113
1114 D *mBackupData;
1115};
1116
[76562]1117#endif /* !MAIN_INCLUDED_VirtualBoxBase_h */
[23257]1118
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use