VirtualBox

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

Last change on this file since 39493 was 38533, checked in by vboxsync, 13 years ago

Main/ErrorInfo: allow to set standard errors without text and error setting
from an existing com::ErrorInfo object

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.2 KB
Line 
1/** @file
2 * VirtualBox COM base classes definition
3 */
4
5/*
6 * Copyright (C) 2006-2010 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16
17#ifndef ____H_VIRTUALBOXBASEIMPL
18#define ____H_VIRTUALBOXBASEIMPL
19
20#include <iprt/cdefs.h>
21#include <iprt/thread.h>
22
23#include <list>
24#include <map>
25
26#include "VBox/com/AutoLock.h"
27#include "VBox/com/string.h"
28#include "VBox/com/Guid.h"
29
30#include "VBox/com/VirtualBox.h"
31
32// avoid including VBox/settings.h and VBox/xml.h;
33// only declare the classes
34namespace xml
35{
36class File;
37}
38
39namespace com
40{
41class ErrorInfo;
42}
43
44using namespace com;
45using namespace util;
46
47class AutoInitSpan;
48class AutoUninitSpan;
49
50class VirtualBox;
51class Machine;
52class Medium;
53class Host;
54typedef std::list< ComObjPtr<Medium> > MediaList;
55typedef std::list<Guid> GuidList;
56
57////////////////////////////////////////////////////////////////////////////////
58//
59// COM helpers
60//
61////////////////////////////////////////////////////////////////////////////////
62
63#if !defined (VBOX_WITH_XPCOM)
64
65#include <atlcom.h>
66
67/* use a special version of the singleton class factory,
68 * see KB811591 in msdn for more info. */
69
70#undef DECLARE_CLASSFACTORY_SINGLETON
71#define DECLARE_CLASSFACTORY_SINGLETON(obj) DECLARE_CLASSFACTORY_EX(CMyComClassFactorySingleton<obj>)
72
73template <class T>
74class CMyComClassFactorySingleton : public CComClassFactory
75{
76public:
77 CMyComClassFactorySingleton() : m_hrCreate(S_OK){}
78 virtual ~CMyComClassFactorySingleton(){}
79 // IClassFactory
80 STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)
81 {
82 HRESULT hRes = E_POINTER;
83 if (ppvObj != NULL)
84 {
85 *ppvObj = NULL;
86 // Aggregation is not supported in singleton objects.
87 ATLASSERT(pUnkOuter == NULL);
88 if (pUnkOuter != NULL)
89 hRes = CLASS_E_NOAGGREGATION;
90 else
91 {
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 _pAtlModule->Lock();
105 CComObjectCached<T> *p;
106 m_hrCreate = 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 _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 }
133 return hRes;
134 }
135 HRESULT m_hrCreate;
136 CComPtr<IUnknown> m_spObj;
137};
138
139#endif /* !defined (VBOX_WITH_XPCOM) */
140
141////////////////////////////////////////////////////////////////////////////////
142//
143// Macros
144//
145////////////////////////////////////////////////////////////////////////////////
146
147/**
148 * Special version of the Assert macro to be used within VirtualBoxBase
149 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
150 *
151 * In the debug build, this macro is equivalent to Assert.
152 * In the release build, this macro uses |setError(E_FAIL, ...)| to set the
153 * error info from the asserted expression.
154 *
155 * @see VirtualBoxSupportErrorInfoImpl::setError
156 *
157 * @param expr Expression which should be true.
158 */
159#if defined (DEBUG)
160#define ComAssert(expr) Assert(expr)
161#else
162#define ComAssert(expr) \
163 do { \
164 if (RT_UNLIKELY(!(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 } while (0)
169#endif
170
171/**
172 * Special version of the AssertFailed macro to be used within VirtualBoxBase
173 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
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 VirtualBoxSupportErrorInfoImpl::setError
180 *
181 */
182#if defined (DEBUG)
183#define ComAssertFailed() AssertFailed()
184#else
185#define ComAssertFailed() \
186 do { \
187 setError(E_FAIL, \
188 "Assertion failed: at '%s' (%d) in %s.\nPlease contact the product vendor!", \
189 __FILE__, __LINE__, __PRETTY_FUNCTION__); \
190 } while (0)
191#endif
192
193/**
194 * Special version of the AssertMsg macro to be used within VirtualBoxBase
195 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
196 *
197 * See ComAssert for more info.
198 *
199 * @param expr Expression which should be true.
200 * @param a printf argument list (in parenthesis).
201 */
202#if defined (DEBUG)
203#define ComAssertMsg(expr, a) AssertMsg(expr, a)
204#else
205#define ComAssertMsg(expr, a) \
206 do { \
207 if (RT_UNLIKELY(!(expr))) \
208 setError(E_FAIL, \
209 "Assertion failed: [%s] at '%s' (%d) in %s.\n%s.\nPlease contact the product vendor!", \
210 #expr, __FILE__, __LINE__, __PRETTY_FUNCTION__, Utf8StrFmt a .c_str()); \
211 } while (0)
212#endif
213
214/**
215 * Special version of the AssertRC macro to be used within VirtualBoxBase
216 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
217 *
218 * See ComAssert for more info.
219 *
220 * @param vrc VBox status code.
221 */
222#if defined (DEBUG)
223#define ComAssertRC(vrc) AssertRC(vrc)
224#else
225#define ComAssertRC(vrc) ComAssertMsgRC(vrc, ("%Rra", vrc))
226#endif
227
228/**
229 * Special version of the AssertMsgRC macro to be used within VirtualBoxBase
230 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
231 *
232 * See ComAssert for more info.
233 *
234 * @param vrc VBox status code.
235 * @param msg printf argument list (in parenthesis).
236 */
237#if defined (DEBUG)
238#define ComAssertMsgRC(vrc, msg) AssertMsgRC(vrc, msg)
239#else
240#define ComAssertMsgRC(vrc, msg) ComAssertMsg(RT_SUCCESS(vrc), msg)
241#endif
242
243/**
244 * Special version of the AssertComRC macro to be used within VirtualBoxBase
245 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
246 *
247 * See ComAssert for more info.
248 *
249 * @param rc COM result code
250 */
251#if defined (DEBUG)
252#define ComAssertComRC(rc) AssertComRC(rc)
253#else
254#define ComAssertComRC(rc) ComAssertMsg(SUCCEEDED(rc), ("COM RC = %Rhrc (0x%08X)", (rc), (rc)))
255#endif
256
257
258/** Special version of ComAssert that returns ret if expr fails */
259#define ComAssertRet(expr, ret) \
260 do { ComAssert(expr); if (!(expr)) return (ret); } while (0)
261/** Special version of ComAssertMsg that returns ret if expr fails */
262#define ComAssertMsgRet(expr, a, ret) \
263 do { ComAssertMsg(expr, a); if (!(expr)) return (ret); } while (0)
264/** Special version of ComAssertRC that returns ret if vrc does not succeed */
265#define ComAssertRCRet(vrc, ret) \
266 do { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) return (ret); } while (0)
267/** Special version of ComAssertComRC that returns ret if rc does not succeed */
268#define ComAssertComRCRet(rc, ret) \
269 do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) return (ret); } while (0)
270/** Special version of ComAssertComRC that returns rc if rc does not succeed */
271#define ComAssertComRCRetRC(rc) \
272 do { ComAssertComRC(rc); if (!SUCCEEDED(rc)) return (rc); } while (0)
273/** Special version of ComAssert that returns ret */
274#define ComAssertFailedRet(ret) \
275 if (1) { ComAssertFailed(); { return (ret); } } else do {} while (0)
276
277
278/** Special version of ComAssert that evaluates eval and breaks if expr fails */
279#define ComAssertBreak(expr, eval) \
280 if (1) { ComAssert(expr); if (!(expr)) { eval; break; } } else do {} while (0)
281/** Special version of ComAssertMsg that evaluates eval and breaks if expr fails */
282#define ComAssertMsgBreak(expr, a, eval) \
283 if (1) { ComAssertMsg(expr, a); if (!(expr)) { eval; break; } } else do {} while (0)
284/** Special version of ComAssertRC that evaluates eval and breaks if vrc does not succeed */
285#define ComAssertRCBreak(vrc, eval) \
286 if (1) { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) { eval; break; } } else do {} while (0)
287/** Special version of ComAssertFailed that evaluates eval and breaks */
288#define ComAssertFailedBreak(eval) \
289 if (1) { ComAssertFailed(); { eval; break; } } else do {} while (0)
290/** Special version of ComAssertMsgFailed that evaluates eval and breaks */
291#define ComAssertMsgFailedBreak(msg, eval) \
292 if (1) { ComAssertMsgFailed (msg); { eval; break; } } else do {} while (0)
293/** Special version of ComAssertComRC that evaluates eval and breaks if rc does not succeed */
294#define ComAssertComRCBreak(rc, eval) \
295 if (1) { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { eval; break; } } else do {} while (0)
296/** Special version of ComAssertComRC that just breaks if rc does not succeed */
297#define ComAssertComRCBreakRC(rc) \
298 if (1) { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { break; } } else do {} while (0)
299
300
301/** Special version of ComAssert that evaluates eval and throws it if expr fails */
302#define ComAssertThrow(expr, eval) \
303 if (1) { ComAssert(expr); if (!(expr)) { throw (eval); } } else do {} while (0)
304/** Special version of ComAssertRC that evaluates eval and throws it if vrc does not succeed */
305#define ComAssertRCThrow(vrc, eval) \
306 if (1) { ComAssertRC(vrc); if (!RT_SUCCESS(vrc)) { throw (eval); } } else do {} while (0)
307/** Special version of ComAssertComRC that evaluates eval and throws it if rc does not succeed */
308#define ComAssertComRCThrow(rc, eval) \
309 if (1) { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { throw (eval); } } else do {} while (0)
310/** Special version of ComAssertComRC that just throws rc if rc does not succeed */
311#define ComAssertComRCThrowRC(rc) \
312 if (1) { ComAssertComRC(rc); if (!SUCCEEDED(rc)) { throw rc; } } else do {} while (0)
313/** Special version of ComAssert that throws eval */
314#define ComAssertFailedThrow(eval) \
315 if (1) { ComAssertFailed(); { throw (eval); } } else do {} while (0)
316
317////////////////////////////////////////////////////////////////////////////////
318
319/**
320 * Checks that the pointer argument is not NULL and returns E_INVALIDARG +
321 * extended error info on failure.
322 * @param arg Input pointer-type argument (strings, interface pointers...)
323 */
324#define CheckComArgNotNull(arg) \
325 do { \
326 if (RT_UNLIKELY((arg) == NULL)) \
327 return setError(E_INVALIDARG, tr("Argument %s is NULL"), #arg); \
328 } while (0)
329
330/**
331 * Checks that the pointer argument is a valid pointer or NULL and returns
332 * E_INVALIDARG + extended error info on failure.
333 * @param arg Input pointer-type argument (strings, interface pointers...)
334 */
335#define CheckComArgMaybeNull(arg) \
336 do { \
337 if (RT_UNLIKELY(!RT_VALID_PTR(arg) && (arg) != NULL)) \
338 return setError(E_INVALIDARG, tr("Argument %s is an invalid pointer"), #arg); \
339 } while (0)
340
341/**
342 * Checks that safe array argument is not NULL and returns E_INVALIDARG +
343 * extended error info on failure.
344 * @param arg Input safe array argument (strings, interface pointers...)
345 */
346#define CheckComArgSafeArrayNotNull(arg) \
347 do { \
348 if (RT_UNLIKELY(ComSafeArrayInIsNull(arg))) \
349 return setError(E_INVALIDARG, tr("Argument %s is NULL"), #arg); \
350 } while (0)
351
352/**
353 * Checks that the string argument is not a NULL or empty string and returns
354 * E_INVALIDARG + extended error info on failure.
355 * @param arg Input string argument (BSTR etc.).
356 */
357#define CheckComArgStrNotEmptyOrNull(arg) \
358 do { \
359 if (RT_UNLIKELY((arg) == NULL || *(arg) == '\0')) \
360 return setError(E_INVALIDARG, \
361 tr("Argument %s is empty or NULL"), #arg); \
362 } while (0)
363
364/**
365 * Converts the Guid input argument (string) to a Guid object, returns with
366 * E_INVALIDARG and error message on failure.
367 *
368 * @param a_Arg Argument.
369 * @param a_GuidVar The Guid variable name.
370 */
371#define CheckComArgGuid(a_Arg, a_GuidVar) \
372 do { \
373 Guid tmpGuid(a_Arg); \
374 (a_GuidVar) = tmpGuid; \
375 if (RT_UNLIKELY((a_GuidVar).isEmpty())) \
376 return setError(E_INVALIDARG, \
377 tr("GUID argument %s is not valid (\"%ls\")"), #a_Arg, Bstr(a_Arg).raw()); \
378 } while (0)
379
380/**
381 * Checks that the given expression (that must involve the argument) is true and
382 * returns E_INVALIDARG + extended error info on failure.
383 * @param arg Argument.
384 * @param expr Expression to evaluate.
385 */
386#define CheckComArgExpr(arg, expr) \
387 do { \
388 if (RT_UNLIKELY(!(expr))) \
389 return setError(E_INVALIDARG, \
390 tr("Argument %s is invalid (must be %s)"), #arg, #expr); \
391 } while (0)
392
393/**
394 * Checks that the given expression (that must involve the argument) is true and
395 * returns E_INVALIDARG + extended error info on failure. The error message must
396 * be customized.
397 * @param arg Argument.
398 * @param expr Expression to evaluate.
399 * @param msg Parenthesized printf-like expression (must start with a verb,
400 * like "must be one of...", "is not within...").
401 */
402#define CheckComArgExprMsg(arg, expr, msg) \
403 do { \
404 if (RT_UNLIKELY(!(expr))) \
405 return setError(E_INVALIDARG, tr ("Argument %s %s"), \
406 #arg, Utf8StrFmt msg .c_str()); \
407 } while (0)
408
409/**
410 * Checks that the given pointer to an output argument is valid and returns
411 * E_POINTER + extended error info otherwise.
412 * @param arg Pointer argument.
413 */
414#define CheckComArgOutPointerValid(arg) \
415 do { \
416 if (RT_UNLIKELY(!VALID_PTR(arg))) \
417 return setError(E_POINTER, \
418 tr("Output argument %s points to invalid memory location (%p)"), \
419 #arg, (void *) (arg)); \
420 } while (0)
421
422/**
423 * Checks that the given pointer to an output safe array argument is valid and
424 * returns E_POINTER + extended error info otherwise.
425 * @param arg Safe array argument.
426 */
427#define CheckComArgOutSafeArrayPointerValid(arg) \
428 do { \
429 if (RT_UNLIKELY(ComSafeArrayOutIsNull(arg))) \
430 return setError(E_POINTER, \
431 tr("Output argument %s points to invalid memory location (%p)"), \
432 #arg, (void*)(arg)); \
433 } while (0)
434
435/**
436 * Sets the extended error info and returns E_NOTIMPL.
437 */
438#define ReturnComNotImplemented() \
439 do { \
440 return setError(E_NOTIMPL, tr("Method %s is not implemented"), __FUNCTION__); \
441 } while (0)
442
443/**
444 * Declares an empty constructor and destructor for the given class.
445 * This is useful to prevent the compiler from generating the default
446 * ctor and dtor, which in turn allows to use forward class statements
447 * (instead of including their header files) when declaring data members of
448 * non-fundamental types with constructors (which are always called implicitly
449 * by constructors and by the destructor of the class).
450 *
451 * This macro is to be placed within (the public section of) the class
452 * declaration. Its counterpart, DEFINE_EMPTY_CTOR_DTOR, must be placed
453 * somewhere in one of the translation units (usually .cpp source files).
454 *
455 * @param cls class to declare a ctor and dtor for
456 */
457#define DECLARE_EMPTY_CTOR_DTOR(cls) cls(); ~cls();
458
459/**
460 * Defines an empty constructor and destructor for the given class.
461 * See DECLARE_EMPTY_CTOR_DTOR for more info.
462 */
463#define DEFINE_EMPTY_CTOR_DTOR(cls) \
464 cls::cls() { /*empty*/ } \
465 cls::~cls() { /*empty*/ }
466
467/**
468 * A variant of 'throw' that hits a debug breakpoint first to make
469 * finding the actual thrower possible.
470 */
471#ifdef DEBUG
472#define DebugBreakThrow(a) \
473 do { \
474 RTAssertDebugBreak(); \
475 throw (a); \
476} while (0)
477#else
478#define DebugBreakThrow(a) throw (a)
479#endif
480
481/**
482 * Parent class of VirtualBoxBase which enables translation support (which
483 * Main doesn't have yet, but this provides the tr() function which will one
484 * day provide translations).
485 *
486 * This class sits in between Lockable and VirtualBoxBase only for the one
487 * reason that the USBProxyService wants translation support but is not
488 * implemented as a COM object, which VirtualBoxBase implies.
489 */
490class ATL_NO_VTABLE VirtualBoxTranslatable
491 : public Lockable
492{
493public:
494
495 /**
496 * Placeholder method with which translations can one day be implemented
497 * in Main. This gets called by the tr() function.
498 * @param context
499 * @param pcszSourceText
500 * @param comment
501 * @return
502 */
503 static const char *translate(const char *context,
504 const char *pcszSourceText,
505 const char *comment = 0)
506 {
507 NOREF(context);
508 NOREF(comment);
509 return pcszSourceText;
510 }
511
512 /**
513 * Translates the given text string by calling translate() and passing
514 * the name of the C class as the first argument ("context of
515 * translation"). See VirtualBoxBase::translate() for more info.
516 *
517 * @param aSourceText String to translate.
518 * @param aComment Comment to the string to resolve possible
519 * ambiguities (NULL means no comment).
520 *
521 * @return Translated version of the source string in UTF-8 encoding, or
522 * the source string itself if the translation is not found in the
523 * specified context.
524 */
525 inline static const char *tr(const char *pcszSourceText,
526 const char *aComment = NULL)
527 {
528 return VirtualBoxTranslatable::translate(NULL, // getComponentName(), eventually
529 pcszSourceText,
530 aComment);
531 }
532};
533
534////////////////////////////////////////////////////////////////////////////////
535//
536// VirtualBoxBase
537//
538////////////////////////////////////////////////////////////////////////////////
539
540#define VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface) \
541 virtual const IID& getClassIID() const \
542 { \
543 return cls::getStaticClassIID(); \
544 } \
545 static const IID& getStaticClassIID() \
546 { \
547 return COM_IIDOF(iface); \
548 } \
549 virtual const char* getComponentName() const \
550 { \
551 return cls::getStaticComponentName(); \
552 } \
553 static const char* getStaticComponentName() \
554 { \
555 return #cls; \
556 }
557
558/**
559 * VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT:
560 * This macro must be used once in the declaration of any class derived
561 * from VirtualBoxBase. It implements the pure virtual getClassIID() and
562 * getComponentName() methods. If this macro is not present, instances
563 * of a class derived from VirtualBoxBase cannot be instantiated.
564 *
565 * @param X The class name, e.g. "Class".
566 * @param IX The interface name which this class implements, e.g. "IClass".
567 */
568#ifdef VBOX_WITH_XPCOM
569 #define VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(cls, iface) \
570 VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface)
571#else // #ifdef VBOX_WITH_XPCOM
572 #define VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT(cls, iface) \
573 VIRTUALBOXBASE_ADD_VIRTUAL_COMPONENT_METHODS(cls, iface) \
574 STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid) \
575 { \
576 const _ATL_INTMAP_ENTRY* pEntries = cls::_GetEntries(); \
577 Assert(pEntries); \
578 if (!pEntries) \
579 return S_FALSE; \
580 BOOL bSupports = FALSE; \
581 BOOL bISupportErrorInfoFound = FALSE; \
582 while (pEntries->pFunc != NULL && !bSupports) \
583 { \
584 if (!bISupportErrorInfoFound) \
585 bISupportErrorInfoFound = InlineIsEqualGUID(*(pEntries->piid), IID_ISupportErrorInfo); \
586 else \
587 bSupports = InlineIsEqualGUID(*(pEntries->piid), riid); \
588 pEntries++; \
589 } \
590 Assert(bISupportErrorInfoFound); \
591 return bSupports ? S_OK : S_FALSE; \
592 }
593#endif // #ifdef VBOX_WITH_XPCOM
594
595/**
596 * Abstract base class for all component classes implementing COM
597 * interfaces of the VirtualBox COM library.
598 *
599 * Declares functionality that should be available in all components.
600 *
601 * Among the basic functionality implemented by this class is the primary object
602 * state that indicates if the object is ready to serve the calls, and if not,
603 * what stage it is currently at. Here is the primary state diagram:
604 *
605 * +-------------------------------------------------------+
606 * | |
607 * | (InitFailed) -----------------------+ |
608 * | ^ | |
609 * v | v |
610 * [*] ---> NotReady ----> (InInit) -----> Ready -----> (InUninit) ----+
611 * ^ |
612 * | v
613 * | Limited
614 * | |
615 * +-------+
616 *
617 * The object is fully operational only when its state is Ready. The Limited
618 * state means that only some vital part of the object is operational, and it
619 * requires some sort of reinitialization to become fully operational. The
620 * NotReady state means the object is basically dead: it either was not yet
621 * initialized after creation at all, or was uninitialized and is waiting to be
622 * destroyed when the last reference to it is released. All other states are
623 * transitional.
624 *
625 * The NotReady->InInit->Ready, NotReady->InInit->Limited and
626 * NotReady->InInit->InitFailed transition is done by the AutoInitSpan smart
627 * class.
628 *
629 * The Limited->InInit->Ready, Limited->InInit->Limited and
630 * Limited->InInit->InitFailed transition is done by the AutoReinitSpan smart
631 * class.
632 *
633 * The Ready->InUninit->NotReady and InitFailed->InUninit->NotReady
634 * transitions are done by the AutoUninitSpan smart class.
635 *
636 * In order to maintain the primary state integrity and declared functionality
637 * all subclasses must:
638 *
639 * 1) Use the above Auto*Span classes to perform state transitions. See the
640 * individual class descriptions for details.
641 *
642 * 2) All public methods of subclasses (i.e. all methods that can be called
643 * directly, not only from within other methods of the subclass) must have a
644 * standard prolog as described in the AutoCaller and AutoLimitedCaller
645 * documentation. Alternatively, they must use addCaller()/releaseCaller()
646 * directly (and therefore have both the prolog and the epilog), but this is
647 * not recommended.
648 */
649class ATL_NO_VTABLE VirtualBoxBase
650 : public VirtualBoxTranslatable,
651 public CComObjectRootEx<CComMultiThreadModel>
652#if !defined (VBOX_WITH_XPCOM)
653 , public ISupportErrorInfo
654#endif
655{
656protected:
657#ifdef RT_OS_WINDOWS
658 CComPtr <IUnknown> m_pUnkMarshaler;
659#endif
660
661 HRESULT BaseFinalConstruct()
662 {
663#ifdef RT_OS_WINDOWS
664 return CoCreateFreeThreadedMarshaler(this, //GetControllingUnknown(),
665 &m_pUnkMarshaler.p);
666#else
667 return S_OK;
668#endif
669 }
670
671 void BaseFinalRelease()
672 {
673#ifdef RT_OS_WINDOWS
674 m_pUnkMarshaler.Release();
675#endif
676 }
677
678
679public:
680 enum State { NotReady, Ready, InInit, InUninit, InitFailed, Limited };
681
682 VirtualBoxBase();
683 virtual ~VirtualBoxBase();
684
685 /**
686 * Uninitialization method.
687 *
688 * Must be called by all final implementations (component classes) when the
689 * last reference to the object is released, before calling the destructor.
690 *
691 * @note Never call this method the AutoCaller scope or after the
692 * #addCaller() call not paired by #releaseCaller() because it is a
693 * guaranteed deadlock. See AutoUninitSpan for details.
694 */
695 virtual void uninit()
696 { }
697
698 virtual HRESULT addCaller(State *aState = NULL,
699 bool aLimited = false);
700 virtual void releaseCaller();
701
702 /**
703 * Adds a limited caller. This method is equivalent to doing
704 * <tt>addCaller (aState, true)</tt>, but it is preferred because provides
705 * better self-descriptiveness. See #addCaller() for more info.
706 */
707 HRESULT addLimitedCaller(State *aState = NULL)
708 {
709 return addCaller(aState, true /* aLimited */);
710 }
711
712 /**
713 * Pure virtual method for simple run-time type identification without
714 * having to enable C++ RTTI.
715 *
716 * This *must* be implemented by every subclass deriving from VirtualBoxBase;
717 * use the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro to do that most easily.
718 */
719 virtual const IID& getClassIID() const = 0;
720
721 /**
722 * Pure virtual method for simple run-time type identification without
723 * having to enable C++ RTTI.
724 *
725 * This *must* be implemented by every subclass deriving from VirtualBoxBase;
726 * use the VIRTUALBOXBASE_ADD_ERRORINFO_SUPPORT macro to do that most easily.
727 */
728 virtual const char* getComponentName() const = 0;
729
730 /**
731 * Virtual method which determines the locking class to be used for validating
732 * lock order with the standard member lock handle. This method is overridden
733 * in a number of subclasses.
734 */
735 virtual VBoxLockingClass getLockingClass() const
736 {
737 return LOCKCLASS_OTHEROBJECT;
738 }
739
740 virtual RWLockHandle *lockHandle() const;
741
742 /**
743 * Returns a lock handle used to protect the primary state fields (used by
744 * #addCaller(), AutoInitSpan, AutoUninitSpan, etc.). Only intended to be
745 * used for similar purposes in subclasses. WARNING: NO any other locks may
746 * be requested while holding this lock!
747 */
748 WriteLockHandle *stateLockHandle() { return &mStateLock; }
749
750 static HRESULT setErrorInternal(HRESULT aResultCode,
751 const GUID &aIID,
752 const char *aComponent,
753 Utf8Str aText,
754 bool aWarning,
755 bool aLogIt);
756 static void clearError(void);
757
758 HRESULT setError(HRESULT aResultCode);
759 HRESULT setError(HRESULT aResultCode, const char *pcsz, ...);
760 HRESULT setError(const ErrorInfo &ei);
761 HRESULT setWarning(HRESULT aResultCode, const char *pcsz, ...);
762 HRESULT setErrorNoLog(HRESULT aResultCode, const char *pcsz, ...);
763
764
765 /** Initialize COM for a new thread. */
766 static HRESULT initializeComForThread(void)
767 {
768#ifndef VBOX_WITH_XPCOM
769 HRESULT hrc = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE | COINIT_SPEED_OVER_MEMORY);
770 AssertComRCReturn(hrc, hrc);
771#endif
772 return S_OK;
773 }
774
775 /** Uninitializes COM for a dying thread. */
776 static void uninitializeComForThread(void)
777 {
778#ifndef VBOX_WITH_XPCOM
779 CoUninitialize();
780#endif
781 }
782
783
784private:
785
786 void setState(State aState)
787 {
788 Assert(mState != aState);
789 mState = aState;
790 mStateChangeThread = RTThreadSelf();
791 }
792
793 /** Primary state of this object */
794 State mState;
795 /** Thread that caused the last state change */
796 RTTHREAD mStateChangeThread;
797 /** Total number of active calls to this object */
798 unsigned mCallers;
799 /** Posted when the number of callers drops to zero */
800 RTSEMEVENT mZeroCallersSem;
801 /** Posted when the object goes from InInit/InUninit to some other state */
802 RTSEMEVENTMULTI mInitUninitSem;
803 /** Number of threads waiting for mInitUninitDoneSem */
804 unsigned mInitUninitWaiters;
805
806 /** Protects access to state related data members */
807 WriteLockHandle mStateLock;
808
809 /** User-level object lock for subclasses */
810 mutable RWLockHandle *mObjectLock;
811
812 friend class AutoInitSpan;
813 friend class AutoReinitSpan;
814 friend class AutoUninitSpan;
815};
816
817/**
818 * Dummy macro that is used to shut down Qt's lupdate tool warnings in some
819 * situations. This macro needs to be present inside (better at the very
820 * beginning) of the declaration of the class that inherits from
821 * VirtualBoxSupportTranslation template, to make lupdate happy.
822 */
823#define Q_OBJECT
824
825////////////////////////////////////////////////////////////////////////////////
826
827////////////////////////////////////////////////////////////////////////////////
828
829
830/**
831 * Simple template that manages data structure allocation/deallocation
832 * and supports data pointer sharing (the instance that shares the pointer is
833 * not responsible for memory deallocation as opposed to the instance that
834 * owns it).
835 */
836template <class D>
837class Shareable
838{
839public:
840
841 Shareable() : mData (NULL), mIsShared(FALSE) {}
842 ~Shareable() { free(); }
843
844 void allocate() { attach(new D); }
845
846 virtual void free() {
847 if (mData) {
848 if (!mIsShared)
849 delete mData;
850 mData = NULL;
851 mIsShared = false;
852 }
853 }
854
855 void attach(D *d) {
856 AssertMsg(d, ("new data must not be NULL"));
857 if (d && mData != d) {
858 if (mData && !mIsShared)
859 delete mData;
860 mData = d;
861 mIsShared = false;
862 }
863 }
864
865 void attach(Shareable &d) {
866 AssertMsg(
867 d.mData == mData || !d.mIsShared,
868 ("new data must not be shared")
869 );
870 if (this != &d && !d.mIsShared) {
871 attach(d.mData);
872 d.mIsShared = true;
873 }
874 }
875
876 void share(D *d) {
877 AssertMsg(d, ("new data must not be NULL"));
878 if (mData != d) {
879 if (mData && !mIsShared)
880 delete mData;
881 mData = d;
882 mIsShared = true;
883 }
884 }
885
886 void share(const Shareable &d) { share(d.mData); }
887
888 void attachCopy(const D *d) {
889 AssertMsg(d, ("data to copy must not be NULL"));
890 if (d)
891 attach(new D(*d));
892 }
893
894 void attachCopy(const Shareable &d) {
895 attachCopy(d.mData);
896 }
897
898 virtual D *detach() {
899 D *d = mData;
900 mData = NULL;
901 mIsShared = false;
902 return d;
903 }
904
905 D *data() const {
906 return mData;
907 }
908
909 D *operator->() const {
910 AssertMsg(mData, ("data must not be NULL"));
911 return mData;
912 }
913
914 bool isNull() const { return mData == NULL; }
915 bool operator!() const { return isNull(); }
916
917 bool isShared() const { return mIsShared; }
918
919protected:
920
921 D *mData;
922 bool mIsShared;
923};
924
925/**
926 * Simple template that enhances Shareable<> and supports data
927 * backup/rollback/commit (using the copy constructor of the managed data
928 * structure).
929 */
930template<class D>
931class Backupable : public Shareable<D>
932{
933public:
934
935 Backupable() : Shareable<D> (), mBackupData(NULL) {}
936
937 void free()
938 {
939 AssertMsg(this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
940 rollback();
941 Shareable<D>::free();
942 }
943
944 D *detach()
945 {
946 AssertMsg(this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
947 rollback();
948 return Shareable<D>::detach();
949 }
950
951 void share(const Backupable &d)
952 {
953 AssertMsg(!d.isBackedUp(), ("data to share must not be backed up"));
954 if (!d.isBackedUp())
955 Shareable<D>::share(d.mData);
956 }
957
958 /**
959 * Stores the current data pointer in the backup area, allocates new data
960 * using the copy constructor on current data and makes new data active.
961 */
962 void backup()
963 {
964 AssertMsg(this->mData, ("data must not be NULL"));
965 if (this->mData && !mBackupData)
966 {
967 D *pNewData = new D(*this->mData);
968 mBackupData = this->mData;
969 this->mData = pNewData;
970 }
971 }
972
973 /**
974 * Deletes new data created by #backup() and restores previous data pointer
975 * stored in the backup area, making it active again.
976 */
977 void rollback()
978 {
979 if (this->mData && mBackupData)
980 {
981 delete this->mData;
982 this->mData = mBackupData;
983 mBackupData = NULL;
984 }
985 }
986
987 /**
988 * Commits current changes by deleting backed up data and clearing up the
989 * backup area. The new data pointer created by #backup() remains active
990 * and becomes the only managed pointer.
991 *
992 * This method is much faster than #commitCopy() (just a single pointer
993 * assignment operation), but makes the previous data pointer invalid
994 * (because it is freed). For this reason, this method must not be
995 * used if it's possible that data managed by this instance is shared with
996 * some other Shareable instance. See #commitCopy().
997 */
998 void commit()
999 {
1000 if (this->mData && mBackupData)
1001 {
1002 if (!this->mIsShared)
1003 delete mBackupData;
1004 mBackupData = NULL;
1005 this->mIsShared = false;
1006 }
1007 }
1008
1009 /**
1010 * Commits current changes by assigning new data to the previous data
1011 * pointer stored in the backup area using the assignment operator.
1012 * New data is deleted, the backup area is cleared and the previous data
1013 * pointer becomes active and the only managed pointer.
1014 *
1015 * This method is slower than #commit(), but it keeps the previous data
1016 * pointer valid (i.e. new data is copied to the same memory location).
1017 * For that reason it's safe to use this method on instances that share
1018 * managed data with other Shareable instances.
1019 */
1020 void commitCopy()
1021 {
1022 if (this->mData && mBackupData)
1023 {
1024 *mBackupData = *(this->mData);
1025 delete this->mData;
1026 this->mData = mBackupData;
1027 mBackupData = NULL;
1028 }
1029 }
1030
1031 void assignCopy(const D *pData)
1032 {
1033 AssertMsg(this->mData, ("data must not be NULL"));
1034 AssertMsg(pData, ("data to copy must not be NULL"));
1035 if (this->mData && pData)
1036 {
1037 if (!mBackupData)
1038 {
1039 D *pNewData = new D(*pData);
1040 mBackupData = this->mData;
1041 this->mData = pNewData;
1042 }
1043 else
1044 *this->mData = *pData;
1045 }
1046 }
1047
1048 void assignCopy(const Backupable &d)
1049 {
1050 assignCopy(d.mData);
1051 }
1052
1053 bool isBackedUp() const
1054 {
1055 return mBackupData != NULL;
1056 }
1057
1058 D *backedUpData() const
1059 {
1060 return mBackupData;
1061 }
1062
1063protected:
1064
1065 D *mBackupData;
1066};
1067
1068#endif // !____H_VIRTUALBOXBASEIMPL
1069
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