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