VirtualBox

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

Last change on this file since 55541 was 55401, checked in by vboxsync, 10 years ago

added a couple of missing Id headers

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