VirtualBox

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

Last change on this file since 61003 was 60977, checked in by vboxsync, 9 years ago

Main/VirtualBoxBase: Add code for collecting information about how many API objects of each component type are currently around and how many have been created ever. While working on this the tiny bug in the event code was found (harmless, as before VirtualBoxBase::BaseFinalRelease was idempotent, but now no longer acceptable)

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