VirtualBox

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

Last change on this file since 76454 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.1 KB
Line 
1/* $Id: VirtualBoxBase.h 69500 2017-10-28 15:14:05Z vboxsync $ */
2/** @file
3 * VirtualBox COM base classes definition
4 */
5
6/*
7 * Copyright (C) 2006-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifndef ____H_VIRTUALBOXBASEIMPL
19#define ____H_VIRTUALBOXBASEIMPL
20
21#include <iprt/cdefs.h>
22#include <iprt/thread.h>
23
24#include <list>
25#include <map>
26
27#include "ObjectState.h"
28
29#include "VBox/com/AutoLock.h"
30#include "VBox/com/string.h"
31#include "VBox/com/Guid.h"
32
33#include "VBox/com/VirtualBox.h"
34
35// avoid including VBox/settings.h and VBox/xml.h; only declare the classes
36namespace xml
37{
38class File;
39}
40
41namespace com
42{
43class ErrorInfo;
44}
45
46using namespace com;
47using namespace util;
48
49class VirtualBox;
50class Machine;
51class Medium;
52class Host;
53typedef std::list<ComObjPtr<Medium> > MediaList;
54typedef std::list<Utf8Str> StringsList;
55
56////////////////////////////////////////////////////////////////////////////////
57//
58// COM helpers
59//
60////////////////////////////////////////////////////////////////////////////////
61
62#if !defined(VBOX_WITH_XPCOM)
63
64/* use a special version of the singleton class factory,
65 * see KB811591 in msdn for more info. */
66
67#undef DECLARE_CLASSFACTORY_SINGLETON
68#define DECLARE_CLASSFACTORY_SINGLETON(obj) DECLARE_CLASSFACTORY_EX(CMyComClassFactorySingleton<obj>)
69
70/**
71 * @todo r=bird: This CMyComClassFactorySingleton stuff is probably obsoleted by
72 * microatl.h? Right?
73 */
74
75template <class T>
76class CMyComClassFactorySingleton : public ATL::CComClassFactory
77{
78public:
79 CMyComClassFactorySingleton() :
80 m_hrCreate(S_OK), m_spObj(NULL)
81 {
82 }
83 virtual ~CMyComClassFactorySingleton()
84 {
85 if (m_spObj)
86 m_spObj->Release();
87 }
88 // IClassFactory
89 STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)
90 {
91 HRESULT hRes = E_POINTER;
92 if (ppvObj != NULL)
93 {
94 *ppvObj = NULL;
95 // no aggregation for singletons
96 AssertReturn(pUnkOuter == NULL, CLASS_E_NOAGGREGATION);
97 if (m_hrCreate == S_OK && m_spObj == NULL)
98 {
99 Lock();
100 __try
101 {
102 // Fix: The following If statement was moved inside the __try statement.
103 // Did another thread arrive here first?
104 if (m_hrCreate == S_OK && m_spObj == NULL)
105 {
106 // lock the module to indicate activity
107 // (necessary for the monitor shutdown thread to correctly
108 // terminate the module in case when CreateInstance() fails)
109 ATL::_pAtlModule->Lock();
110 ATL::CComObjectCached<T> *p;
111 m_hrCreate = ATL::CComObjectCached<T>::CreateInstance(&p);
112 if (SUCCEEDED(m_hrCreate))
113 {
114 m_hrCreate = p->QueryInterface(IID_IUnknown, (void **)&m_spObj);
115 if (FAILED(m_hrCreate))
116 {
117 delete p;
118 }
119 }
120 ATL::_pAtlModule->Unlock();
121 }
122 }
123 __finally
124 {
125 Unlock();
126 }
127 }
128 if (m_hrCreate == S_OK)
129 {
130 hRes = m_spObj->QueryInterface(riid, ppvObj);
131 }
132 else
133 {
134 hRes = m_hrCreate;
135 }
136 }
137 return hRes;
138 }
139 HRESULT m_hrCreate;
140 IUnknown *m_spObj;
141};
142
143#endif /* !defined(VBOX_WITH_XPCOM) */
144
145////////////////////////////////////////////////////////////////////////////////
146//
147// Macros
148//
149////////////////////////////////////////////////////////////////////////////////
150
151/**
152 * Special version of the Assert macro to be used within VirtualBoxBase
153 * subclasses.
154 *
155 * In the debug build, this macro is equivalent to Assert.
156 * In the release build, this macro uses |setError(E_FAIL, ...)| to set the
157 * error info from the asserted expression.
158 *
159 * @see VirtualBoxBase::setError
160 *
161 * @param expr Expression which should be true.
162 */
163#define ComAssert(expr) \
164 do { \
165 if (RT_LIKELY(!!(expr))) \
166 { /* likely */ } \
167 else \
168 { \
169 AssertMsgFailed(("%s\n", #expr)); \
170 setError(E_FAIL, \
171 "Assertion failed: [%s] at '%s' (%d) in %s.\nPlease contact the product vendor!", \
172 #expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
173 } \
174 } while (0)
175
176/**
177 * Special version of the AssertFailed macro to be used within VirtualBoxBase
178 * subclasses.
179 *
180 * In the debug build, this macro is equivalent to AssertFailed.
181 * In the release build, this macro uses |setError(E_FAIL, ...)| to set the
182 * error info from the asserted expression.
183 *
184 * @see VirtualBoxBase::setError
185 *
186 */
187#define ComAssertFailed() \
188 do { \
189 AssertFailed(); \
190 setError(E_FAIL, \
191 "Assertion failed: at '%s' (%d) in %s.\nPlease contact the product vendor!", \
192 __FILE__, __LINE__, __PRETTY_FUNCTION__); \
193 } while (0)
194
195/**
196 * Special version of the AssertMsg macro to be used within VirtualBoxBase
197 * subclasses.
198 *
199 * See ComAssert for more info.
200 *
201 * @param expr Expression which should be true.
202 * @param a printf argument list (in parenthesis).
203 */
204#define ComAssertMsg(expr, a) \
205 do { \
206 if (RT_LIKELY(!!(expr))) \
207 { /* likely */ } \
208 else \
209 { \
210 Utf8StrFmt MyAssertMsg a; /* may throw bad_alloc */ \
211 AssertMsgFailed(("%s\n", MyAssertMsg.c_str())); \
212 setError(E_FAIL, \
213 "Assertion failed: [%s] at '%s' (%d) in %s.\n%s.\nPlease contact the product vendor!", \
214 #expr, __FILE__, __LINE__, __PRETTY_FUNCTION__, MyAssertMsg.c_str()); \
215 } \
216 } while (0)
217
218/**
219 * Special version of the AssertMsgFailed macro to be used within VirtualBoxBase
220 * subclasses.
221 *
222 * See ComAssert for more info.
223 *
224 * @param a printf argument list (in parenthesis).
225 */
226#define ComAssertMsgFailed(a) \
227 do { \
228 Utf8StrFmt MyAssertMsg a; /* may throw bad_alloc */ \
229 AssertMsgFailed(("%s\n", MyAssertMsg.c_str())); \
230 setError(E_FAIL, \
231 "Assertion failed: at '%s' (%d) in %s.\n%s.\nPlease contact the product vendor!", \
232 __FILE__, __LINE__, __PRETTY_FUNCTION__, MyAssertMsg.c_str()); \
233 } while (0)
234
235/**
236 * Special version of the AssertRC macro to be used within VirtualBoxBase
237 * subclasses.
238 *
239 * See ComAssert for more info.
240 *
241 * @param vrc VBox status code.
242 */
243#define ComAssertRC(vrc) ComAssertMsgRC(vrc, ("%Rra", vrc))
244
245/**
246 * Special version of the AssertMsgRC macro to be used within VirtualBoxBase
247 * subclasses.
248 *
249 * See ComAssert for more info.
250 *
251 * @param vrc VBox status code.
252 * @param msg printf argument list (in parenthesis).
253 */
254#define ComAssertMsgRC(vrc, msg) ComAssertMsg(RT_SUCCESS(vrc), msg)
255
256/**
257 * Special version of the AssertComRC macro to be used within VirtualBoxBase
258 * subclasses.
259 *
260 * See ComAssert for more info.
261 *
262 * @param hrc COM result code
263 */
264#define ComAssertComRC(hrc) ComAssertMsg(SUCCEEDED(hrc), ("COM RC=%Rhrc (0x%08X)", (hrc), (hrc)))
265
266
267/** Special version of ComAssert that returns ret if expr fails */
268#define ComAssertRet(expr, ret) \
269 do { ComAssert(expr); if (!(expr)) return (ret); } while (0)
270/** Special version of ComAssertMsg that returns ret if expr fails */
271#define ComAssertMsgRet(expr, a, ret) \
272 do { ComAssertMsg(expr, a); if (!(expr)) return (ret); } while (0)
273/** Special version of ComAssertRC that returns ret if vrc does not succeed */
274#define ComAssertRCRet(vrc, ret) \
275 do { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) return (ret); } while (0)
276/** Special version of ComAssertComRC that returns ret if rc does not succeed */
277#define ComAssertComRCRet(rc, ret) \
278 do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) return (ret); } while (0)
279/** Special version of ComAssertComRC that returns rc if rc does not succeed */
280#define ComAssertComRCRetRC(rc) \
281 do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) return (rc); } while (0)
282/** Special version of ComAssertFailed that returns ret */
283#define ComAssertFailedRet(ret) \
284 do { ComAssertFailed(); return (ret); } while (0)
285/** Special version of ComAssertMsgFailed that returns ret */
286#define ComAssertMsgFailedRet(msg, ret) \
287 do { ComAssertMsgFailed(msg); return (ret); } while (0)
288
289
290/** Special version of ComAssert that returns void if expr fails */
291#define ComAssertRetVoid(expr) \
292 do { ComAssert(expr); if (!(expr)) return; } while (0)
293/** Special version of ComAssertMsg that returns void if expr fails */
294#define ComAssertMsgRetVoid(expr, a) \
295 do { ComAssertMsg(expr, a); if (!(expr)) return; } while (0)
296/** Special version of ComAssertRC that returns void if vrc does not succeed */
297#define ComAssertRCRetVoid(vrc) \
298 do { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) return; } while (0)
299/** Special version of ComAssertComRC that returns void if rc does not succeed */
300#define ComAssertComRCRetVoid(rc) \
301 do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) return; } while (0)
302/** Special version of ComAssertFailed that returns void */
303#define ComAssertFailedRetVoid() \
304 do { ComAssertFailed(); return; } while (0)
305/** Special version of ComAssertMsgFailed that returns void */
306#define ComAssertMsgFailedRetVoid(msg) \
307 do { ComAssertMsgFailed(msg); return; } while (0)
308
309
310/** Special version of ComAssert that evaluates eval and breaks if expr fails */
311#define ComAssertBreak(expr, eval) \
312 if (1) { ComAssert(expr); if (!(expr)) { eval; break; } } else do {} while (0)
313/** Special version of ComAssertMsg that evaluates eval and breaks if expr fails */
314#define ComAssertMsgBreak(expr, a, eval) \
315 if (1) { ComAssertMsg(expr, a); if (!(expr)) { eval; break; } } else do {} while (0)
316/** Special version of ComAssertRC that evaluates eval and breaks if vrc does not succeed */
317#define ComAssertRCBreak(vrc, eval) \
318 if (1) { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) { eval; break; } } else do {} while (0)
319/** Special version of ComAssertFailed that evaluates eval and breaks */
320#define ComAssertFailedBreak(eval) \
321 if (1) { ComAssertFailed(); { eval; break; } } else do {} while (0)
322/** Special version of ComAssertMsgFailed that evaluates eval and breaks */
323#define ComAssertMsgFailedBreak(msg, eval) \
324 if (1) { ComAssertMsgFailed (msg); { eval; break; } } else do {} while (0)
325/** Special version of ComAssertComRC that evaluates eval and breaks if rc does not succeed */
326#define ComAssertComRCBreak(rc, eval) \
327 if (1) { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { eval; break; } } else do {} while (0)
328/** Special version of ComAssertComRC that just breaks if rc does not succeed */
329#define ComAssertComRCBreakRC(rc) \
330 if (1) { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { break; } } else do {} while (0)
331
332
333/** Special version of ComAssert that evaluates eval and throws it if expr fails */
334#define ComAssertThrow(expr, eval) \
335 do { ComAssert(expr); if (!(expr)) { throw (eval); } } while (0)
336/** Special version of ComAssertRC that evaluates eval and throws it if vrc does not succeed */
337#define ComAssertRCThrow(vrc, eval) \
338 do { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) { throw (eval); } } while (0)
339/** Special version of ComAssertComRC that evaluates eval and throws it if rc does not succeed */
340#define ComAssertComRCThrow(rc, eval) \
341 do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { throw (eval); } } while (0)
342/** Special version of ComAssertComRC that just throws rc if rc does not succeed */
343#define ComAssertComRCThrowRC(rc) \
344 do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { throw rc; } } while (0)
345/** Special version of ComAssert that throws eval */
346#define ComAssertFailedThrow(eval) \
347 do { ComAssertFailed(); { throw (eval); } } while (0)
348
349////////////////////////////////////////////////////////////////////////////////
350
351/**
352 * Checks that the pointer argument is not NULL and returns E_INVALIDARG +
353 * extended error info on failure.
354 * @param arg Input pointer-type argument (strings, interface pointers...)
355 */
356#define CheckComArgNotNull(arg) \
357 do { \
358 if (RT_LIKELY((arg) != NULL)) \
359 { /* likely */ }\
360 else \
361 return setError(E_INVALIDARG, tr("Argument %s is NULL"), #arg); \
362 } while (0)
363
364/**
365 * Checks that the pointer argument is a valid pointer or NULL and returns
366 * E_INVALIDARG + extended error info on failure.
367 * @param arg Input pointer-type argument (strings, interface pointers...)
368 */
369#define CheckComArgMaybeNull(arg) \
370 do { \
371 if (RT_LIKELY(RT_VALID_PTR(arg) || (arg) == NULL)) \
372 { /* likely */ }\
373 else \
374 return setError(E_INVALIDARG, tr("Argument %s is an invalid pointer"), #arg); \
375 } while (0)
376
377/**
378 * Checks that the given pointer to an argument is valid and returns
379 * E_POINTER + extended error info otherwise.
380 * @param arg Pointer argument.
381 */
382#define CheckComArgPointerValid(arg) \
383 do { \
384 if (RT_LIKELY(RT_VALID_PTR(arg))) \
385 { /* likely */ }\
386 else \
387 return setError(E_POINTER, \
388 tr("Argument %s points to invalid memory location (%p)"), \
389 #arg, (void *)(arg)); \
390 } while (0)
391
392/**
393 * Checks that safe array argument is not NULL and returns E_INVALIDARG +
394 * extended error info on failure.
395 * @param arg Input safe array argument (strings, interface pointers...)
396 */
397#define CheckComArgSafeArrayNotNull(arg) \
398 do { \
399 if (RT_LIKELY(!ComSafeArrayInIsNull(arg))) \
400 { /* likely */ }\
401 else \
402 return setError(E_INVALIDARG, tr("Argument %s is NULL"), #arg); \
403 } while (0)
404
405/**
406 * Checks that a string input argument is valid (not NULL or obviously invalid
407 * pointer), returning E_INVALIDARG + extended error info if invalid.
408 * @param a_bstrIn Input string argument (IN_BSTR).
409 */
410#define CheckComArgStr(a_bstrIn) \
411 do { \
412 IN_BSTR const bstrInCheck = (a_bstrIn); /* type check */ \
413 if (RT_LIKELY(RT_VALID_PTR(bstrInCheck))) \
414 { /* likely */ }\
415 else \
416 return setError(E_INVALIDARG, tr("Argument %s is an invalid pointer"), #a_bstrIn); \
417 } while (0)
418/**
419 * Checks that the string argument is not a NULL, a invalid pointer or an empty
420 * string, returning E_INVALIDARG + extended error info on failure.
421 * @param a_bstrIn Input string argument (BSTR etc.).
422 */
423#define CheckComArgStrNotEmptyOrNull(a_bstrIn) \
424 do { \
425 IN_BSTR const bstrInCheck = (a_bstrIn); /* type check */ \
426 if (RT_LIKELY(RT_VALID_PTR(bstrInCheck) && *(bstrInCheck) != '\0')) \
427 { /* likely */ }\
428 else \
429 return setError(E_INVALIDARG, tr("Argument %s is empty or an invalid pointer"), #a_bstrIn); \
430 } while (0)
431
432/**
433 * Converts the Guid input argument (string) to a Guid object, returns with
434 * E_INVALIDARG and error message on failure.
435 *
436 * @param a_Arg Argument.
437 * @param a_GuidVar The Guid variable name.
438 */
439#define CheckComArgGuid(a_Arg, a_GuidVar) \
440 do { \
441 Guid tmpGuid(a_Arg); \
442 (a_GuidVar) = tmpGuid; \
443 if (RT_LIKELY((a_GuidVar).isValid())) \
444 { /* likely */ }\
445 else \
446 return setError(E_INVALIDARG, \
447 tr("GUID argument %s is not valid (\"%ls\")"), #a_Arg, Bstr(a_Arg).raw()); \
448 } while (0)
449
450/**
451 * Checks that the given expression (that must involve the argument) is true and
452 * returns E_INVALIDARG + extended error info on failure.
453 * @param arg Argument.
454 * @param expr Expression to evaluate.
455 */
456#define CheckComArgExpr(arg, expr) \
457 do { \
458 if (RT_LIKELY(!!(expr))) \
459 { /* likely */ }\
460 else \
461 return setError(E_INVALIDARG, \
462 tr("Argument %s is invalid (must be %s)"), #arg, #expr); \
463 } while (0)
464
465/**
466 * Checks that the given expression (that must involve the argument) is true and
467 * returns E_INVALIDARG + extended error info on failure. The error message must
468 * be customized.
469 * @param arg Argument.
470 * @param expr Expression to evaluate.
471 * @param msg Parenthesized printf-like expression (must start with a verb,
472 * like "must be one of...", "is not within...").
473 */
474#define CheckComArgExprMsg(arg, expr, msg) \
475 do { \
476 if (RT_LIKELY(!!(expr))) \
477 { /* likely */ }\
478 else \
479 return setError(E_INVALIDARG, tr("Argument %s %s"), \
480 #arg, Utf8StrFmt msg .c_str()); \
481 } while (0)
482
483/**
484 * Checks that the given pointer to an output argument is valid and returns
485 * E_POINTER + extended error info otherwise.
486 * @param arg Pointer argument.
487 */
488#define CheckComArgOutPointerValid(arg) \
489 do { \
490 if (RT_LIKELY(RT_VALID_PTR(arg))) \
491 { /* likely */ }\
492 else \
493 return setError(E_POINTER, \
494 tr("Output argument %s points to invalid memory location (%p)"), \
495 #arg, (void *)(arg)); \
496 } while (0)
497
498/**
499 * Checks that the given pointer to an output safe array argument is valid and
500 * returns E_POINTER + extended error info otherwise.
501 * @param arg Safe array argument.
502 */
503#define CheckComArgOutSafeArrayPointerValid(arg) \
504 do { \
505 if (RT_LIKELY(!ComSafeArrayOutIsNull(arg))) \
506 { /* likely */ }\
507 else \
508 return setError(E_POINTER, \
509 tr("Output argument %s points to invalid memory location (%p)"), \
510 #arg, (void*)(arg)); \
511 } while (0)
512
513/**
514 * Sets the extended error info and returns E_NOTIMPL.
515 */
516#define ReturnComNotImplemented() \
517 do { \
518 return setError(E_NOTIMPL, tr("Method %s is not implemented"), __FUNCTION__); \
519 } while (0)
520
521/**
522 * Declares an empty constructor and destructor for the given class.
523 * This is useful to prevent the compiler from generating the default
524 * ctor and dtor, which in turn allows to use forward class statements
525 * (instead of including their header files) when declaring data members of
526 * non-fundamental types with constructors (which are always called implicitly
527 * by constructors and by the destructor of the class).
528 *
529 * This macro is to be placed within (the public section of) the class
530 * declaration. Its counterpart, DEFINE_EMPTY_CTOR_DTOR, must be placed
531 * somewhere in one of the translation units (usually .cpp source files).
532 *
533 * @param cls class to declare a ctor and dtor for
534 */
535#define DECLARE_EMPTY_CTOR_DTOR(cls) cls(); virtual ~cls();
536
537/**
538 * Defines an empty constructor and destructor for the given class.
539 * See DECLARE_EMPTY_CTOR_DTOR for more info.
540 */
541#define DEFINE_EMPTY_CTOR_DTOR(cls) \
542 cls::cls() { /*empty*/ } \
543 cls::~cls() { /*empty*/ }
544
545/**
546 * A variant of 'throw' that hits a debug breakpoint first to make
547 * finding the actual thrower possible.
548 */
549#ifdef DEBUG
550# define DebugBreakThrow(a) \
551 do { \
552 RTAssertDebugBreak(); \
553 throw (a); \
554 } while (0)
555#else
556# define DebugBreakThrow(a) throw (a)
557#endif
558
559/**
560 * Parent class of VirtualBoxBase which enables translation support (which
561 * Main doesn't have yet, but this provides the tr() function which will one
562 * day provide translations).
563 *
564 * This class sits in between Lockable and VirtualBoxBase only for the one
565 * reason that the USBProxyService wants translation support but is not
566 * implemented as a COM object, which VirtualBoxBase implies.
567 */
568class ATL_NO_VTABLE VirtualBoxTranslatable
569 : public Lockable
570{
571public:
572
573 /**
574 * Placeholder method with which translations can one day be implemented
575 * in Main. This gets called by the tr() function.
576 * @param context
577 * @param pcszSourceText
578 * @param comment
579 * @return
580 */
581 static const char *translate(const char *context,
582 const char *pcszSourceText,
583 const char *comment = 0)
584 {
585 NOREF(context);
586 NOREF(comment);
587 return pcszSourceText;
588 }
589
590 /**
591 * Translates the given text string by calling translate() and passing
592 * the name of the C class as the first argument ("context of
593 * translation"). See VirtualBoxBase::translate() for more info.
594 *
595 * @param pcszSourceText String to translate.
596 * @param aComment Comment to the string to resolve possible
597 * ambiguities (NULL means no comment).
598 *
599 * @return Translated version of the source string in UTF-8 encoding, or
600 * the source string itself if the translation is not found in the
601 * specified context.
602 */
603 inline static const char *tr(const char *pcszSourceText,
604 const char *aComment = NULL)
605 {
606 return VirtualBoxTranslatable::translate(NULL, // getComponentName(), eventually
607 pcszSourceText,
608 aComment);
609 }
610};
611
612////////////////////////////////////////////////////////////////////////////////
613//
614// VirtualBoxBase
615//
616////////////////////////////////////////////////////////////////////////////////
617
618#define VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface) \
619 virtual const IID& getClassIID() const \
620 { \
621 return cls::getStaticClassIID(); \
622 } \
623 static const IID& getStaticClassIID() \
624 { \
625 return COM_IIDOF(iface); \
626 } \
627 virtual const char* getComponentName() const \
628 { \
629 return cls::getStaticComponentName(); \
630 } \
631 static const char* getStaticComponentName() \
632 { \
633 return #cls; \
634 }
635
636/**
637 * VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT:
638 * This macro must be used once in the declaration of any class derived
639 * from VirtualBoxBase. It implements the pure virtual getClassIID() and
640 * getComponentName() methods. If this macro is not present, instances
641 * of a class derived from VirtualBoxBase cannot be instantiated.
642 *
643 * @param cls The class name, e.g. "Class".
644 * @param iface The interface name which this class implements, e.g. "IClass".
645 */
646#ifdef VBOX_WITH_XPCOM
647 #define VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(cls, iface) \
648 VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface)
649#else // !VBOX_WITH_XPCOM
650 #define VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(cls, iface) \
651 VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface) \
652 STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid) \
653 { \
654 const ATL::_ATL_INTMAP_ENTRY* pEntries = cls::_GetEntries(); \
655 Assert(pEntries); \
656 if (!pEntries) \
657 return S_FALSE; \
658 BOOL bSupports = FALSE; \
659 BOOL bISupportErrorInfoFound = FALSE; \
660 while (pEntries->pFunc != NULL && !bSupports) \
661 { \
662 if (!bISupportErrorInfoFound) \
663 bISupportErrorInfoFound = InlineIsEqualGUID(*(pEntries->piid), IID_ISupportErrorInfo); \
664 else \
665 bSupports = InlineIsEqualGUID(*(pEntries->piid), riid); \
666 pEntries++; \
667 } \
668 Assert(bISupportErrorInfoFound); \
669 return bSupports ? S_OK : S_FALSE; \
670 }
671#endif // !VBOX_WITH_XPCOM
672
673/**
674 * VBOX_TWEAK_INTERFACE_ENTRY:
675 * Macro for defining magic interface entries needed for all interfaces
676 * implemented by any subclass of VirtualBoxBase.
677 */
678#ifdef VBOX_WITH_XPCOM
679#define VBOX_TWEAK_INTERFACE_ENTRY(iface)
680#else // !VBOX_WITH_XPCOM
681#define VBOX_TWEAK_INTERFACE_ENTRY(iface) \
682 COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pUnkMarshaler.m_p)
683#endif // !VBOX_WITH_XPCOM
684
685
686/**
687 * Abstract base class for all component classes implementing COM
688 * interfaces of the VirtualBox COM library.
689 *
690 * Declares functionality that should be available in all components.
691 *
692 * The object state logic is documented in ObjectState.h.
693 */
694class ATL_NO_VTABLE VirtualBoxBase
695 : public VirtualBoxTranslatable,
696 public ATL::CComObjectRootEx<ATL::CComMultiThreadModel>
697#if !defined (VBOX_WITH_XPCOM)
698 , public ISupportErrorInfo
699#endif
700{
701protected:
702#ifdef RT_OS_WINDOWS
703 ComPtr<IUnknown> m_pUnkMarshaler;
704#endif
705
706 HRESULT BaseFinalConstruct();
707 void BaseFinalRelease();
708
709public:
710 VirtualBoxBase();
711 virtual ~VirtualBoxBase();
712
713 /**
714 * Uninitialization method.
715 *
716 * Must be called by all final implementations (component classes) when the
717 * last reference to the object is released, before calling the destructor.
718 *
719 * @note Never call this method the AutoCaller scope or after the
720 * ObjectState::addCaller() call not paired by
721 * ObjectState::releaseCaller() because it is a guaranteed deadlock.
722 * See AutoUninitSpan and AutoCaller.h/ObjectState.h for details.
723 */
724 virtual void uninit()
725 { }
726
727 /**
728 */
729 ObjectState &getObjectState()
730 {
731 return mState;
732 }
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 IID& getClassIID() const = 0;
742
743 /**
744 * Pure virtual method for simple run-time type identification without
745 * having to enable C++ RTTI.
746 *
747 * This *must* be implemented by every subclass deriving from VirtualBoxBase;
748 * use the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro to do that most easily.
749 */
750 virtual const char* getComponentName() const = 0;
751
752 /**
753 * Virtual method which determines the locking class to be used for validating
754 * lock order with the standard member lock handle. This method is overridden
755 * in a number of subclasses.
756 */
757 virtual VBoxLockingClass getLockingClass() const
758 {
759 return LOCKCLASS_OTHEROBJECT;
760 }
761
762 virtual RWLockHandle *lockHandle() const;
763
764 static HRESULT handleUnexpectedExceptions(VirtualBoxBase *const aThis, RT_SRC_POS_DECL);
765
766 static HRESULT setErrorInternal(HRESULT aResultCode,
767 const GUID &aIID,
768 const char *aComponent,
769 Utf8Str aText,
770 bool aWarning,
771 bool aLogIt,
772 LONG aResultDetail = 0);
773 static void clearError(void);
774
775 HRESULT setError(HRESULT aResultCode);
776 HRESULT setError(HRESULT aResultCode, const char *pcsz, ...);
777 HRESULT setError(const ErrorInfo &ei);
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
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
805private:
806 /** Object for representing object state */
807 ObjectState mState;
808
809 /** User-level object lock for subclasses */
810 RWLockHandle *mObjectLock;
811
812 /** Slot of this object in the g_aClassFactoryStats array */
813 uint32_t iFactoryStat;
814
815private:
816 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(VirtualBoxBase); /* Shuts up MSC warning C4625. */
817};
818
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
839/**
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
842 * beginning) of the declaration of the class that inherits from
843 * VirtualBoxTranslatable, to make lupdate happy.
844 */
845#define Q_OBJECT
846
847////////////////////////////////////////////////////////////////////////////////
848
849////////////////////////////////////////////////////////////////////////////////
850
851
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
863 Shareable() : mData(NULL), mIsShared(FALSE) {}
864 virtual ~Shareable() { free(); }
865
866 void allocate() { attach(new D); }
867
868 virtual void free() {
869 if (mData) {
870 if (!mIsShared)
871 delete mData;
872 mData = NULL;
873 mIsShared = false;
874 }
875 }
876
877 void attach(D *d) {
878 AssertMsg(d, ("new data must not be NULL"));
879 if (d && mData != d) {
880 if (mData && !mIsShared)
881 delete mData;
882 mData = d;
883 mIsShared = false;
884 }
885 }
886
887 void attach(Shareable &d) {
888 AssertMsg(
889 d.mData == mData || !d.mIsShared,
890 ("new data must not be shared")
891 );
892 if (this != &d && !d.mIsShared) {
893 attach(d.mData);
894 d.mIsShared = true;
895 }
896 }
897
898 void share(D *d) {
899 AssertMsg(d, ("new data must not be NULL"));
900 if (mData != d) {
901 if (mData && !mIsShared)
902 delete mData;
903 mData = d;
904 mIsShared = true;
905 }
906 }
907
908 void share(const Shareable &d) { share(d.mData); }
909
910 void attachCopy(const D *d) {
911 AssertMsg(d, ("data to copy must not be NULL"));
912 if (d)
913 attach(new D(*d));
914 }
915
916 void attachCopy(const Shareable &d) {
917 attachCopy(d.mData);
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 {
932 AssertMsg(mData, ("data must not be NULL"));
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 */
952template<class D>
953class Backupable : public Shareable<D>
954{
955public:
956
957 Backupable() : Shareable<D>(), mBackupData(NULL) {}
958
959 void free()
960 {
961 AssertMsg(this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
962 rollback();
963 Shareable<D>::free();
964 }
965
966 D *detach()
967 {
968 AssertMsg(this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
969 rollback();
970 return Shareable<D>::detach();
971 }
972
973 void share(const Backupable &d)
974 {
975 AssertMsg(!d.isBackedUp(), ("data to share must not be backed up"));
976 if (!d.isBackedUp())
977 Shareable<D>::share(d.mData);
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.
983 *
984 * @deprecated Use backupEx to avoid throwing wild out-of-memory exceptions.
985 */
986 void backup()
987 {
988 AssertMsg(this->mData, ("data must not be NULL"));
989 if (this->mData && !mBackupData)
990 {
991 D *pNewData = new D(*this->mData);
992 mBackupData = this->mData;
993 this->mData = pNewData;
994 }
995 }
996
997 /**
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 /**
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
1080 void assignCopy(const D *pData)
1081 {
1082 AssertMsg(this->mData, ("data must not be NULL"));
1083 AssertMsg(pData, ("data to copy must not be NULL"));
1084 if (this->mData && pData)
1085 {
1086 if (!mBackupData)
1087 {
1088 D *pNewData = new D(*pData);
1089 mBackupData = this->mData;
1090 this->mData = pNewData;
1091 }
1092 else
1093 *this->mData = *pData;
1094 }
1095 }
1096
1097 void assignCopy(const Backupable &d)
1098 {
1099 assignCopy(d.mData);
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
1117#endif // !____H_VIRTUALBOXBASEIMPL
1118
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