diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2012-10-26 16:25:44 +0000 |
---|---|---|
committer | <> | 2012-11-12 12:15:52 +0000 |
commit | 58ed4748338f9466599adfc8a9171280ed99e23f (patch) | |
tree | 02027d99ded4fb56a64aa9489ac2eb487e7858ab /include/VBox/com | |
download | VirtualBox-58ed4748338f9466599adfc8a9171280ed99e23f.tar.gz |
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.2.4.tar.bz2.VirtualBox-4.2.4
Diffstat (limited to 'include/VBox/com')
-rw-r--r-- | include/VBox/com/AutoLock.h | 638 | ||||
-rw-r--r-- | include/VBox/com/ErrorInfo.h | 495 | ||||
-rw-r--r-- | include/VBox/com/EventQueue.h | 140 | ||||
-rw-r--r-- | include/VBox/com/Guid.h | 353 | ||||
-rw-r--r-- | include/VBox/com/Makefile.kup | 0 | ||||
-rw-r--r-- | include/VBox/com/MultiResult.h | 262 | ||||
-rw-r--r-- | include/VBox/com/VirtualBox.h | 55 | ||||
-rw-r--r-- | include/VBox/com/array.h | 1702 | ||||
-rw-r--r-- | include/VBox/com/assert.h | 108 | ||||
-rw-r--r-- | include/VBox/com/com.h | 111 | ||||
-rw-r--r-- | include/VBox/com/defs.h | 549 | ||||
-rw-r--r-- | include/VBox/com/errorprint.h | 261 | ||||
-rw-r--r-- | include/VBox/com/list.h | 197 | ||||
-rw-r--r-- | include/VBox/com/listeners.h | 171 | ||||
-rw-r--r-- | include/VBox/com/mtlist.h | 197 | ||||
-rw-r--r-- | include/VBox/com/ptr.h | 493 | ||||
-rw-r--r-- | include/VBox/com/string.h | 810 |
17 files changed, 6542 insertions, 0 deletions
diff --git a/include/VBox/com/AutoLock.h b/include/VBox/com/AutoLock.h new file mode 100644 index 00000000..9c700dd9 --- /dev/null +++ b/include/VBox/com/AutoLock.h @@ -0,0 +1,638 @@ +/** @file + * + * Automatic locks, implementation + */ + +/* + * Copyright (C) 2006-2012 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ____H_AUTOLOCK +#define ____H_AUTOLOCK + +#include <iprt/types.h> + +// macros for automatic lock validation; these will amount to nothing +// unless lock validation is enabled for the runtime +#if defined(RT_LOCK_STRICT) +# define VBOX_WITH_MAIN_LOCK_VALIDATION +# define COMMA_LOCKVAL_SRC_POS , RT_SRC_POS +# define LOCKVAL_SRC_POS_DECL RT_SRC_POS_DECL +# define COMMA_LOCKVAL_SRC_POS_DECL , RT_SRC_POS_DECL +# define LOCKVAL_SRC_POS_ARGS RT_SRC_POS_ARGS +# define COMMA_LOCKVAL_SRC_POS_ARGS , RT_SRC_POS_ARGS +#else +# define COMMA_LOCKVAL_SRC_POS +# define LOCKVAL_SRC_POS_DECL +# define COMMA_LOCKVAL_SRC_POS_DECL +# define LOCKVAL_SRC_POS_ARGS +# define COMMA_LOCKVAL_SRC_POS_ARGS +#endif + +namespace util +{ + +//////////////////////////////////////////////////////////////////////////////// +// +// Order classes for lock validation +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * IPRT now has a sophisticated system of run-time locking classes to validate + * locking order. Since the Main code is handled by simpler minds, we want + * compile-time constants for simplicity, and we'll look up the run-time classes + * in AutoLock.cpp transparently. These are passed to the constructors of the + * LockHandle classes. + */ +enum VBoxLockingClass +{ + LOCKCLASS_NONE = 0, + LOCKCLASS_WEBSERVICE = 1, // highest order: webservice locks + LOCKCLASS_VIRTUALBOXOBJECT = 2, // highest order within Main itself: VirtualBox object lock + LOCKCLASS_HOSTOBJECT = 3, // Host object lock + LOCKCLASS_LISTOFMACHINES = 4, // list of machines in VirtualBox object + LOCKCLASS_MACHINEOBJECT = 5, // Machine object lock + LOCKCLASS_SNAPSHOTOBJECT = 6, // snapshot object locks + // (the snapshots tree, including the child pointers in Snapshot, + // is protected by the normal Machine object lock) + LOCKCLASS_MEDIUMQUERY = 7, // lock used to protect Machine::queryInfo + LOCKCLASS_LISTOFMEDIA = 8, // list of media (hard disks, DVDs, floppies) in VirtualBox object + LOCKCLASS_LISTOFOTHEROBJECTS = 9, // any other list of objects + LOCKCLASS_OTHEROBJECT = 10, // any regular object member variable lock + LOCKCLASS_PROGRESSLIST = 11, // list of progress objects in VirtualBox; no other object lock + // may be held after this! + LOCKCLASS_OBJECTSTATE = 12 // object state lock (handled by AutoCaller classes) +}; + +void InitAutoLockSystem(); + +/** + * Check whether the current thread holds any locks in the given class + * + * @return true if any such locks are held, false otherwise. If the lock + * validator is not compiled in, always returns false. + * @param lockClass Which lock class to check. + */ +bool AutoLockHoldsLocksInClass(VBoxLockingClass lockClass); + +//////////////////////////////////////////////////////////////////////////////// +// +// LockHandle and friends +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Abstract base class for semaphore handles (RWLockHandle and WriteLockHandle). + * Don't use this directly, but this implements lock validation for them. + */ +class LockHandle +{ +public: + LockHandle() + {} + + virtual ~LockHandle() + {} + + /** + * Returns @c true if the current thread holds a write lock on this + * read/write semaphore. Intended for debugging only. + */ + virtual bool isWriteLockOnCurrentThread() const = 0; + + /** + * Returns the current write lock level of this semaphore. The lock level + * determines the number of nested #lock() calls on the given semaphore + * handle. + * + * Note that this call is valid only when the current thread owns a write + * lock on the given semaphore handle and will assert otherwise. + */ + virtual uint32_t writeLockLevel() const = 0; + + virtual void lockWrite(LOCKVAL_SRC_POS_DECL) = 0; + virtual void unlockWrite() = 0; + virtual void lockRead(LOCKVAL_SRC_POS_DECL) = 0; + virtual void unlockRead() = 0; + +#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION + virtual const char* describe() const = 0; +#endif + +private: + // prohibit copy + assignment + LockHandle(const LockHandle&); + LockHandle& operator=(const LockHandle&); +}; + +/** + * Full-featured read/write semaphore handle implementation. + * + * This is an auxiliary base class for classes that need full-featured + * read/write locking as described in the AutoWriteLock class documentation. + * Instances of classes inherited from this class can be passed as arguments to + * the AutoWriteLock and AutoReadLock constructors. + */ +class RWLockHandle : public LockHandle +{ +public: + RWLockHandle(VBoxLockingClass lockClass); + virtual ~RWLockHandle(); + + virtual bool isWriteLockOnCurrentThread() const; + + virtual void lockWrite(LOCKVAL_SRC_POS_DECL); + virtual void unlockWrite(); + virtual void lockRead(LOCKVAL_SRC_POS_DECL); + virtual void unlockRead(); + + virtual uint32_t writeLockLevel() const; + +#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION + virtual const char* describe() const; +#endif + +private: + struct Data; + Data *m; +}; + +/** + * Write-only semaphore handle implementation. + * + * This is an auxiliary base class for classes that need write-only (exclusive) + * locking and do not need read (shared) locking. This implementation uses a + * cheap and fast critical section for both lockWrite() and lockRead() methods + * which makes a lockRead() call fully equivalent to the lockWrite() call and + * therefore makes it pointless to use instahces of this class with + * AutoReadLock instances -- shared locking will not be possible anyway and + * any call to lock() will block if there are lock owners on other threads. + * + * Use with care only when absolutely sure that shared locks are not necessary. + */ +class WriteLockHandle : public LockHandle +{ +public: + WriteLockHandle(VBoxLockingClass lockClass); + virtual ~WriteLockHandle(); + virtual bool isWriteLockOnCurrentThread() const; + + virtual void lockWrite(LOCKVAL_SRC_POS_DECL); + virtual void unlockWrite(); + virtual void lockRead(LOCKVAL_SRC_POS_DECL); + virtual void unlockRead(); + virtual uint32_t writeLockLevel() const; + +#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION + virtual const char* describe() const; +#endif + +private: + struct Data; + Data *m; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// Lockable +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Lockable interface. + * + * This is an abstract base for classes that need read/write locking. Unlike + * RWLockHandle and other classes that makes the read/write semaphore a part of + * class data, this class allows subclasses to decide which semaphore handle to + * use. + */ +class Lockable +{ +public: + + /** + * Returns a pointer to a LockHandle used by AutoWriteLock/AutoReadLock + * for locking. Subclasses are allowed to return @c NULL -- in this case, + * the AutoWriteLock/AutoReadLock object constructed using an instance of + * such subclass will simply turn into no-op. + */ + virtual LockHandle *lockHandle() const = 0; + + /** + * Equivalent to <tt>#lockHandle()->isWriteLockOnCurrentThread()</tt>. + * Returns @c false if lockHandle() returns @c NULL. + */ + bool isWriteLockOnCurrentThread() + { + LockHandle *h = lockHandle(); + return h ? h->isWriteLockOnCurrentThread() : false; + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// AutoLockBase +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Abstract base class for all autolocks. + * + * This cannot be used directly. Use AutoReadLock or AutoWriteLock or AutoMultiWriteLock2/3 + * which directly and indirectly derive from this. + * + * In the implementation, the instance data contains a list of lock handles. + * The class provides some utility functions to help locking and unlocking + * them. + */ + +class AutoLockBase +{ +protected: + AutoLockBase(uint32_t cHandles + COMMA_LOCKVAL_SRC_POS_DECL); + AutoLockBase(uint32_t cHandles, + LockHandle *pHandle + COMMA_LOCKVAL_SRC_POS_DECL); + virtual ~AutoLockBase(); + + struct Data; + Data *m; + + virtual void callLockImpl(LockHandle &l) = 0; + virtual void callUnlockImpl(LockHandle &l) = 0; + + void callLockOnAllHandles(); + void callUnlockOnAllHandles(); + + void cleanup(); + +public: + void acquire(); + void release(); + +private: + // prohibit copy + assignment + AutoLockBase(const AutoLockBase&); + AutoLockBase& operator=(const AutoLockBase&); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// AutoReadLock +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Automatic read lock. Use this with a RWLockHandle to request a read/write + * semaphore in read mode. You can also use this with a WriteLockHandle but + * that makes little sense since they treat read mode like write mode. + * + * If constructed with a RWLockHandle or an instance of Lockable (which in + * practice means any VirtualBoxBase derivative), it autoamtically requests + * the lock in read mode and releases the read lock in the destructor. + */ +class AutoReadLock : public AutoLockBase +{ +public: + + /** + * Constructs a null instance that does not manage any read/write + * semaphore. + * + * Note that all method calls on a null instance are no-ops. This allows to + * have the code where lock protection can be selected (or omitted) at + * runtime. + */ + AutoReadLock(LOCKVAL_SRC_POS_DECL) + : AutoLockBase(1, + NULL + COMMA_LOCKVAL_SRC_POS_ARGS) + { } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a read lock. + */ + AutoReadLock(LockHandle *aHandle + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoLockBase(1, + aHandle + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a read lock. + */ + AutoReadLock(LockHandle &aHandle + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoLockBase(1, + &aHandle + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a read lock. + */ + AutoReadLock(const Lockable &aLockable + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoLockBase(1, + aLockable.lockHandle() + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a read lock. + */ + AutoReadLock(const Lockable *aLockable + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoLockBase(1, + aLockable ? aLockable->lockHandle() : NULL + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + virtual ~AutoReadLock(); + + virtual void callLockImpl(LockHandle &l); + virtual void callUnlockImpl(LockHandle &l); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// AutoWriteLockBase +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Base class for all auto write locks. + * + * This cannot be used directly. Use AutoWriteLock or AutoMultiWriteLock2/3 + * which derive from this. + * + * It has some utility methods for subclasses. + */ +class AutoWriteLockBase : public AutoLockBase +{ +protected: + AutoWriteLockBase(uint32_t cHandles + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoLockBase(cHandles + COMMA_LOCKVAL_SRC_POS_ARGS) + { } + + AutoWriteLockBase(uint32_t cHandles, + LockHandle *pHandle + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoLockBase(cHandles, + pHandle + COMMA_LOCKVAL_SRC_POS_ARGS) + { } + + virtual ~AutoWriteLockBase() + { } + + virtual void callLockImpl(LockHandle &l); + virtual void callUnlockImpl(LockHandle &l); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// AutoWriteLock +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Automatic write lock. Use this with a RWLockHandle to request a read/write + * semaphore in write mode. There can only ever be one writer of a read/write + * semaphore: while the lock is held in write mode, no other writer or reader + * can request the semaphore and will block. + * + * If constructed with a RWLockHandle or an instance of Lockable (which in + * practice means any VirtualBoxBase derivative), it autoamtically requests + * the lock in write mode and releases the write lock in the destructor. + * + * When used with a WriteLockHandle, it requests the semaphore contained therein + * exclusively. + */ +class AutoWriteLock : public AutoWriteLockBase +{ +public: + + /** + * Constructs a null instance that does not manage any read/write + * semaphore. + * + * Note that all method calls on a null instance are no-ops. This allows to + * have the code where lock protection can be selected (or omitted) at + * runtime. + */ + AutoWriteLock(LOCKVAL_SRC_POS_DECL) + : AutoWriteLockBase(1, + NULL + COMMA_LOCKVAL_SRC_POS_ARGS) + { } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a write lock. + */ + AutoWriteLock(LockHandle *aHandle + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoWriteLockBase(1, + aHandle + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a write lock. + */ + AutoWriteLock(LockHandle &aHandle + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoWriteLockBase(1, + &aHandle + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a write lock. + */ + AutoWriteLock(const Lockable &aLockable + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoWriteLockBase(1, + aLockable.lockHandle() + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a write lock. + */ + AutoWriteLock(const Lockable *aLockable + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoWriteLockBase(1, + aLockable ? aLockable->lockHandle() : NULL + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a write lock. + */ + AutoWriteLock(uint32_t cHandles, + LockHandle** pHandles + COMMA_LOCKVAL_SRC_POS_DECL); + + /** + * Release all write locks acquired by this instance through the #lock() + * call and destroys the instance. + * + * Note that if there there are nested #lock() calls without the + * corresponding number of #unlock() calls when the destructor is called, it + * will assert. This is because having an unbalanced number of nested locks + * is a program logic error which must be fixed. + */ + virtual ~AutoWriteLock() + { + cleanup(); + } + + void attach(LockHandle *aHandle); + + /** @see attach (LockHandle *) */ + void attach(LockHandle &aHandle) + { + attach(&aHandle); + } + + /** @see attach (LockHandle *) */ + void attach(const Lockable &aLockable) + { + attach(aLockable.lockHandle()); + } + + /** @see attach (LockHandle *) */ + void attach(const Lockable *aLockable) + { + attach(aLockable ? aLockable->lockHandle() : NULL); + } + + bool isWriteLockOnCurrentThread() const; + uint32_t writeLockLevel() const; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// AutoMultiWriteLock* +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * A multi-write-lock containing two other write locks. + * + */ +class AutoMultiWriteLock2 : public AutoWriteLockBase +{ +public: + AutoMultiWriteLock2(Lockable *pl1, + Lockable *pl2 + COMMA_LOCKVAL_SRC_POS_DECL); + AutoMultiWriteLock2(LockHandle *pl1, + LockHandle *pl2 + COMMA_LOCKVAL_SRC_POS_DECL); + + virtual ~AutoMultiWriteLock2() + { + cleanup(); + } +}; + +/** + * A multi-write-lock containing three other write locks. + * + */ +class AutoMultiWriteLock3 : public AutoWriteLockBase +{ +public: + AutoMultiWriteLock3(Lockable *pl1, + Lockable *pl2, + Lockable *pl3 + COMMA_LOCKVAL_SRC_POS_DECL); + AutoMultiWriteLock3(LockHandle *pl1, + LockHandle *pl2, + LockHandle *pl3 + COMMA_LOCKVAL_SRC_POS_DECL); + + virtual ~AutoMultiWriteLock3() + { + cleanup(); + } +}; + +/** + * A multi-write-lock containing four other write locks. + * + */ +class AutoMultiWriteLock4 : public AutoWriteLockBase +{ +public: + AutoMultiWriteLock4(Lockable *pl1, + Lockable *pl2, + Lockable *pl3, + Lockable *pl4 + COMMA_LOCKVAL_SRC_POS_DECL); + AutoMultiWriteLock4(LockHandle *pl1, + LockHandle *pl2, + LockHandle *pl3, + LockHandle *pl4 + COMMA_LOCKVAL_SRC_POS_DECL); + + virtual ~AutoMultiWriteLock4() + { + cleanup(); + } +}; + +} /* namespace util */ + +#endif // ____H_AUTOLOCK + +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/include/VBox/com/ErrorInfo.h b/include/VBox/com/ErrorInfo.h new file mode 100644 index 00000000..1037b253 --- /dev/null +++ b/include/VBox/com/ErrorInfo.h @@ -0,0 +1,495 @@ +/** @file + * MS COM / XPCOM Abstraction Layer: + * ErrorInfo class declaration + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_com_ErrorInfo_h +#define ___VBox_com_ErrorInfo_h + +#include "VBox/com/ptr.h" +#include "VBox/com/string.h" +#include "VBox/com/Guid.h" +#include "VBox/com/assert.h" + +struct IProgress; +struct IVirtualBoxErrorInfo; + +namespace com +{ + +/** + * General discussion: + * + * In COM all errors are stored on a per thread basis. In general this means + * only _one_ active error is possible per thread. A new error will overwrite + * the previous one. To prevent this use MultiResult or ErrorInfoKeeper (see + * below). The implementations in MSCOM/XPCOM differ slightly, but the details + * are handled by this glue code. + * + * We have different classes which are involved in the error management. I try + * to describe them separately to make clear what they are there for. + * + * ErrorInfo: + * + * This class is able to retrieve the per thread error and store it into its + * member variables. This class can also handle non-VirtualBox errors (like + * standard COM errors). + * + * ProgressErrorInfo: + * + * This is just a simple wrapper class to get the ErrorInfo stored within an + * IProgress object. That is the error which was stored when the progress + * object was in use and not an error produced by IProgress itself. + * + * IVirtualBoxErrorInfo: + * + * The VirtualBox interface class for accessing error information from Main + * clients. This class is also used for storing the error information in the + * thread context. + * + * ErrorInfoKeeper: + * + * A helper class which stores the current per thread info internally. After + * calling methods which may produce other errors it is possible to restore + * the previous error and therefore restore the situation before calling the + * other methods. + * + * MultiResult: + * + * Creating an instance of MultiResult turns error chain saving on. All errors + * which follow will be saved in a chain for later access. + * + * COMErrorInfo (Qt/Gui only): + * + * The Qt GUI does some additional work for saving errors. Because we create + * wrappers for _every_ COM call, it is possible to automatically save the + * error info after the execution. This allow some additional info like saving + * the callee. Please note that this error info is saved on the client side + * and therefore locally to the object instance. See COMBaseWithEI, + * COMErrorInfo and the generated COMWrappers.cpp in the GUI. + * + * Errors itself are set in VirtualBoxBase::setErrorInternal. First a + * IVirtualBoxErrorInfo object is created and the given error is saved within. + * If MultiResult is active the current per thread error is fetched and + * attached to the new created IVirtualBoxErrorInfo object. Next this object is + * set as the new per thread error. + * + * Some general hints: + * + * - Always use setError, especially when you are working in an asynchronous thread + * to indicate an error. Otherwise the error information itself will not make + * it into the client. + * + */ + +/** + * The ErrorInfo class provides a convenient way to retrieve error + * information set by the most recent interface method, that was invoked on + * the current thread and returned an unsuccessful result code. + * + * Once the instance of this class is created, the error information for + * the current thread is cleared. + * + * There is no sense to use instances of this class after the last + * invoked interface method returns a success. + * + * The class usage pattern is as follows: + * <code> + * IFoo *foo; + * ... + * HRESULT rc = foo->SomeMethod(); + * if (FAILED(rc)) { + * ErrorInfo info(foo); + * if (info.isFullAvailable()) { + * printf("error message = %ls\n", info.getText().raw()); + * } + * } + * </code> + * + * This class fetches error information using the IErrorInfo interface on + * Win32 (MS COM) or the nsIException interface on other platforms (XPCOM), + * or the extended IVirtualBoxErrorInfo interface when when it is available + * (i.e. a given IErrorInfo or nsIException instance implements it). + * Currently, IVirtualBoxErrorInfo is only available for VirtualBox components. + * + * ErrorInfo::isFullAvailable() and ErrorInfo::isBasicAvailable() determine + * what level of error information is available. If #isBasicAvailable() + * returns true, it means that only IErrorInfo or nsIException is available as + * the source of information (depending on the platform), but not + * IVirtualBoxErrorInfo. If #isFullAvailable() returns true, it means that all + * three interfaces are available. If both methods return false, no error info + * is available at all. + * + * Here is a table of correspondence between this class methods and + * and IErrorInfo/nsIException/IVirtualBoxErrorInfo attributes/methods: + * + * ErrorInfo IErrorInfo nsIException IVirtualBoxErrorInfo + * -------------------------------------------------------------------- + * getResultCode -- result resultCode + * getIID GetGUID -- interfaceID + * getComponent GetSource -- component + * getText GetDescription message text + * + * '--' means that this interface does not provide the corresponding portion + * of information, therefore it is useless to query it if only + * #isBasicAvailable() returns true. As it can be seen, the amount of + * information provided at the basic level, depends on the platform + * (MS COM or XPCOM). + */ +class ErrorInfo +{ +public: + + /** + * Constructs a new, "interfaceless" ErrorInfo instance that takes + * the error information possibly set on the current thread by an + * interface method of some COM component or by the COM subsystem. + * + * This constructor is useful, for example, after an unsuccessful attempt + * to instantiate (create) a component, so there is no any valid interface + * pointer available. + */ + explicit ErrorInfo() + : mIsBasicAvailable(false), + mIsFullAvailable(false), + mResultCode(S_OK), + m_pNext(NULL) + { + init(); + } + + ErrorInfo(IUnknown *pObj, const GUID &aIID) + : mIsBasicAvailable(false), + mIsFullAvailable(false), + mResultCode(S_OK), + m_pNext(NULL) + { + init(pObj, aIID); + } + + /** Specialization for the IVirtualBoxErrorInfo smart pointer */ + ErrorInfo (const ComPtr <IVirtualBoxErrorInfo> &aPtr) + : mIsBasicAvailable (false), mIsFullAvailable (false) + , mResultCode (S_OK) + { init (aPtr); } + + /** + * Constructs a new ErrorInfo instance from the IVirtualBoxErrorInfo + * interface pointer. If this pointer is not NULL, both #isFullAvailable() + * and #isBasicAvailable() will return |true|. + * + * @param aInfo pointer to the IVirtualBoxErrorInfo interface that + * holds error info to be fetched by this instance + */ + ErrorInfo (IVirtualBoxErrorInfo *aInfo) + : mIsBasicAvailable (false), mIsFullAvailable (false) + , mResultCode (S_OK) + { init (aInfo); } + + ErrorInfo(const ErrorInfo &x) + { + copyFrom(x); + } + + virtual ~ErrorInfo() + { + cleanup(); + } + + ErrorInfo& operator=(const ErrorInfo& x) + { + cleanup(); + copyFrom(x); + return *this; + } + + /** + * Returns whether basic error info is actually available for the current + * thread. If the instance was created from an interface pointer that + * supports basic error info and successfully provided it, or if it is an + * "interfaceless" instance and there is some error info for the current + * thread, the returned value will be true. + * + * See the class description for details about the basic error info level. + * + * The appropriate methods of this class provide meaningful info only when + * this method returns true (otherwise they simply return NULL-like values). + */ + bool isBasicAvailable() const + { + return mIsBasicAvailable; + } + + /** + * Returns whether full error info is actually available for the current + * thread. If the instance was created from an interface pointer that + * supports full error info and successfully provided it, or if it is an + * "interfaceless" instance and there is some error info for the current + * thread, the returned value will be true. + * + * See the class description for details about the full error info level. + * + * The appropriate methods of this class provide meaningful info only when + * this method returns true (otherwise they simply return NULL-like values). + */ + bool isFullAvailable() const + { + return mIsFullAvailable; + } + + /** + * Returns the COM result code of the failed operation. + */ + HRESULT getResultCode() const + { + return mResultCode; + } + + /** + * Returns the IID of the interface that defined the error. + */ + const Guid& getInterfaceID() const + { + return mInterfaceID; + } + + /** + * Returns the name of the component that generated the error. + */ + const Bstr& getComponent() const + { + return mComponent; + } + + /** + * Returns the textual description of the error. + */ + const Bstr& getText() const + { + return mText; + } + + /** + * Returns the next error information object or @c NULL if there is none. + */ + const ErrorInfo* getNext() const + { + return m_pNext; + } + + /** + * Returns the name of the interface that defined the error + */ + const Bstr& getInterfaceName() const + { + return mInterfaceName; + } + + /** + * Returns the IID of the interface that returned the error. + * + * This method returns a non-null IID only if the instance was created + * using #template <class I> ErrorInfo(I *i) or + * template <class I> ErrorInfo(const ComPtr<I> &i) constructor. + */ + const Guid& getCalleeIID() const + { + return mCalleeIID; + } + + /** + * Returns the name of the interface that returned the error + * + * This method returns a non-null name only if the instance was created + * using #template <class I> ErrorInfo(I *i) or + * template <class I> ErrorInfo(const ComPtr<I> &i) constructor. + */ + const Bstr& getCalleeName() const + { + return mCalleeName; + } + + /** + * Resets all collected error information. #isBasicAvailable() and + * #isFullAvailable will return @c true after this method is called. + */ + void setNull() + { + cleanup(); + } + +protected: + + ErrorInfo(bool /* aDummy */) + : mIsBasicAvailable(false), + mIsFullAvailable(false), + mResultCode(S_OK), + m_pNext(NULL) + { } + + void copyFrom(const ErrorInfo &x); + void cleanup(); + + void init(bool aKeepObj = false); + void init(IUnknown *aUnk, const GUID &aIID, bool aKeepObj = false); + void init(IVirtualBoxErrorInfo *aInfo); + + bool mIsBasicAvailable : 1; + bool mIsFullAvailable : 1; + + HRESULT mResultCode; + Guid mInterfaceID; + Bstr mComponent; + Bstr mText; + + ErrorInfo *m_pNext; + + Bstr mInterfaceName; + Guid mCalleeIID; + Bstr mCalleeName; + + ComPtr<IUnknown> mErrorInfo; +}; + +/** + * A convenience subclass of ErrorInfo that, given an IProgress interface + * pointer, reads its errorInfo attribute and uses the returned + * IVirtualBoxErrorInfo instance to construct itself. + */ +class ProgressErrorInfo : public ErrorInfo +{ +public: + + /** + * Constructs a new instance by fetching error information from the + * IProgress interface pointer. If the progress object is not NULL, + * its completed attribute is true, resultCode represents a failure, + * and the errorInfo attribute returns a valid IVirtualBoxErrorInfo pointer, + * both #isFullAvailable() and #isBasicAvailable() will return true. + * + * @param progress the progress object representing a failed operation + */ + ProgressErrorInfo(IProgress *progress); +}; + +/** + * A convenience subclass of ErrorInfo that allows to preserve the current + * error info. Instances of this class fetch an error info object set on the + * current thread and keep a reference to it, which allows to restore it + * later using the #restore() method. This is useful to preserve error + * information returned by some method for the duration of making another COM + * call that may set its own error info and overwrite the existing + * one. Preserving and restoring error information makes sense when some + * method wants to return error information set by other call as its own + * error information while it still needs to make another call before return. + * + * Instead of calling #restore() explicitly you may let the object destructor + * do it for you, if you correctly limit the object's lifetime. + * + * The usage pattern is: + * <code> + * rc = foo->method(); + * if (FAILED(rc)) + * { + * ErrorInfoKeeper eik; + * ... + * // bar may return error info as well + * bar->method(); + * ... + * // no need to call #restore() explicitly here because the eik's + * // destructor will restore error info fetched after the failed + * // call to foo before returning to the caller + * return rc; + * } + * </code> + */ +class ErrorInfoKeeper : public ErrorInfo +{ +public: + + /** + * Constructs a new instance that will fetch the current error info if + * @a aIsNull is @c false (by default) or remain uninitialized (null) + * otherwise. + * + * @param aIsNull @c true to prevent fetching error info and leave + * the instance uninitialized. + */ + ErrorInfoKeeper(bool aIsNull = false) + : ErrorInfo(false), mForgot(aIsNull) + { + if (!aIsNull) + init(true /* aKeepObj */); + } + + /** + * Destroys this instance and automatically calls #restore() which will + * either restore error info fetched by the constructor or do nothing + * if #forget() was called before destruction. + */ + ~ErrorInfoKeeper() { if (!mForgot) restore(); } + + /** + * Tries to (re-)fetch error info set on the current thread. On success, + * the previous error information, if any, will be overwritten with the + * new error information. On failure, or if there is no error information + * available, this instance will be reset to null. + */ + void fetch() + { + setNull(); + mForgot = false; + init(true /* aKeepObj */); + } + + /** + * Restores error info fetched by the constructor and forgets it + * afterwards. Does nothing if the error info was forgotten by #forget(). + * + * @return COM result of the restore operation. + */ + HRESULT restore(); + + /** + * Forgets error info fetched by the constructor to prevent it from + * being restored by #restore() or by the destructor. + */ + void forget() { mForgot = true; } + + /** + * Forgets error info fetched by the constructor to prevent it from + * being restored by #restore() or by the destructor, and returns the + * stored error info object to the caller. + */ + ComPtr<IUnknown> takeError() { mForgot = true; return mErrorInfo; } + +private: + + bool mForgot : 1; +}; + +} /* namespace com */ + +#endif + diff --git a/include/VBox/com/EventQueue.h b/include/VBox/com/EventQueue.h new file mode 100644 index 00000000..14f4fc84 --- /dev/null +++ b/include/VBox/com/EventQueue.h @@ -0,0 +1,140 @@ +/** @file + * MS COM / XPCOM Abstraction Layer: + * Event and EventQueue class declaration + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_com_EventQueue_h +#define ___VBox_com_EventQueue_h + +#ifndef VBOX_WITH_XPCOM +# include <Windows.h> +#else // VBOX_WITH_XPCOM +# include <nsEventQueueUtils.h> +#endif // VBOX_WITH_XPCOM + +#include <VBox/com/defs.h> +#include <VBox/com/assert.h> + +namespace com +{ + +class EventQueue; + +/** + * Base class for all events. Intended to be subclassed to introduce new + * events and handlers for them. + * + * Subclasses usually reimplement virtual #handler() (that does nothing by + * default) and add new data members describing the event. + */ +class Event +{ +public: + + Event() {} + virtual ~Event() {}; + +protected: + + /** + * Event handler. Called in the context of the event queue's thread. + * Always reimplemented by subclasses + * + * @return reserved, should be NULL. + */ + virtual void *handler() { return NULL; } + + friend class EventQueue; +}; + +/** + * Simple event queue. + * + * When using XPCOM, this will map onto the default XPCOM queue for the thread. + * So, if a queue is created on the main thread, it automatically processes + * XPCOM/IPC events while waiting. + * + * When using Windows, Darwin and OS/2, this will map onto the native thread + * queue/runloop. So, windows messages and what not will be processed while + * waiting for events. + * + * @note It is intentional that there is no way to retrieve arbitrary + * events and controlling their processing. There is no use case which + * warrants introducing the complexity of platform independent events. + */ +class EventQueue +{ +public: + + EventQueue(); + ~EventQueue(); + + BOOL postEvent(Event *event); + int processEventQueue(RTMSINTERVAL cMsTimeout); + int interruptEventQueueProcessing(); + int getSelectFD(); + static int init(); + static int uninit(); + static EventQueue *getMainEventQueue(); + +#ifdef VBOX_WITH_XPCOM + already_AddRefed<nsIEventQueue> getIEventQueue() + { + return mEventQ.get(); + } +#else + static int dispatchMessageOnWindows(MSG const *pMsg, int rc); +#endif + +private: + static EventQueue *sMainQueue; + +#ifndef VBOX_WITH_XPCOM + + /** The thread which the queue belongs to. */ + DWORD mThreadId; + /** Duplicated thread handle for MsgWaitForMultipleObjects. */ + HANDLE mhThread; + +#else // VBOX_WITH_XPCOM + + /** Whether it was created (and thus needs destroying) or if a queue already + * associated with the thread was used. */ + bool mEQCreated; + + /** Whether event processing should be interrupted. */ + bool mInterrupted; + + nsCOMPtr <nsIEventQueue> mEventQ; + nsCOMPtr <nsIEventQueueService> mEventQService; + + static void *PR_CALLBACK plEventHandler(PLEvent *self); + static void PR_CALLBACK plEventDestructor(PLEvent *self); + +#endif // VBOX_WITH_XPCOM +}; + +} /* namespace com */ + +#endif diff --git a/include/VBox/com/Guid.h b/include/VBox/com/Guid.h new file mode 100644 index 00000000..c55d69dc --- /dev/null +++ b/include/VBox/com/Guid.h @@ -0,0 +1,353 @@ +/* $Id: Guid.h $ */ +/** @file + * MS COM / XPCOM Abstraction Layer - Guid class declaration. + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_com_Guid_h +#define ___VBox_com_Guid_h + +/* Make sure all the stdint.h macros are included - must come first! */ +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#if defined(VBOX_WITH_XPCOM) +# include <nsMemory.h> +#endif + +#include "VBox/com/string.h" + +#include <iprt/uuid.h> +#include <iprt/err.h> + +namespace com +{ + +/** + * Helper class that represents the UUID type and hides platform-specific + * implementation details. + */ +class Guid +{ +public: + + Guid() + { + ::RTUuidClear(&mUuid); + refresh(); + } + + Guid(const Guid &that) + { + mUuid = that.mUuid; + refresh(); + } + + Guid(const RTUUID &that) + { + mUuid = that; + refresh(); + } + + Guid(const GUID &that) + { + AssertCompileSize(GUID, sizeof(RTUUID)); + ::memcpy(&mUuid, &that, sizeof(GUID)); + refresh(); + } + + /** + * Construct a GUID from a string. + * + * Should the string be invalid, the object will be set to the null GUID + * (isEmpty() == true). + * + * @param that The UUID string. We feed this to RTUuidFromStr(), + * so check it out for the exact format. + */ + Guid(const char *that) + { + int rc = ::RTUuidFromStr(&mUuid, that); + if (RT_FAILURE(rc)) + ::RTUuidClear(&mUuid); + refresh(); + } + + /** + * Construct a GUID from a BSTR. + * + * Should the string be empty or invalid, the object will be set to the + * null GUID (isEmpty() == true). + * + * @param that The UUID BSTR. We feed this to RTUuidFromUtf16(), + * so check it out for the exact format. + */ + Guid(const Bstr &that) + { + int rc = !that.isEmpty() + ? ::RTUuidFromUtf16(&mUuid, that.raw()) + : VERR_INVALID_UUID_FORMAT; + if (RT_FAILURE(rc)) + ::RTUuidClear(&mUuid); + refresh(); + } + + Guid& operator=(const Guid &that) + { + ::memcpy(&mUuid, &that.mUuid, sizeof (RTUUID)); + refresh(); + return *this; + } + Guid& operator=(const GUID &guid) + { + ::memcpy(&mUuid, &guid, sizeof (GUID)); + refresh(); + return *this; + } + Guid& operator=(const RTUUID &guid) + { + ::memcpy(&mUuid, &guid, sizeof (RTUUID)); + refresh(); + return *this; + } + Guid& operator=(const char *str) + { + int rc = ::RTUuidFromStr(&mUuid, str); + if (RT_FAILURE(rc)) + ::RTUuidClear(&mUuid); + refresh(); + return *this; + } + + void create() + { + ::RTUuidCreate(&mUuid); + refresh(); + } + void clear() + { + ::RTUuidClear(&mUuid); + refresh(); + } + + /** + * Convert the GUID to a string. + * + * @returns String object containing the formatted GUID. + * @throws std::bad_alloc + */ + Utf8Str toString() const + { + char buf[RTUUID_STR_LENGTH]; + ::RTUuidToStr(&mUuid, buf, RTUUID_STR_LENGTH); + return Utf8Str(buf); + } + + /** + * Like toString, but encloses the returned string in curly brackets. + * + * @returns String object containing the formatted GUID in curly brackets. + * @throws std::bad_alloc + */ + Utf8Str toStringCurly() const + { + char buf[RTUUID_STR_LENGTH + 2] = "{"; + ::RTUuidToStr(&mUuid, buf + 1, RTUUID_STR_LENGTH); + buf[sizeof(buf) - 2] = '}'; + buf[sizeof(buf) - 1] = '\0'; + return Utf8Str(buf); + } + + /** + * Convert the GUID to a string. + * + * @returns Bstr object containing the formatted GUID. + * @throws std::bad_alloc + */ + Bstr toUtf16() const + { + if (isEmpty()) + return Bstr(); + + RTUTF16 buf[RTUUID_STR_LENGTH]; + ::RTUuidToUtf16(&mUuid, buf, RTUUID_STR_LENGTH); + return Bstr(buf); + } + + bool isEmpty() const + { + return ::RTUuidIsNull(&mUuid); + } + + bool isNotEmpty() const + { + return !::RTUuidIsNull(&mUuid); + } + + bool operator==(const Guid &that) const { return ::RTUuidCompare(&mUuid, &that.mUuid) == 0; } + bool operator==(const GUID &guid) const { return ::RTUuidCompare(&mUuid, (PRTUUID)&guid) == 0; } + bool operator!=(const Guid &that) const { return !operator==(that); } + bool operator!=(const GUID &guid) const { return !operator==(guid); } + bool operator<( const Guid &that) const { return ::RTUuidCompare(&mUuid, &that.mUuid) < 0; } + bool operator<( const GUID &guid) const { return ::RTUuidCompare(&mUuid, (PRTUUID)&guid) < 0; } + + /** + * To directly copy the contents to a GUID, or for passing it as an input + * parameter of type (const GUID *), the compiler converts. */ + const GUID &ref() const + { + return *(const GUID *)&mUuid; + } + + /** + * To pass instances to printf-like functions. + */ + PCRTUUID raw() const + { + return (PCRTUUID)&mUuid; + } + +#if !defined(VBOX_WITH_XPCOM) + + /** To assign instances to OUT_GUID parameters from within the interface + * method. */ + const Guid &cloneTo(GUID *pguid) const + { + if (pguid) + ::memcpy(pguid, &mUuid, sizeof(GUID)); + return *this; + } + + /** To pass instances as OUT_GUID parameters to interface methods. */ + GUID *asOutParam() + { + return (GUID *)&mUuid; + } + +#else + + /** To assign instances to OUT_GUID parameters from within the + * interface method */ + const Guid &cloneTo(nsID **ppGuid) const + { + if (ppGuid) + *ppGuid = (nsID *)nsMemory::Clone(&mUuid, sizeof(nsID)); + return *this; + } + + /** + * Internal helper class for asOutParam(). + * + * This takes a GUID refrence in the constructor and copies the mUuid from + * the method to that instance in its destructor. + */ + class GuidOutParam + { + GuidOutParam(Guid &guid) + : ptr(0), + outer(guid) + { + outer.clear(); + } + + nsID *ptr; + Guid &outer; + GuidOutParam(const GuidOutParam &that); // disabled + GuidOutParam &operator=(const GuidOutParam &that); // disabled + public: + operator nsID**() { return &ptr; } + ~GuidOutParam() + { + if (ptr && outer.isEmpty()) + { + outer = *ptr; + outer.refresh(); + nsMemory::Free(ptr); + } + } + friend class Guid; + }; + + /** to pass instances as OUT_GUID parameters to interface methods */ + GuidOutParam asOutParam() { return GuidOutParam(*this); } + +#endif + + /* to directly test IN_GUID interface method's parameters */ + static bool isEmpty(const GUID &guid) + { + return ::RTUuidIsNull((PRTUUID)&guid); + } + + /** + * Static immutable empty object. May be used for comparison purposes. + */ + static const Guid Empty; + +private: + /** + * Refresh the debug-only UUID string. + * + * In debug code, refresh the UUID string representatino for debugging; + * must be called every time the internal uuid changes; compiles to nothing + * in release code. + */ + inline void refresh() + { +#ifdef DEBUG + ::RTUuidToStr(&mUuid, mszUuid, RTUUID_STR_LENGTH); + m_pcszUUID = mszUuid; +#endif + } + + /** The UUID. */ + RTUUID mUuid; + +#ifdef DEBUG + /** String representation of mUuid for printing in the debugger. */ + char mszUuid[RTUUID_STR_LENGTH]; + /** Another string variant for the debugger, points to szUUID. */ + const char *m_pcszUUID; +#endif +}; + +inline Bstr asGuidStr(const Bstr& str) +{ + Guid guid(str); + return guid.isEmpty() ? Bstr() : guid.toUtf16(); +} + +inline bool isValidGuid(const Bstr& str) +{ + Guid guid(str); + return !guid.isEmpty(); +} + +} /* namespace com */ + +#endif /* !___VBox_com_Guid_h */ + diff --git a/include/VBox/com/Makefile.kup b/include/VBox/com/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/VBox/com/Makefile.kup diff --git a/include/VBox/com/MultiResult.h b/include/VBox/com/MultiResult.h new file mode 100644 index 00000000..705e1dbe --- /dev/null +++ b/include/VBox/com/MultiResult.h @@ -0,0 +1,262 @@ +/* $Id: MultiResult.h $ */ + +/** @file + * MS COM / XPCOM Abstraction Layer: + * MultiResult class declarations + */ + +/* + * Copyright (C) 2008-2012 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_com_MultiResult_h +#define ___VBox_com_MultiResult_h + +#include "VBox/com/defs.h" +#include "VBox/com/string.h" + +#include <stdarg.h> + +namespace com +{ + +/** + * "First worst" result type. + * + * Variables of this class are used instead of HRESULT variables when it is + * desirable to memorize the "first worst" result code instead of the last + * assigned one. In other words, an assignment operation to a variable of this + * class will succeed only if the result code to assign has worse severity. The + * following table demonstrate this (the first column lists the previous result + * code stored in the variable, the first row lists the new result code being + * assigned, 'A' means the assignment will take place, '> S_OK' means a warning + * result code): + * + * {{{ + * FAILED > S_OK S_OK + * FAILED - - - + * > S_OK A - - + * S_OK A A - + * + * }}} + * + * In practice, you will need to use a FWResult variable when you call some COM + * method B after another COM method A fails and want to return the result code + * of A even if B also fails, but want to return the failed result code of B if + * A issues a warning or succeeds. + */ +class FWResult +{ + +public: + + /** + * Constructs a new variable. Note that by default this constructor sets the + * result code to E_FAIL to make sure a failure is returned to the caller if + * the variable is never assigned another value (which is considered as the + * improper use of this class). + */ + FWResult (HRESULT aRC = E_FAIL) : mRC (aRC) {} + + FWResult &operator= (HRESULT aRC) + { + if ((FAILED (aRC) && !FAILED (mRC)) || + (mRC == S_OK && aRC != S_OK)) + mRC = aRC; + + return *this; + } + + operator HRESULT() const { return mRC; } + + HRESULT *operator&() { return &mRC; } + +private: + + HRESULT mRC; +}; + +/** + * The MultiResult class is a com::FWResult enhancement that also acts as a + * switch to turn on multi-error mode for VirtualBoxBase::setError() and + * VirtualBoxBase::setWarning() calls. + * + * When an instance of this class is created, multi-error mode is turned on + * for the current thread and the turn-on counter is increased by one. In + * multi-error mode, a call to setError() or setWarning() does not + * overwrite the current error or warning info object possibly set on the + * current thread by other method calls, but instead it stores this old + * object in the IVirtualBoxErrorInfo::next attribute of the new error + * object being set. + * + * This way, error/warning objects are stacked together and form a chain of + * errors where the most recent error is the first one retrieved by the + * calling party, the preceding error is what the + * IVirtualBoxErrorInfo::next attribute of the first error points to, and so + * on, up to the first error or warning occurred which is the last in the + * chain. See IVirtualBoxErrorInfo documentation for more info. + * + * When the instance of the MultiResult class goes out of scope and gets + * destroyed, it automatically decreases the turn-on counter by one. If + * the counter drops to zero, multi-error mode for the current thread is + * turned off and the thread switches back to single-error mode where every + * next error or warning object overwrites the previous one. + * + * Note that the caller of a COM method uses a non-S_OK result code to + * decide if the method has returned an error (negative codes) or a warning + * (positive non-zero codes) and will query extended error info only in + * these two cases. However, since multi-error mode implies that the method + * doesn't return control return to the caller immediately after the first + * error or warning but continues its execution, the functionality provided + * by the base com::FWResult class becomes very useful because it allows to + * preserve the error or the warning result code even if it is later assigned + * a S_OK value multiple times. See com::FWResult for details. + * + * Here is the typical usage pattern: + * <code> + + HRESULT Bar::method() + { + // assume multi-errors are turned off here... + + if (something) + { + // Turn on multi-error mode and make sure severity is preserved + MultiResult rc = foo->method1(); + + // return on fatal error, but continue on warning or on success + CheckComRCReturnRC (rc); + + rc = foo->method2(); + // no matter what result, stack it and continue + + // ... + + // return the last worst result code (it will be preserved even if + // foo->method2() returns S_OK. + return rc; + } + + // multi-errors are turned off here again... + + return S_OK; + } + + * </code> + * + * @note This class is intended to be instantiated on the stack, therefore + * You cannot create them using new(). Although it is possible to copy + * instances of MultiResult or return them by value, please never do + * that as it is breaks the class semantics (and will assert); + */ +class MultiResult : public FWResult +{ +public: + + /** + * @copydoc FWResult::FWResult(). + */ + MultiResult (HRESULT aRC = E_FAIL) : FWResult (aRC) { incCounter(); } + + MultiResult (const MultiResult &aThat) : FWResult (aThat) + { + /* We need this copy constructor only for GCC that wants to have + * it in case of expressions like |MultiResult rc = E_FAIL;|. But + * we assert since the optimizer should actually avoid the + * temporary and call the other constructor directly instead. */ + AssertFailed(); + } + + ~MultiResult() { decCounter(); } + + MultiResult &operator= (HRESULT aRC) + { + FWResult::operator= (aRC); + return *this; + } + + MultiResult &operator= (const MultiResult & /* aThat */) + { + /* We need this copy constructor only for GCC that wants to have + * it in case of expressions like |MultiResult rc = E_FAIL;|. But + * we assert since the optimizer should actually avoid the + * temporary and call the other constructor directly instead. */ + AssertFailed(); + return *this; + } + + /** + * Returns true if multi-mode is enabled for the current thread (i.e. at + * least one MultiResult instance exists on the stack somewhere). + * @return + */ + static bool isMultiEnabled(); + +private: + + DECLARE_CLS_NEW_DELETE_NOOP(MultiResult) + + static void incCounter(); + static void decCounter(); + + static RTTLS sCounter; + + friend class MultiResultRef; +}; + +/** + * The MultiResultRef class is equivalent to MultiResult except that it takes + * a reference to the existing HRESULT variable instead of maintaining its own + * one. + */ +class MultiResultRef +{ +public: + + MultiResultRef (HRESULT &aRC) : mRC (aRC) { MultiResult::incCounter(); } + + ~MultiResultRef() { MultiResult::decCounter(); } + + MultiResultRef &operator= (HRESULT aRC) + { + /* Copied from FWResult */ + if ((FAILED (aRC) && !FAILED (mRC)) || + (mRC == S_OK && aRC != S_OK)) + mRC = aRC; + + return *this; + } + + operator HRESULT() const { return mRC; } + + HRESULT *operator&() { return &mRC; } + +private: + + DECLARE_CLS_NEW_DELETE_NOOP (MultiResultRef) + + HRESULT &mRC; +}; + + +} /* namespace com */ + +#endif /* ___VBox_com_MultiResult_h */ + diff --git a/include/VBox/com/VirtualBox.h b/include/VBox/com/VirtualBox.h new file mode 100644 index 00000000..92fe1e84 --- /dev/null +++ b/include/VBox/com/VirtualBox.h @@ -0,0 +1,55 @@ +/** @file + * MS COM / XPCOM Abstraction Layer: + * VirtualBox COM Library definitions. + * + * Note: This is the main header file that COM/XPCOM clients + * include; however, it is only a wrapper around another + * platform-dependent include file that contains the real + * COM/XPCOM interface declarations. That other include file + * is generated automatically at build time from + * /src/VBox/Main/idl/VirtualBox.xidl, which contains all + * the VirtualBox interfaces; the include file is called + * VirtualBox.h on Windows hosts and VirtualBox_XPCOM.h + * on Linux hosts. The build process places it in + * out/<platform>/bin/sdk/include, from where it gets + * included by the rest of the VirtualBox code. + */ + +/* + * Copyright (C) 2006-2007 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_com_VirtualBox_h +#define ___VBox_com_VirtualBox_h + +// generated VirtualBox COM library definition file +#if !defined (VBOXCOM_NOINCLUDE) +# if !defined (VBOX_WITH_XPCOM) +# include <VirtualBox.h> +# else +# include <VirtualBox_XPCOM.h> +# endif +#endif // !defined (VBOXCOM_NOINCLUDE) + +// for convenience +#include "VBox/com/defs.h" +#include "VBox/com/ptr.h" + +#endif diff --git a/include/VBox/com/array.h b/include/VBox/com/array.h new file mode 100644 index 00000000..7f1796d9 --- /dev/null +++ b/include/VBox/com/array.h @@ -0,0 +1,1702 @@ +/** @file + * MS COM / XPCOM Abstraction Layer: + * Safe array helper class declaration + */ + +/* + * Copyright (C) 2006-2011 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_com_array_h +#define ___VBox_com_array_h + +/** @defgroup grp_COM_arrays COM/XPCOM Arrays + * @{ + * + * The COM/XPCOM array support layer provides a cross-platform way to pass + * arrays to and from COM interface methods and consists of the com::SafeArray + * template and a set of ComSafeArray* macros part of which is defined in + * VBox/com/defs.h. + * + * This layer works with interface attributes and method parameters that have + * the 'safearray="yes"' attribute in the XIDL definition: + * @code + + <interface name="ISomething" ...> + + <method name="testArrays"> + <param name="inArr" type="long" dir="in" safearray="yes"/> + <param name="outArr" type="long" dir="out" safearray="yes"/> + <param name="retArr" type="long" dir="return" safearray="yes"/> + </method> + + </interface> + + * @endcode + * + * Methods generated from this and similar definitions are implemented in + * component classes using the following declarations: + * @code + + STDMETHOD(TestArrays)(ComSafeArrayIn(LONG, aIn), + ComSafeArrayOut(LONG, aOut), + ComSafeArrayOut(LONG, aRet)); + + * @endcode + * + * And the following function bodies: + * @code + + STDMETHODIMP Component::TestArrays(ComSafeArrayIn(LONG, aIn), + ComSafeArrayOut(LONG, aOut), + ComSafeArrayOut(LONG, aRet)) + { + if (ComSafeArrayInIsNull(aIn)) + return E_INVALIDARG; + if (ComSafeArrayOutIsNull(aOut)) + return E_POINTER; + if (ComSafeArrayOutIsNull(aRet)) + return E_POINTER; + + // Use SafeArray to access the input array parameter + + com::SafeArray<LONG> in(ComSafeArrayInArg(aIn)); + + for (size_t i = 0; i < in.size(); ++ i) + LogFlow(("*** in[%u]=%d\n", i, in[i])); + + // Use SafeArray to create the return array (the same technique is used + // for output array parameters) + + SafeArray<LONG> ret(in.size() * 2); + for (size_t i = 0; i < in.size(); ++ i) + { + ret[i] = in[i]; + ret[i + in.size()] = in[i] * 10; + } + + ret.detachTo(ComSafeArrayOutArg(aRet)); + + return S_OK; + } + + * @endcode + * + * Such methods can be called from the client code using the following pattern: + * @code + + ComPtr<ISomething> component; + + // ... + + com::SafeArray<LONG> in(3); + in[0] = -1; + in[1] = -2; + in[2] = -3; + + com::SafeArray<LONG> out; + com::SafeArray<LONG> ret; + + HRESULT rc = component->TestArrays(ComSafeArrayAsInParam(in), + ComSafeArrayAsOutParam(out), + ComSafeArrayAsOutParam(ret)); + + if (SUCCEEDED(rc)) + for (size_t i = 0; i < ret.size(); ++ i) + printf("*** ret[%u]=%d\n", i, ret[i]); + + * @endcode + * + * For interoperability with standard C++ containers, there is a template + * constructor that takes such a container as argument and performs a deep copy + * of its contents. This can be used in method implementations like this: + * @code + + STDMETHODIMP Component::COMGETTER(Values)(ComSafeArrayOut(int, aValues)) + { + // ... assume there is a |std::list<int> mValues| data member + + com::SafeArray<int> values(mValues); + values.detachTo(ComSafeArrayOutArg(aValues)); + + return S_OK; + } + + * @endcode + * + * The current implementation of the SafeArray layer supports all types normally + * allowed in XIDL as array element types (including 'wstring' and 'uuid'). + * However, 'pointer-to-...' types (e.g. 'long *', 'wstring *') are not + * supported and therefore cannot be used as element types. + * + * Note that for GUID arrays you should use SafeGUIDArray and + * SafeConstGUIDArray, customized SafeArray<> specializations. + * + * Also note that in order to pass input BSTR array parameters declared + * using the ComSafeArrayIn(IN_BSTR, aParam) macro to the SafeArray<> + * constructor using the ComSafeArrayInArg() macro, you should use IN_BSTR + * as the SafeArray<> template argument, not just BSTR. + * + * Arrays of interface pointers are also supported but they require to use a + * special SafeArray implementation, com::SafeIfacePointer, which takes the + * interface class name as a template argument (e.g. com::SafeIfacePointer + * <IUnknown>). This implementation functions identically to com::SafeArray. + */ + +#ifdef VBOX_WITH_XPCOM +# include <nsMemory.h> +#endif + +#include "VBox/com/defs.h" +#include "VBox/com/ptr.h" +#include "VBox/com/assert.h" +#include "iprt/cpp/list.h" + +#ifdef VBOX_WITH_XPCOM + +/** + * Wraps the given com::SafeArray instance to generate an expression that is + * suitable for passing it to functions that take input safearray parameters + * declared using the ComSafeArrayIn macro. + * + * @param aArray com::SafeArray instance to pass as an input parameter. + */ +#define ComSafeArrayAsInParam(aArray) \ + (aArray).size(), (aArray).__asInParam_Arr((aArray).raw()) + +/** + * Wraps the given com::SafeArray instance to generate an expression that is + * suitable for passing it to functions that take output safearray parameters + * declared using the ComSafeArrayOut macro. + * + * @param aArray com::SafeArray instance to pass as an output parameter. + */ +#define ComSafeArrayAsOutParam(aArray) \ + (aArray).__asOutParam_Size(), (aArray).__asOutParam_Arr() + +#else /* !VBOX_WITH_XPCOM */ + +#define ComSafeArrayAsInParam(aArray) (aArray).__asInParam() + +#define ComSafeArrayAsOutParam(aArray) (aArray).__asOutParam() + +#endif /* !VBOX_WITH_XPCOM */ + +/** + * + */ +namespace com +{ + +#ifdef VBOX_WITH_XPCOM + +//////////////////////////////////////////////////////////////////////////////// + +/** + * Provides various helpers for SafeArray. + * + * @param T Type of array elements. + */ +template<typename T> +struct SafeArrayTraits +{ +protected: + + /** Initializes memory for aElem. */ + static void Init(T &aElem) { aElem = 0; } + + /** Initializes memory occupied by aElem. */ + static void Uninit(T &aElem) { aElem = 0; } + + /** Creates a deep copy of aFrom and stores it in aTo. */ + static void Copy(const T &aFrom, T &aTo) { aTo = aFrom; } + +public: + + /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard (that + * in particular forbid casts of 'char **' to 'const char **'). Then initial + * reason for this magic is that XPIDL declares input strings + * (char/PRUnichar pointers) as const but doesn't do so for pointers to + * arrays. */ + static T *__asInParam_Arr(T *aArr) { return aArr; } + static T *__asInParam_Arr(const T *aArr) { return const_cast<T *>(aArr); } +}; + +template<typename T> +struct SafeArrayTraits<T *> +{ + // Arbitrary pointers are not supported +}; + +template<> +struct SafeArrayTraits<PRUnichar *> +{ +protected: + + static void Init(PRUnichar * &aElem) { aElem = NULL; } + + static void Uninit(PRUnichar * &aElem) + { + if (aElem) + { + ::SysFreeString(aElem); + aElem = NULL; + } + } + + static void Copy(const PRUnichar * aFrom, PRUnichar * &aTo) + { + AssertCompile(sizeof(PRUnichar) == sizeof(OLECHAR)); + aTo = aFrom ? ::SysAllocString((const OLECHAR *)aFrom) : NULL; + } + +public: + + /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard */ + static const PRUnichar **__asInParam_Arr(PRUnichar **aArr) + { + return const_cast<const PRUnichar **>(aArr); + } + static const PRUnichar **__asInParam_Arr(const PRUnichar **aArr) { return aArr; } +}; + +template<> +struct SafeArrayTraits<const PRUnichar *> +{ +protected: + + static void Init(const PRUnichar * &aElem) { aElem = NULL; } + static void Uninit(const PRUnichar * &aElem) + { + if (aElem) + { + ::SysFreeString(const_cast<PRUnichar *>(aElem)); + aElem = NULL; + } + } + + static void Copy(const PRUnichar * aFrom, const PRUnichar * &aTo) + { + AssertCompile(sizeof(PRUnichar) == sizeof(OLECHAR)); + aTo = aFrom ? ::SysAllocString((const OLECHAR *)aFrom) : NULL; + } + +public: + + /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard */ + static const PRUnichar **__asInParam_Arr(const PRUnichar **aArr) { return aArr; } +}; + +template<> +struct SafeArrayTraits<nsID *> +{ +protected: + + static void Init(nsID * &aElem) { aElem = NULL; } + + static void Uninit(nsID * &aElem) + { + if (aElem) + { + ::nsMemory::Free(aElem); + aElem = NULL; + } + } + + static void Copy(const nsID * aFrom, nsID * &aTo) + { + if (aFrom) + { + aTo = (nsID *) ::nsMemory::Alloc(sizeof(nsID)); + if (aTo) + *aTo = *aFrom; + } + else + aTo = NULL; + } + + /* This specification is also reused for SafeConstGUIDArray, so provide a + * no-op Init() and Uninit() which are necessary for SafeArray<> but should + * be never called in context of SafeConstGUIDArray. */ + + static void Init(const nsID * &aElem) { NOREF(aElem); AssertFailed(); } + static void Uninit(const nsID * &aElem) { NOREF(aElem); AssertFailed(); } + +public: + + /** Magic to workaround strict rules of par. 4.4.4 of the C++ standard. */ + static const nsID **__asInParam_Arr(nsID **aArr) + { + return const_cast<const nsID **>(aArr); + } + static const nsID **__asInParam_Arr(const nsID **aArr) { return aArr; } +}; + +#else /* !VBOX_WITH_XPCOM */ + +//////////////////////////////////////////////////////////////////////////////// + +struct SafeArrayTraitsBase +{ +protected: + + static SAFEARRAY *CreateSafeArray(VARTYPE aVarType, SAFEARRAYBOUND *aBound) + { return SafeArrayCreate(aVarType, 1, aBound); } +}; + +/** + * Provides various helpers for SafeArray. + * + * @param T Type of array elements. + * + * Specializations of this template must provide the following methods: + * + // Returns the VARTYPE of COM SafeArray elements to be used for T + static VARTYPE VarType(); + + // Returns the number of VarType() elements necessary for aSize + // elements of T + static ULONG VarCount(size_t aSize); + + // Returns the number of elements of T that fit into the given number of + // VarType() elements (opposite to VarCount(size_t aSize)). + static size_t Size(ULONG aVarCount); + + // Creates a deep copy of aFrom and stores it in aTo + static void Copy(ULONG aFrom, ULONG &aTo); + */ +template<typename T> +struct SafeArrayTraits : public SafeArrayTraitsBase +{ +protected: + + // Arbitrary types are treated as passed by value and each value is + // represented by a number of VT_Ix type elements where VT_Ix has the + // biggest possible bitness necessary to represent T w/o a gap. COM enums + // fall into this category. + + static VARTYPE VarType() + { + if (sizeof(T) % 8 == 0) return VT_I8; + if (sizeof(T) % 4 == 0) return VT_I4; + if (sizeof(T) % 2 == 0) return VT_I2; + return VT_I1; + } + + static ULONG VarCount(size_t aSize) + { + if (sizeof(T) % 8 == 0) return (ULONG)((sizeof(T) / 8) * aSize); + if (sizeof(T) % 4 == 0) return (ULONG)((sizeof(T) / 4) * aSize); + if (sizeof(T) % 2 == 0) return (ULONG)((sizeof(T) / 2) * aSize); + return (ULONG)(sizeof(T) * aSize); + } + + static size_t Size(ULONG aVarCount) + { + if (sizeof(T) % 8 == 0) return (size_t)(aVarCount * 8) / sizeof(T); + if (sizeof(T) % 4 == 0) return (size_t)(aVarCount * 4) / sizeof(T); + if (sizeof(T) % 2 == 0) return (size_t)(aVarCount * 2) / sizeof(T); + return (size_t) aVarCount / sizeof(T); + } + + static void Copy(T aFrom, T &aTo) { aTo = aFrom; } +}; + +template<typename T> +struct SafeArrayTraits<T *> +{ + // Arbitrary pointer types are not supported +}; + +/* Although the generic SafeArrayTraits template would work for all integers, + * we specialize it for some of them in order to use the correct VT_ type */ + +template<> +struct SafeArrayTraits<LONG> : public SafeArrayTraitsBase +{ +protected: + + static VARTYPE VarType() { return VT_I4; } + static ULONG VarCount(size_t aSize) { return (ULONG)aSize; } + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; } + + static void Copy(LONG aFrom, LONG &aTo) { aTo = aFrom; } +}; + +template<> +struct SafeArrayTraits<ULONG> : public SafeArrayTraitsBase +{ +protected: + + static VARTYPE VarType() { return VT_UI4; } + static ULONG VarCount(size_t aSize) { return (ULONG)aSize; } + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; } + + static void Copy(ULONG aFrom, ULONG &aTo) { aTo = aFrom; } +}; + +template<> +struct SafeArrayTraits<LONG64> : public SafeArrayTraitsBase +{ +protected: + + static VARTYPE VarType() { return VT_I8; } + static ULONG VarCount(size_t aSize) { return (ULONG)aSize; } + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; } + + static void Copy(LONG64 aFrom, LONG64 &aTo) { aTo = aFrom; } +}; + +template<> +struct SafeArrayTraits<ULONG64> : public SafeArrayTraitsBase +{ +protected: + + static VARTYPE VarType() { return VT_UI8; } + static ULONG VarCount(size_t aSize) { return (ULONG)aSize; } + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; } + + static void Copy(ULONG64 aFrom, ULONG64 &aTo) { aTo = aFrom; } +}; + +template<> +struct SafeArrayTraits<BSTR> : public SafeArrayTraitsBase +{ +protected: + + static VARTYPE VarType() { return VT_BSTR; } + static ULONG VarCount(size_t aSize) { return (ULONG)aSize; } + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; } + + static void Copy(BSTR aFrom, BSTR &aTo) + { + aTo = aFrom ? ::SysAllocString((const OLECHAR *)aFrom) : NULL; + } +}; + +template<> +struct SafeArrayTraits<GUID> : public SafeArrayTraitsBase +{ +protected: + + /* Use the 64-bit unsigned integer type for GUID */ + static VARTYPE VarType() { return VT_UI8; } + + /* GUID is 128 bit, so we need two VT_UI8 */ + static ULONG VarCount(size_t aSize) + { + AssertCompileSize(GUID, 16); + return (ULONG)(aSize * 2); + } + + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount / 2; } + + static void Copy(GUID aFrom, GUID &aTo) { aTo = aFrom; } +}; + +/** + * Helper for SafeArray::__asOutParam() that automatically updates m.raw after a + * non-NULL m.arr assignment. + */ +class OutSafeArrayDipper +{ + OutSafeArrayDipper(SAFEARRAY **aArr, void **aRaw) + : arr(aArr), raw(aRaw) { Assert(*aArr == NULL && *aRaw == NULL); } + + SAFEARRAY **arr; + void **raw; + + template<class, class> friend class SafeArray; + +public: + + ~OutSafeArrayDipper() + { + if (*arr != NULL) + { + HRESULT rc = SafeArrayAccessData(*arr, raw); + AssertComRC(rc); + } + } + + operator SAFEARRAY **() { return arr; } +}; + +#endif /* !VBOX_WITH_XPCOM */ + +//////////////////////////////////////////////////////////////////////////////// + +/** + * The SafeArray class represents the safe array type used in COM to pass arrays + * to/from interface methods. + * + * This helper class hides all MSCOM/XPCOM specific implementation details and, + * together with ComSafeArrayIn, ComSafeArrayOut and ComSafeArrayRet macros, + * provides a platform-neutral way to handle safe arrays in the method + * implementation. + * + * When an instance of this class is destroyed, it automatically frees all + * resources occupied by individual elements of the array as well as by the + * array itself. However, when the value of an element is manually changed + * using #operator[] or by accessing array data through the #raw() pointer, it is + * the caller's responsibility to free resources occupied by the previous + * element's value. + * + * Also, objects of this class do not support copy and assignment operations and + * therefore cannot be returned from functions by value. In other words, this + * class is just a temporary storage for handling interface method calls and not + * intended to be used to store arrays as data members and such -- you should + * use normal list/vector classes for that. + * + * @note The current implementation supports only one-dimensional arrays. + * + * @note This class is not thread-safe. + */ +template<typename T, class Traits = SafeArrayTraits<T> > +class SafeArray : public Traits +{ +public: + + /** + * Creates a null array. + */ + SafeArray() {} + + /** + * Creates a new array of the given size. All elements of the newly created + * array initialized with null values. + * + * @param aSize Initial number of elements in the array. + * + * @note If this object remains null after construction it means that there + * was not enough memory for creating an array of the requested size. + * The constructor will also assert in this case. + */ + SafeArray(size_t aSize) { resize(aSize); } + + /** + * Weakly attaches this instance to the existing array passed in a method + * parameter declared using the ComSafeArrayIn macro. When using this call, + * always wrap the parameter name in the ComSafeArrayInArg macro call like + * this: + * <pre> + * SafeArray safeArray(ComSafeArrayInArg(aArg)); + * </pre> + * + * Note that this constructor doesn't take the ownership of the array. In + * particular, it means that operations that operate on the ownership (e.g. + * #detachTo()) are forbidden and will assert. + * + * @param aArg Input method parameter to attach to. + */ + SafeArray(ComSafeArrayIn(T, aArg)) + { +#ifdef VBOX_WITH_XPCOM + + AssertReturnVoid(aArg != NULL); + + m.size = aArgSize; + m.arr = aArg; + m.isWeak = true; + +#else /* !VBOX_WITH_XPCOM */ + + AssertReturnVoid(aArg != NULL); + SAFEARRAY *arg = aArg; + + if (arg) + { + AssertReturnVoid(arg->cDims == 1); + + VARTYPE vt; + HRESULT rc = SafeArrayGetVartype(arg, &vt); + AssertComRCReturnVoid(rc); + AssertMsgReturnVoid(vt == VarType(), + ("Expected vartype %d, got %d.\n", + VarType(), vt)); + + rc = SafeArrayAccessData(arg, (void HUGEP **)&m.raw); + AssertComRCReturnVoid(rc); + } + + m.arr = arg; + m.isWeak = true; + +#endif /* !VBOX_WITH_XPCOM */ + } + + /** + * Creates a deep copy of the given standard C++ container that stores + * T objects. + * + * @param aCntr Container object to copy. + * + * @param C Standard C++ container template class (normally deduced from + * @c aCntr). + */ + template<template<typename, typename> class C, class A> + SafeArray(const C<T, A> & aCntr) + { + resize(aCntr.size()); + AssertReturnVoid(!isNull()); + + size_t i = 0; + for (typename C<T, A>::const_iterator it = aCntr.begin(); + it != aCntr.end(); ++ it, ++ i) +#ifdef VBOX_WITH_XPCOM + SafeArray::Copy(*it, m.arr[i]); +#else + Copy(*it, m.raw[i]); +#endif + } + + /** + * Creates a deep copy of the given standard C++ map that stores T objects + * as values. + * + * @param aMap Map object to copy. + * + * @param C Standard C++ map template class (normally deduced from + * @c aCntr). + * @param L Standard C++ compare class (deduced from @c aCntr). + * @param A Standard C++ allocator class (deduced from @c aCntr). + * @param K Map key class (deduced from @c aCntr). + */ + template<template<typename, typename, typename, typename> + class C, class L, class A, class K> + SafeArray(const C<K, T, L, A> & aMap) + { + typedef C<K, T, L, A> Map; + + resize(aMap.size()); + AssertReturnVoid(!isNull()); + + int i = 0; + for (typename Map::const_iterator it = aMap.begin(); + it != aMap.end(); ++ it, ++ i) +#ifdef VBOX_WITH_XPCOM + Copy(it->second, m.arr[i]); +#else + Copy(it->second, m.raw[i]); +#endif + } + + /** + * Destroys this instance after calling #setNull() to release allocated + * resources. See #setNull() for more details. + */ + virtual ~SafeArray() { setNull(); } + + /** + * Returns @c true if this instance represents a null array. + */ + bool isNull() const { return m.arr == NULL; } + + /** + * Returns @c true if this instance does not represents a null array. + */ + bool isNotNull() const { return m.arr != NULL; } + + /** + * Resets this instance to null and, if this instance is not a weak one, + * releases any resources occupied by the array data. + * + * @note This method destroys (cleans up) all elements of the array using + * the corresponding cleanup routine for the element type before the + * array itself is destroyed. + */ + virtual void setNull() { m.uninit(); } + + /** + * Returns @c true if this instance is weak. A weak instance doesn't own the + * array data and therefore operations manipulating the ownership (e.g. + * #detachTo()) are forbidden and will assert. + */ + bool isWeak() const { return m.isWeak; } + + /** Number of elements in the array. */ + size_t size() const + { +#ifdef VBOX_WITH_XPCOM + if (m.arr) + return m.size; + return 0; +#else + if (m.arr) + return Size(m.arr->rgsabound[0].cElements); + return 0; +#endif + } + + /** + * Appends a copy of the given element at the end of the array. + * + * The array size is increased by one by this method and the additional + * space is allocated as needed. + * + * This method is handy in cases where you want to assign a copy of the + * existing value to the array element, for example: + * <tt>Bstr string; array.push_back(string);</tt>. If you create a string + * just to put it in the array, you may find #appendedRaw() more useful. + * + * @param aElement Element to append. + * + * @return @c true on success and @c false if there is not enough + * memory for resizing. + */ + bool push_back(const T &aElement) + { + if (!ensureCapacity(size() + 1)) + return false; + +#ifdef VBOX_WITH_XPCOM + SafeArray::Copy(aElement, m.arr[m.size]); + ++ m.size; +#else + Copy(aElement, m.raw[size() - 1]); +#endif + return true; + } + + /** + * Appends an empty element at the end of the array and returns a raw + * pointer to it suitable for assigning a raw value (w/o constructing a + * copy). + * + * The array size is increased by one by this method and the additional + * space is allocated as needed. + * + * Note that in case of raw assignment, value ownership (for types with + * dynamically allocated data and for interface pointers) is transferred to + * the safe array object. + * + * This method is handy for operations like + * <tt>Bstr("foo").detachTo(array.appendedRaw());</tt>. Don't use it as + * an l-value (<tt>array.appendedRaw() = SysAllocString(L"tralala");</tt>) + * since this doesn't check for a NULL condition; use #resize() and + * #setRawAt() instead. If you need to assign a copy of the existing value + * instead of transferring the ownership, look at #push_back(). + * + * @return Raw pointer to the added element or NULL if no memory. + */ + T *appendedRaw() + { + if (!ensureCapacity(size() + 1)) + return NULL; + +#ifdef VBOX_WITH_XPCOM + SafeArray::Init(m.arr[m.size]); + ++ m.size; + return &m.arr[m.size - 1]; +#else + /* nothing to do here, SafeArrayCreate() has performed element + * initialization */ + return &m.raw[size() - 1]; +#endif + } + + /** + * Resizes the array preserving its contents when possible. If the new size + * is larger than the old size, new elements are initialized with null + * values. If the new size is less than the old size, the contents of the + * array beyond the new size is lost. + * + * @param aNewSize New number of elements in the array. + * @return @c true on success and @c false if there is not enough + * memory for resizing. + */ + bool resize(size_t aNewSize) + { + if (!ensureCapacity(aNewSize)) + return false; + +#ifdef VBOX_WITH_XPCOM + + if (m.size < aNewSize) + { + /* initialize the new elements */ + for (size_t i = m.size; i < aNewSize; ++ i) + SafeArray::Init(m.arr[i]); + } + + m.size = aNewSize; +#else + /* nothing to do here, SafeArrayCreate() has performed element + * initialization */ +#endif + return true; + } + + /** + * Reinitializes this instance by preallocating space for the given number + * of elements. The previous array contents is lost. + * + * @param aNewSize New number of elements in the array. + * @return @c true on success and @c false if there is not enough + * memory for resizing. + */ + bool reset(size_t aNewSize) + { + m.uninit(); + return resize(aNewSize); + } + + /** + * Returns a pointer to the raw array data. Use this raw pointer with care + * as no type or bound checking is done for you in this case. + * + * @note This method returns @c NULL when this instance is null. + * @see #operator[] + */ + T *raw() + { +#ifdef VBOX_WITH_XPCOM + return m.arr; +#else + return m.raw; +#endif + } + + /** + * Const version of #raw(). + */ + const T *raw() const + { +#ifdef VBOX_WITH_XPCOM + return m.arr; +#else + return m.raw; +#endif + } + + /** + * Array access operator that returns an array element by reference. A bit + * safer than #raw(): asserts and returns an invalid reference if this + * instance is null or if the index is out of bounds. + * + * @note For weak instances, this call will succeed but the behavior of + * changing the contents of an element of the weak array instance is + * undefined and may lead to a program crash on some platforms. + */ + T &operator[] (size_t aIdx) + { + AssertReturn(m.arr != NULL, *((T *)NULL)); + AssertReturn(aIdx < size(), *((T *)NULL)); +#ifdef VBOX_WITH_XPCOM + return m.arr[aIdx]; +#else + AssertReturn(m.raw != NULL, *((T *)NULL)); + return m.raw[aIdx]; +#endif + } + + /** + * Const version of #operator[] that returns an array element by value. + */ + const T operator[] (size_t aIdx) const + { + AssertReturn(m.arr != NULL, *((T *)NULL)); + AssertReturn(aIdx < size(), *((T *)NULL)); +#ifdef VBOX_WITH_XPCOM + return m.arr[aIdx]; +#else + AssertReturn(m.raw != NULL, *((T *)NULL)); + return m.raw[aIdx]; +#endif + } + + /** + * Creates a copy of this array and stores it in a method parameter declared + * using the ComSafeArrayOut macro. When using this call, always wrap the + * parameter name in the ComSafeArrayOutArg macro call like this: + * <pre> + * safeArray.cloneTo(ComSafeArrayOutArg(aArg)); + * </pre> + * + * @note It is assumed that the ownership of the returned copy is + * transferred to the caller of the method and he is responsible to free the + * array data when it is no longer needed. + * + * @param aArg Output method parameter to clone to. + */ + virtual const SafeArray &cloneTo(ComSafeArrayOut(T, aArg)) const + { + /// @todo Implement me! +#ifdef VBOX_WITH_XPCOM + NOREF(aArgSize); + NOREF(aArg); +#else + NOREF(aArg); +#endif + AssertFailedReturn(*this); + } + + void cloneTo(SafeArray<T>& aOther) const + { + aOther.reset(size()); + aOther.initFrom(*this); + } + + + /** + * Transfers the ownership of this array's data to the specified location + * declared using the ComSafeArrayOut macro and makes this array a null + * array. When using this call, always wrap the parameter name in the + * ComSafeArrayOutArg macro call like this: + * <pre> + * safeArray.detachTo(ComSafeArrayOutArg(aArg)); + * </pre> + * + * Detaching the null array is also possible in which case the location will + * receive NULL. + * + * @note Since the ownership of the array data is transferred to the + * caller of the method, he is responsible to free the array data when it is + * no longer needed. + * + * @param aArg Location to detach to. + */ + virtual SafeArray &detachTo(ComSafeArrayOut(T, aArg)) + { + AssertReturn(m.isWeak == false, *this); + +#ifdef VBOX_WITH_XPCOM + + AssertReturn(aArgSize != NULL, *this); + AssertReturn(aArg != NULL, *this); + + *aArgSize = m.size; + *aArg = m.arr; + + m.isWeak = false; + m.size = 0; + m.arr = NULL; + +#else /* !VBOX_WITH_XPCOM */ + + AssertReturn(aArg != NULL, *this); + *aArg = m.arr; + + if (m.raw) + { + HRESULT rc = SafeArrayUnaccessData(m.arr); + AssertComRCReturn(rc, *this); + m.raw = NULL; + } + + m.isWeak = false; + m.arr = NULL; + +#endif /* !VBOX_WITH_XPCOM */ + + return *this; + } + + /** + * Returns a copy of this SafeArray as RTCList<T>. + */ + RTCList<T> toList() + { + RTCList<T> list(size()); + for (size_t i = 0; i < size(); ++i) +#ifdef VBOX_WITH_XPCOM + list.append(m.arr[i]); +#else + list.append(m.raw[i]); +#endif + return list; + } + + inline void initFrom(const com::SafeArray<T> & aRef); + inline void initFrom(const T* aPtr, size_t aSize); + + // Public methods for internal purposes only. + +#ifdef VBOX_WITH_XPCOM + + /** Internal function. Never call it directly. */ + PRUint32 *__asOutParam_Size() { setNull(); return &m.size; } + + /** Internal function Never call it directly. */ + T **__asOutParam_Arr() { Assert(isNull()); return &m.arr; } + +#else /* !VBOX_WITH_XPCOM */ + + /** Internal function Never call it directly. */ + SAFEARRAY * __asInParam() { return m.arr; } + + /** Internal function Never call it directly. */ + OutSafeArrayDipper __asOutParam() + { setNull(); return OutSafeArrayDipper(&m.arr, (void **)&m.raw); } + +#endif /* !VBOX_WITH_XPCOM */ + + static const SafeArray Null; + +protected: + + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(SafeArray) + + /** + * Ensures that the array is big enough to contain aNewSize elements. + * + * If the new size is greater than the current capacity, a new array is + * allocated and elements from the old array are copied over. The size of + * the array doesn't change, only the capacity increases (which is always + * greater than the size). Note that the additionally allocated elements are + * left uninitialized by this method. + * + * If the new size is less than the current size, the existing array is + * truncated to the specified size and the elements outside the new array + * boundary are freed. + * + * If the new size is the same as the current size, nothing happens. + * + * @param aNewSize New size of the array. + * + * @return @c true on success and @c false if not enough memory. + */ + bool ensureCapacity(size_t aNewSize) + { + AssertReturn(!m.isWeak, false); + +#ifdef VBOX_WITH_XPCOM + + /* Note: we distinguish between a null array and an empty (zero + * elements) array. Therefore we never use zero in malloc (even if + * aNewSize is zero) to make sure we get a non-null pointer. */ + + if (m.size == aNewSize && m.arr != NULL) + return true; + + /* Allocate in 16-byte pieces. */ + size_t newCapacity = RT_MAX((aNewSize + 15) / 16 * 16, 16); + + if (m.capacity != newCapacity) + { + T *newArr = (T *)nsMemory::Alloc(RT_MAX(newCapacity, 1) * sizeof(T)); + AssertReturn(newArr != NULL, false); + + if (m.arr != NULL) + { + if (m.size > aNewSize) + { + /* Truncation takes place, uninit exceeding elements and + * shrink the size. */ + for (size_t i = aNewSize; i < m.size; ++ i) + SafeArray::Uninit(m.arr[i]); + + m.size = aNewSize; + } + + /* Copy the old contents. */ + memcpy(newArr, m.arr, m.size * sizeof(T)); + nsMemory::Free((void *)m.arr); + } + + m.arr = newArr; + } + else + { + if (m.size > aNewSize) + { + /* Truncation takes place, uninit exceeding elements and + * shrink the size. */ + for (size_t i = aNewSize; i < m.size; ++ i) + SafeArray::Uninit(m.arr[i]); + + m.size = aNewSize; + } + } + + m.capacity = newCapacity; + +#else + + SAFEARRAYBOUND bound = { VarCount(aNewSize), 0 }; + HRESULT rc; + + if (m.arr == NULL) + { + m.arr = CreateSafeArray(VarType(), &bound); + AssertReturn(m.arr != NULL, false); + } + else + { + SafeArrayUnaccessData(m.arr); + + rc = SafeArrayRedim(m.arr, &bound); + AssertComRCReturn(rc == S_OK, false); + } + + rc = SafeArrayAccessData(m.arr, (void HUGEP **)&m.raw); + AssertComRCReturn(rc, false); + +#endif + return true; + } + + struct Data + { + Data() + : isWeak(false) +#ifdef VBOX_WITH_XPCOM + , capacity(0), size(0), arr(NULL) +#else + , arr(NULL), raw(NULL) +#endif + {} + + ~Data() { uninit(); } + + void uninit() + { +#ifdef VBOX_WITH_XPCOM + + if (arr) + { + if (!isWeak) + { + for (size_t i = 0; i < size; ++ i) + SafeArray::Uninit(arr[i]); + + nsMemory::Free((void *)arr); + } + else + isWeak = false; + + arr = NULL; + } + + size = capacity = 0; + +#else /* !VBOX_WITH_XPCOM */ + + if (arr) + { + if (raw) + { + SafeArrayUnaccessData(arr); + raw = NULL; + } + + if (!isWeak) + { + HRESULT rc = SafeArrayDestroy(arr); + AssertComRCReturnVoid(rc); + } + else + isWeak = false; + + arr = NULL; + } + +#endif /* !VBOX_WITH_XPCOM */ + } + + bool isWeak : 1; + +#ifdef VBOX_WITH_XPCOM + PRUint32 capacity; + PRUint32 size; + T *arr; +#else + SAFEARRAY *arr; + T *raw; +#endif + }; + + Data m; +}; + +/* Few fast specializations for primitive array types */ +template<> +inline void com::SafeArray<BYTE>::initFrom(const com::SafeArray<BYTE> & aRef) +{ + size_t sSize = aRef.size(); + resize(sSize); + ::memcpy(raw(), aRef.raw(), sSize); +} +template<> +inline void com::SafeArray<BYTE>::initFrom(const BYTE* aPtr, size_t aSize) +{ + resize(aSize); + ::memcpy(raw(), aPtr, aSize); +} + + +template<> +inline void com::SafeArray<LONG>::initFrom(const com::SafeArray<LONG> & aRef) +{ + size_t sSize = aRef.size(); + resize(sSize); + ::memcpy(raw(), aRef.raw(), sSize * sizeof(LONG)); +} +template<> +inline void com::SafeArray<LONG>::initFrom(const LONG* aPtr, size_t aSize) +{ + resize(aSize); + ::memcpy(raw(), aPtr, aSize * sizeof(LONG)); +} + + +//////////////////////////////////////////////////////////////////////////////// + +#ifdef VBOX_WITH_XPCOM + +/** + * Version of com::SafeArray for arrays of GUID. + * + * In MS COM, GUID arrays store GUIDs by value and therefore input arrays are + * represented using |GUID *| and out arrays -- using |GUID **|. In XPCOM, + * GUID arrays store pointers to nsID so that input arrays are |const nsID **| + * and out arrays are |nsID ***|. Due to this difference, it is impossible to + * work with arrays of GUID on both platforms by simply using com::SafeArray + * <GUID>. This class is intended to provide some level of cross-platform + * behavior. + * + * The basic usage pattern is basically similar to com::SafeArray<> except that + * you use ComSafeGUIDArrayIn* and ComSafeGUIDArrayOut* macros instead of + * ComSafeArrayIn* and ComSafeArrayOut*. Another important nuance is that the + * raw() array type is different (nsID **, or GUID ** on XPCOM and GUID * on MS + * COM) so it is recommended to use operator[] instead which always returns a + * GUID by value. + * + * Note that due to const modifiers, you cannot use SafeGUIDArray for input GUID + * arrays. Please use SafeConstGUIDArray for this instead. + * + * Other than mentioned above, the functionality of this class is equivalent to + * com::SafeArray<>. See the description of that template and its methods for + * more information. + * + * Output GUID arrays are handled by a separate class, SafeGUIDArrayOut, since + * this class cannot handle them because of const modifiers. + */ +class SafeGUIDArray : public SafeArray<nsID *> +{ +public: + + typedef SafeArray<nsID *> Base; + + class nsIDRef + { + public: + + nsIDRef(nsID * &aVal) : mVal(aVal) {} + + operator const nsID &() const { return mVal ? *mVal : *Empty; } + operator nsID() const { return mVal ? *mVal : *Empty; } + + const nsID *operator&() const { return mVal ? mVal : Empty; } + + nsIDRef &operator= (const nsID &aThat) + { + if (mVal == NULL) + Copy(&aThat, mVal); + else + *mVal = aThat; + return *this; + } + + private: + + nsID * &mVal; + + static const nsID *Empty; + + friend class SafeGUIDArray; + }; + + /** See SafeArray<>::SafeArray(). */ + SafeGUIDArray() {} + + /** See SafeArray<>::SafeArray(size_t). */ + SafeGUIDArray(size_t aSize) : Base(aSize) {} + + /** + * Array access operator that returns an array element by reference. As a + * special case, the return value of this operator on XPCOM is an nsID (GUID) + * reference, instead of an nsID pointer (the actual SafeArray template + * argument), for compatibility with the MS COM version. + * + * The rest is equivalent to SafeArray<>::operator[]. + */ + nsIDRef operator[] (size_t aIdx) + { + Assert(m.arr != NULL); + Assert(aIdx < size()); + return nsIDRef(m.arr[aIdx]); + } + + /** + * Const version of #operator[] that returns an array element by value. + */ + const nsID &operator[] (size_t aIdx) const + { + Assert(m.arr != NULL); + Assert(aIdx < size()); + return m.arr[aIdx] ? *m.arr[aIdx] : *nsIDRef::Empty; + } +}; + +/** + * Version of com::SafeArray for const arrays of GUID. + * + * This class is used to work with input GUID array parameters in method + * implementations. See SafeGUIDArray for more details. + */ +class SafeConstGUIDArray : public SafeArray<const nsID *, + SafeArrayTraits<nsID *> > +{ +public: + + typedef SafeArray<const nsID *, SafeArrayTraits<nsID *> > Base; + + /** See SafeArray<>::SafeArray(). */ + SafeConstGUIDArray() {} + + /* See SafeArray<>::SafeArray(ComSafeArrayIn(T, aArg)). */ + SafeConstGUIDArray(ComSafeGUIDArrayIn(aArg)) + : Base(ComSafeGUIDArrayInArg(aArg)) {} + + /** + * Array access operator that returns an array element by reference. As a + * special case, the return value of this operator on XPCOM is nsID (GUID) + * instead of nsID *, for compatibility with the MS COM version. + * + * The rest is equivalent to SafeArray<>::operator[]. + */ + const nsID &operator[] (size_t aIdx) const + { + AssertReturn(m.arr != NULL, **((const nsID * *)NULL)); + AssertReturn(aIdx < size(), **((const nsID * *)NULL)); + return *m.arr[aIdx]; + } + +private: + + /* These are disabled because of const. */ + bool reset(size_t aNewSize) { NOREF(aNewSize); return false; } +}; + +#else /* !VBOX_WITH_XPCOM */ + +typedef SafeArray<GUID> SafeGUIDArray; +typedef SafeArray<const GUID, SafeArrayTraits<GUID> > SafeConstGUIDArray; + +#endif /* !VBOX_WITH_XPCOM */ + +//////////////////////////////////////////////////////////////////////////////// + +#ifdef VBOX_WITH_XPCOM + +template<class I> +struct SafeIfaceArrayTraits +{ +protected: + + static void Init(I * &aElem) { aElem = NULL; } + static void Uninit(I * &aElem) + { + if (aElem) + { + aElem->Release(); + aElem = NULL; + } + } + + static void Copy(I * aFrom, I * &aTo) + { + if (aFrom != NULL) + { + aTo = aFrom; + aTo->AddRef(); + } + else + aTo = NULL; + } + +public: + + /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard. */ + static I **__asInParam_Arr(I **aArr) { return aArr; } + static I **__asInParam_Arr(const I **aArr) { return const_cast<I **>(aArr); } +}; + +#else /* !VBOX_WITH_XPCOM */ + +template<class I> +struct SafeIfaceArrayTraits +{ +protected: + + static VARTYPE VarType() { return VT_DISPATCH; } + static ULONG VarCount(size_t aSize) { return (ULONG)aSize; } + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; } + + static void Copy(I * aFrom, I * &aTo) + { + if (aFrom != NULL) + { + aTo = aFrom; + aTo->AddRef(); + } + else + aTo = NULL; + } + + static SAFEARRAY *CreateSafeArray(VARTYPE aVarType, SAFEARRAYBOUND *aBound) + { + NOREF(aVarType); + return SafeArrayCreateEx(VT_DISPATCH, 1, aBound, (PVOID)&_ATL_IIDOF(I)); + } +}; + +#endif /* !VBOX_WITH_XPCOM */ + +//////////////////////////////////////////////////////////////////////////////// + +/** + * Version of com::SafeArray for arrays of interface pointers. + * + * Except that it manages arrays of interface pointers, the usage of this class + * is identical to com::SafeArray. + * + * @param I Interface class (no asterisk). + */ +template<class I> +class SafeIfaceArray : public SafeArray<I *, SafeIfaceArrayTraits<I> > +{ +public: + + typedef SafeArray<I *, SafeIfaceArrayTraits<I> > Base; + + /** + * Creates a null array. + */ + SafeIfaceArray() {} + + /** + * Creates a new array of the given size. All elements of the newly created + * array initialized with null values. + * + * @param aSize Initial number of elements in the array. Must be greater + * than 0. + * + * @note If this object remains null after construction it means that there + * was not enough memory for creating an array of the requested size. + * The constructor will also assert in this case. + */ + SafeIfaceArray(size_t aSize) { Base::resize(aSize); } + + /** + * Weakly attaches this instance to the existing array passed in a method + * parameter declared using the ComSafeArrayIn macro. When using this call, + * always wrap the parameter name in the ComSafeArrayOutArg macro call like + * this: + * <pre> + * SafeArray safeArray(ComSafeArrayInArg(aArg)); + * </pre> + * + * Note that this constructor doesn't take the ownership of the array. In + * particular, this means that operations that operate on the ownership + * (e.g. #detachTo()) are forbidden and will assert. + * + * @param aArg Input method parameter to attach to. + */ + SafeIfaceArray(ComSafeArrayIn(I *, aArg)) + { +#ifdef VBOX_WITH_XPCOM + + AssertReturnVoid(aArg != NULL); + + Base::m.size = aArgSize; + Base::m.arr = aArg; + Base::m.isWeak = true; + +#else /* !VBOX_WITH_XPCOM */ + + AssertReturnVoid(aArg != NULL); + SAFEARRAY *arg = aArg; + + if (arg) + { + AssertReturnVoid(arg->cDims == 1); + + VARTYPE vt; + HRESULT rc = SafeArrayGetVartype(arg, &vt); + AssertComRCReturnVoid(rc); + AssertMsgReturnVoid(vt == VT_UNKNOWN || vt == VT_DISPATCH, + ("Expected vartype VT_UNKNOWN, got %d.\n", + VarType(), vt)); + GUID guid; + rc = SafeArrayGetIID(arg, &guid); + AssertComRCReturnVoid(rc); + AssertMsgReturnVoid(InlineIsEqualGUID(_ATL_IIDOF(I), guid), + ("Expected IID {%RTuuid}, got {%RTuuid}.\n", + &_ATL_IIDOF(I), &guid)); + + rc = SafeArrayAccessData(arg, (void HUGEP **)&m.raw); + AssertComRCReturnVoid(rc); + } + + m.arr = arg; + m.isWeak = true; + +#endif /* !VBOX_WITH_XPCOM */ + } + + /** + * Creates a deep copy of the given standard C++ container that stores + * interface pointers as objects of the ComPtr<I> class. + * + * @param aCntr Container object to copy. + * + * @param C Standard C++ container template class (normally deduced from + * @c aCntr). + * @param A Standard C++ allocator class (deduced from @c aCntr). + * @param OI Argument to the ComPtr template (deduced from @c aCntr). + */ + template<template<typename, typename> class C, class A, class OI> + SafeIfaceArray(const C<ComPtr<OI>, A> & aCntr) + { + typedef C<ComPtr<OI>, A> List; + + Base::resize(aCntr.size()); + AssertReturnVoid(!Base::isNull()); + + int i = 0; + for (typename List::const_iterator it = aCntr.begin(); + it != aCntr.end(); ++ it, ++ i) +#ifdef VBOX_WITH_XPCOM + Copy(*it, Base::m.arr[i]); +#else + Copy(*it, Base::m.raw[i]); +#endif + } + + /** + * Creates a deep copy of the given standard C++ container that stores + * interface pointers as objects of the ComObjPtr<I> class. + * + * @param aCntr Container object to copy. + * + * @param C Standard C++ container template class (normally deduced from + * @c aCntr). + * @param A Standard C++ allocator class (deduced from @c aCntr). + * @param OI Argument to the ComObjPtr template (deduced from @c aCntr). + */ + template<template<typename, typename> class C, class A, class OI> + SafeIfaceArray(const C<ComObjPtr<OI>, A> & aCntr) + { + typedef C<ComObjPtr<OI>, A> List; + + Base::resize(aCntr.size()); + AssertReturnVoid(!Base::isNull()); + + int i = 0; + for (typename List::const_iterator it = aCntr.begin(); + it != aCntr.end(); ++ it, ++ i) +#ifdef VBOX_WITH_XPCOM + SafeIfaceArray::Copy(*it, Base::m.arr[i]); +#else + Copy(*it, Base::m.raw[i]); +#endif + } + + /** + * Creates a deep copy of the given standard C++ map whose values are + * interface pointers stored as objects of the ComPtr<I> class. + * + * @param aMap Map object to copy. + * + * @param C Standard C++ map template class (normally deduced from + * @c aCntr). + * @param L Standard C++ compare class (deduced from @c aCntr). + * @param A Standard C++ allocator class (deduced from @c aCntr). + * @param K Map key class (deduced from @c aCntr). + * @param OI Argument to the ComPtr template (deduced from @c aCntr). + */ + template<template<typename, typename, typename, typename> + class C, class L, class A, class K, class OI> + SafeIfaceArray(const C<K, ComPtr<OI>, L, A> & aMap) + { + typedef C<K, ComPtr<OI>, L, A> Map; + + Base::resize(aMap.size()); + AssertReturnVoid(!Base::isNull()); + + int i = 0; + for (typename Map::const_iterator it = aMap.begin(); + it != aMap.end(); ++ it, ++ i) +#ifdef VBOX_WITH_XPCOM + SafeIfaceArray::Copy(it->second, Base::m.arr[i]); +#else + Copy(it->second, Base::m.raw[i]); +#endif + } + + /** + * Creates a deep copy of the given standard C++ map whose values are + * interface pointers stored as objects of the ComObjPtr<I> class. + * + * @param aMap Map object to copy. + * + * @param C Standard C++ map template class (normally deduced from + * @c aCntr). + * @param L Standard C++ compare class (deduced from @c aCntr). + * @param A Standard C++ allocator class (deduced from @c aCntr). + * @param K Map key class (deduced from @c aCntr). + * @param OI Argument to the ComObjPtr template (deduced from @c aCntr). + */ + template<template<typename, typename, typename, typename> + class C, class L, class A, class K, class OI> + SafeIfaceArray(const C<K, ComObjPtr<OI>, L, A> & aMap) + { + typedef C<K, ComObjPtr<OI>, L, A> Map; + + Base::resize(aMap.size()); + AssertReturnVoid(!Base::isNull()); + + int i = 0; + for (typename Map::const_iterator it = aMap.begin(); + it != aMap.end(); ++ it, ++ i) +#ifdef VBOX_WITH_XPCOM + SafeIfaceArray::Copy(it->second, Base::m.arr[i]); +#else + Copy(it->second, Base::m.raw[i]); +#endif + } + + void setElement(size_t iIdx, I* obj) + { +#ifdef VBOX_WITH_XPCOM + SafeIfaceArray::Copy(obj, Base::m.arr[iIdx]); +#else + Copy(obj, Base::m.raw[iIdx]); +#endif + } +}; + +} /* namespace com */ + +/** @} */ + +#endif /* ___VBox_com_array_h */ diff --git a/include/VBox/com/assert.h b/include/VBox/com/assert.h new file mode 100644 index 00000000..0a9b1afd --- /dev/null +++ b/include/VBox/com/assert.h @@ -0,0 +1,108 @@ +/** @file + * MS COM / XPCOM Abstraction Layer: + * Assertion macros for COM/XPCOM + */ + +/* + * Copyright (C) 2006-2007 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_com_assert_h +#define ___VBox_com_assert_h + +#include <iprt/assert.h> + +/** + * Asserts that the COM result code is succeeded in strict builds. + * In non-strict builds the result code will be NOREF'ed to kill compiler warnings. + * + * @param rc COM result code + */ +#define AssertComRC(rc) \ + do { AssertMsg (SUCCEEDED (rc), ("COM RC = %Rhrc (0x%08X)\n", rc, rc)); NOREF (rc); } while (0) + +/** + * A special version of AssertComRC that returns the given expression + * if the result code is failed. + * + * @param rc COM result code + * @param ret the expression to return + */ +#define AssertComRCReturn(rc, ret) \ + AssertMsgReturn (SUCCEEDED (rc), ("COM RC = %Rhrc (0x%08X)\n", rc, rc), ret) + +/** + * A special version of AssertComRC that returns the given result code + * if it is failed. + * + * @param rc COM result code + * @param ret the expression to return + */ +#define AssertComRCReturnRC(rc) \ + AssertMsgReturn (SUCCEEDED (rc), ("COM RC = %Rhrc (0x%08X)\n", rc, rc), rc) + +/** + * A special version of AssertComRC that returns if the result code is failed. + * + * @param rc COM result code + * @param ret the expression to return + */ +#define AssertComRCReturnVoid(rc) \ + AssertMsgReturnVoid (SUCCEEDED (rc), ("COM RC = %Rhrc (0x%08X)\n", rc, rc)) + +/** + * A special version of AssertComRC that evaluates the given expression and + * breaks if the result code is failed. + * + * @param rc COM result code + * @param eval the expression to evaluate + */ +#define AssertComRCBreak(rc, eval) \ + if (!SUCCEEDED (rc)) { AssertComRC (rc); eval; break; } else do {} while (0) + +/** + * A special version of AssertComRC that evaluates the given expression and + * throws it if the result code is failed. + * + * @param rc COM result code + * @param eval the expression to throw + */ +#define AssertComRCThrow(rc, eval) \ + if (!SUCCEEDED (rc)) { AssertComRC (rc); throw (eval); } else do {} while (0) + +/** + * A special version of AssertComRC that just breaks if the result code is + * failed. + * + * @param rc COM result code + */ +#define AssertComRCBreakRC(rc) \ + if (!SUCCEEDED (rc)) { AssertComRC (rc); break; } else do {} while (0) + +/** + * A special version of AssertComRC that just throws @a rc if the result code is + * failed. + * + * @param rc COM result code + */ +#define AssertComRCThrowRC(rc) \ + if (!SUCCEEDED (rc)) { AssertComRC (rc); throw rc; } else do {} while (0) + +#endif // !___VBox_com_assert_h diff --git a/include/VBox/com/com.h b/include/VBox/com/com.h new file mode 100644 index 00000000..524c89c6 --- /dev/null +++ b/include/VBox/com/com.h @@ -0,0 +1,111 @@ +/** @file + * MS COM / XPCOM Abstraction Layer: + * COM initialization / shutdown + */ + +/* + * Copyright (C) 2005-2012 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_com_com_h +#define ___VBox_com_com_h + +#include "VBox/com/defs.h" + +namespace com +{ + +/** + * Initializes the COM runtime. + * Must be called on the main thread, before any COM activity in any thread, and by any thread + * willing to perform COM operations. + * + * @param fMain if call is performed on the GUI thread + * @return COM result code + */ +HRESULT Initialize(bool fGui = false); + +/** + * Shuts down the COM runtime. + * Must be called on the main thread before termination. + * No COM calls may be made in any thread after this method returns. + */ +HRESULT Shutdown(); + +/** + * Resolves a given interface ID to a string containing the interface name. + * If, for some reason, the given IID cannot be resolved to a name, a NULL + * string is returned. A non-NULL string returned by this function must be + * freed using SysFreeString(). + * + * @param aIID ID of the interface to get a name for + * @param aName Resolved interface name or @c NULL on error + */ +void GetInterfaceNameByIID(const GUID &aIID, BSTR *aName); + +/** + * Returns the VirtualBox user home directory. + * + * On failure, this function will return a path that caused a failure (or + * NULL if the failure is not path-related). + * + * On success, this function will try to create the returned directory if it + * doesn't exist yet. This may also fail with the corresponding status code. + * + * If @a aDirLen is smaller than RTPATH_MAX then there is a great chance that + * this method will return VERR_BUFFER_OVERFLOW. + * + * @param aDir Buffer to store the directory string in UTF-8 encoding. + * @param aDirLen Length of the supplied buffer including space for the + * terminating null character, in bytes. + * @param fCreateDir Flag whether to create the returned directory on success if it + * doesn't exist. + * @return VBox status code. + */ +int GetVBoxUserHomeDirectory(char *aDir, size_t aDirLen, bool fCreateDir = true); + +/** + * Creates a release log file, used both in VBoxSVC and in API clients. + * + * @param pcszEntity Human readable name of the program. + * @param pcszLogFile Name of the release log file. + * @param fFlags Logger instance flags. + * @param pcszGroupSettings Group logging settings. + * @param pcszEnvVarBase Base environment variable name for the logger. + * @param fDestFlags Logger destination flags. + * @param cMaxEntriesPerGroup Limit for log entries per group. UINT32_MAX for no limit. + * @param cHistory Number of old log files to keep. + * @param uHistoryFileTime Maximum amount of time to put in a log file. + * @param uHistoryFileSize Maximum size of a log file before rotating. + * @param pszError In case of creation failure: buffer for error message. + * @param cbError Size of error message buffer. + * @return VBox status code. + */ +int VBoxLogRelCreate(const char *pcszEntity, const char *pcszLogFile, + uint32_t fFlags, const char *pcszGroupSettings, + const char *pcszEnvVarBase, uint32_t fDestFlags, + uint32_t cMaxEntriesPerGroup, uint32_t cHistory, + uint32_t uHistoryFileTime, uint64_t uHistoryFileSize, + char *pszError, size_t cbError); + +} /* namespace com */ + +#endif + diff --git a/include/VBox/com/defs.h b/include/VBox/com/defs.h new file mode 100644 index 00000000..aa9800dd --- /dev/null +++ b/include/VBox/com/defs.h @@ -0,0 +1,549 @@ +/** @file + * MS COM / XPCOM Abstraction Layer: + * Common definitions + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_com_defs_h +#define ___VBox_com_defs_h + +/* Make sure all the stdint.h macros are included - must come first! */ +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#if defined (RT_OS_OS2) + +# if defined(RT_MAX) && RT_MAX != 22 +# undef RT_MAX +# define REDEFINE_RT_MAX +# endif +# undef RT_MAX + +/* Make sure OS/2 Toolkit headers are pulled in to have BOOL/ULONG/etc. typedefs + * already defined in order to be able to redefine them using #define. */ +# define INCL_BASE +# define INCL_PM +# include <os2.h> + +/* OS/2 Toolkit defines TRUE and FALSE */ +# undef FALSE +# undef TRUE + +/* */ +# undef RT_MAX +# ifdef REDEFINE_RT_MAX +# define RT_MAX(Value1, Value2) ( (Value1) >= (Value2) ? (Value1) : (Value2) ) +# endif + +#endif /* defined (RT_OS_OS2) */ + +/* Include iprt/types.h (which also includes iprt/types.h) now to make sure iprt + * gets to stdint.h first, otherwise a system/xpcom header might beat us and + * we'll be without the macros that are optional in C++. */ +#include <iprt/types.h> + +#if !defined (VBOX_WITH_XPCOM) + +#if defined (RT_OS_WINDOWS) + +// Windows COM +///////////////////////////////////////////////////////////////////////////// + +#include <objbase.h> +#ifndef VBOX_COM_NO_ATL +# define _ATL_FREE_THREADED + +# include <atlbase.h> +#include <atlcom.h> +#endif + +#define NS_DECL_ISUPPORTS +#define NS_IMPL_ISUPPORTS1_CI(a, b) + +/* these are XPCOM only, one for every interface implemented */ +#define NS_DECL_ISUPPORTS + +/** Returns @c true if @a rc represents a warning result code */ +#define SUCCEEDED_WARNING(rc) (SUCCEEDED (rc) && (rc) != S_OK) + +/** Tests is a COM result code indicates that the process implementing the + * interface is dead. + * + * COM status codes: + * 0x800706ba - RPC_S_SERVER_UNAVAILABLE. Killed before call was made. + * 0x800706be - RPC_S_CALL_FAILED. Killed after call was made. + * 0x800706bf - RPC_S_CALL_FAILED_DNE. Not observed, but should be matter of timing. + */ +#define FAILED_DEAD_INTERFACE(rc) \ + ( (rc) == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) \ + || (rc) == HRESULT_FROM_WIN32(RPC_S_CALL_FAILED) \ + || (rc) == HRESULT_FROM_WIN32(RPC_S_CALL_FAILED_DNE) \ + ) + +/** Immutable BSTR string */ +typedef const OLECHAR *CBSTR; + +/** Input BSTR argument of interface method declaration. */ +#define IN_BSTR BSTR + +/** Input GUID argument of interface method declaration. */ +#define IN_GUID GUID +/** Output GUID argument of interface method declaration. */ +#define OUT_GUID GUID* + +/** Makes the name of the getter interface function (n must be capitalized). */ +#define COMGETTER(n) get_##n +/** Makes the name of the setter interface function (n must be capitalized). */ +#define COMSETTER(n) put_##n + +/** + * Declares an input safearray parameter in the COM method implementation. Also + * used to declare the COM attribute setter parameter. Corresponds to either of + * the following XIDL definitions: + * <pre> + * <param name="arg" ... dir="in" safearray="yes"/> + * ... + * <attribute name="arg" ... safearray="yes"/> + * </pre> + * + * The method implementation should use the com::SafeArray helper class to work + * with parameters declared using this define. + * + * @param aType Array element type. + * @param aArg Parameter/attribute name. + */ +#define ComSafeArrayIn(aType, aArg) SAFEARRAY *aArg + +/** + * Expands to @true if the given input safearray parameter is a "null pointer" + * which makes it impossible to use it for reading safearray data. + */ +#define ComSafeArrayInIsNull(aArg) ((aArg) == NULL) + +/** + * Wraps the given parameter name to generate an expression that is suitable for + * passing the parameter to functions that take input safearray parameters + * declared using the ComSafeArrayIn marco. + * + * @param aArg Parameter name to wrap. The given parameter must be declared + * within the calling function using the ComSafeArrayIn macro. + */ +#define ComSafeArrayInArg(aArg) aArg + +/** + * Declares an output safearray parameter in the COM method implementation. Also + * used to declare the COM attribute getter parameter. Corresponds to either of + * the following XIDL definitions: + * <pre> + * <param name="arg" ... dir="out" safearray="yes"/> + * <param name="arg" ... dir="return" safearray="yes"/> + * ... + * <attribute name="arg" ... safearray="yes"/> + * </pre> + * + * The method implementation should use the com::SafeArray helper class to work + * with parameters declared using this define. + * + * @param aType Array element type. + * @param aArg Parameter/attribute name. + */ +#define ComSafeArrayOut(aType, aArg) SAFEARRAY **aArg + +/** + * Expands to @true if the given output safearray parameter is a "null pointer" + * which makes it impossible to use it for returning a safearray. + */ +#define ComSafeArrayOutIsNull(aArg) ((aArg) == NULL) + +/** + * Wraps the given parameter name to generate an expression that is suitable for + * passing the parameter to functions that take output safearray parameters + * declared using the ComSafeArrayOut marco. + * + * @param aArg Parameter name to wrap. The given parameter must be declared + * within the calling function using the ComSafeArrayOut macro. + */ +#define ComSafeArrayOutArg(aArg) aArg + +/** + * Version of ComSafeArrayIn for GUID. + * @param aArg Parameter name to wrap. + */ +#define ComSafeGUIDArrayIn(aArg) SAFEARRAY *aArg + +/** + * Version of ComSafeArrayInIsNull for GUID. + * @param aArg Parameter name to wrap. + */ +#define ComSafeGUIDArrayInIsNull(aArg) ComSafeArrayInIsNull (aArg) + +/** + * Version of ComSafeArrayInArg for GUID. + * @param aArg Parameter name to wrap. + */ +#define ComSafeGUIDArrayInArg(aArg) ComSafeArrayInArg (aArg) + +/** + * Version of ComSafeArrayOut for GUID. + * @param aArg Parameter name to wrap. + */ +#define ComSafeGUIDArrayOut(aArg) SAFEARRAY **aArg + +/** + * Version of ComSafeArrayOutIsNull for GUID. + * @param aArg Parameter name to wrap. + */ +#define ComSafeGUIDArrayOutIsNull(aArg) ComSafeArrayOutIsNull (aArg) + +/** + * Version of ComSafeArrayOutArg for GUID. + * @param aArg Parameter name to wrap. + */ +#define ComSafeGUIDArrayOutArg(aArg) ComSafeArrayOutArg (aArg) + +/** + * Returns the const reference to the IID (i.e., |const GUID &|) of the given + * interface. + * + * @param i interface class + */ +#define COM_IIDOF(I) _ATL_IIDOF(I) + +/** + * For using interfaces before including the interface definitions. This will + * deal with XPCOM using 'class' and COM using 'struct' when defining + * interfaces. + * + * @param I interface name. + */ +#define COM_STRUCT_OR_CLASS(I) struct I + +#else /* defined (RT_OS_WINDOWS) */ + +#error "VBOX_WITH_XPCOM must be defined on a platform other than Windows!" + +#endif /* defined (RT_OS_WINDOWS) */ + +#else /* !defined (VBOX_WITH_XPCOM) */ + +// XPCOM +///////////////////////////////////////////////////////////////////////////// + +#if defined (RT_OS_DARWIN) || (defined (QT_VERSION) && (QT_VERSION >= 0x040000)) + /* CFBase.h defines these & + * qglobal.h from Qt4 defines these */ +# undef FALSE +# undef TRUE +#endif /* RT_OS_DARWIN || QT_VERSION */ + +#include <nsID.h> + +#define ATL_NO_VTABLE +#define DECLARE_CLASSFACTORY(a) +#define DECLARE_CLASSFACTORY_SINGLETON(a) +#define DECLARE_REGISTRY_RESOURCEID(a) +#define DECLARE_NOT_AGGREGATABLE(a) +#define DECLARE_PROTECT_FINAL_CONSTRUCT() +#define BEGIN_COM_MAP(a) +#define COM_INTERFACE_ENTRY(a) +#define COM_INTERFACE_ENTRY2(a,b) +#define END_COM_MAP() NS_DECL_ISUPPORTS +#define COM_INTERFACE_ENTRY_AGGREGATE(a,b) + +#define HRESULT nsresult +#define SUCCEEDED NS_SUCCEEDED +#define FAILED NS_FAILED + +#define SUCCEEDED_WARNING(rc) (NS_SUCCEEDED (rc) && (rc) != NS_OK) + +#define FAILED_DEAD_INTERFACE(rc) ( (rc) == NS_ERROR_ABORT \ + || (rc) == NS_ERROR_CALL_FAILED \ + ) + +#define IUnknown nsISupports + +#define BOOL PRBool +#define BYTE PRUint8 +#define SHORT PRInt16 +#define USHORT PRUint16 +#define LONG PRInt32 +#define ULONG PRUint32 +#define LONG64 PRInt64 +#define ULONG64 PRUint64 +/* XPCOM has only 64bit floats */ +#define FLOAT PRFloat64 +#define DOUBLE PRFloat64 + +#define FALSE PR_FALSE +#define TRUE PR_TRUE + +#define OLECHAR wchar_t + +/* note: typedef to semantically match BSTR on Win32 */ +typedef PRUnichar *BSTR; +typedef const PRUnichar *CBSTR; +typedef BSTR *LPBSTR; + +/** Input BSTR argument the interface method declaration. */ +#define IN_BSTR CBSTR + +/** + * Type to define a raw GUID variable (for members use the com::Guid class + * instead). + */ +#define GUID nsID +/** Input GUID argument the interface method declaration. */ +#define IN_GUID const nsID & +/** Output GUID argument the interface method declaration. */ +#define OUT_GUID nsID ** + +/** Makes the name of the getter interface function (n must be capitalized). */ +#define COMGETTER(n) Get##n +/** Makes the name of the setter interface function (n must be capitalized). */ +#define COMSETTER(n) Set##n + +/* safearray input parameter macros */ +#define ComSafeArrayIn(aType, aArg) PRUint32 aArg##Size, aType *aArg +#define ComSafeArrayInIsNull(aArg) ((aArg) == NULL) +#define ComSafeArrayInArg(aArg) aArg##Size, aArg + +/* safearray output parameter macros */ +#define ComSafeArrayOut(aType, aArg) PRUint32 *aArg##Size, aType **aArg +#define ComSafeArrayOutIsNull(aArg) ((aArg) == NULL) +#define ComSafeArrayOutArg(aArg) aArg##Size, aArg + +/* safearray input parameter macros for GUID */ +#define ComSafeGUIDArrayIn(aArg) PRUint32 aArg##Size, const nsID **aArg +#define ComSafeGUIDArrayInIsNull(aArg) ComSafeArrayInIsNull (aArg) +#define ComSafeGUIDArrayInArg(aArg) ComSafeArrayInArg (aArg) + +/* safearray output parameter macros for GUID */ +#define ComSafeGUIDArrayOut(aArg) PRUint32 *aArg##Size, nsID ***aArg +#define ComSafeGUIDArrayOutIsNull(aArg) ComSafeArrayOutIsNull (aArg) +#define ComSafeGUIDArrayOutArg(aArg) ComSafeArrayOutArg (aArg) + +/* CLSID and IID for compatibility with Win32 */ +typedef nsCID CLSID; +typedef nsIID IID; + +/* OLE error codes */ +#define S_OK ((nsresult) NS_OK) +#define E_UNEXPECTED NS_ERROR_UNEXPECTED +#define E_NOTIMPL NS_ERROR_NOT_IMPLEMENTED +#define E_OUTOFMEMORY NS_ERROR_OUT_OF_MEMORY +#define E_INVALIDARG NS_ERROR_INVALID_ARG +#define E_NOINTERFACE NS_ERROR_NO_INTERFACE +#define E_POINTER NS_ERROR_NULL_POINTER +#define E_ABORT NS_ERROR_ABORT +#define E_FAIL NS_ERROR_FAILURE +/* Note: a better analog for E_ACCESSDENIED would probably be + * NS_ERROR_NOT_AVAILABLE, but we want binary compatibility for now. */ +#define E_ACCESSDENIED ((nsresult) 0x80070005L) + +#define STDMETHOD(a) NS_IMETHOD a +#define STDMETHODIMP NS_IMETHODIMP + +#define COM_IIDOF(I) NS_GET_IID(I) + +#define COM_STRUCT_OR_CLASS(I) class I + +/* A few very simple ATL emulator classes to provide + * FinalConstruct()/FinalRelease() functionality on Linux. */ + +class CComMultiThreadModel +{ +}; + +template <class Base> class CComObjectRootEx : public Base +{ +public: + HRESULT FinalConstruct() { return S_OK; } + void FinalRelease() {} +}; + +template <class Base> class CComObject : public Base +{ +public: + virtual ~CComObject() { this->FinalRelease(); } +}; + +/* helper functions */ +extern "C" +{ +BSTR SysAllocString (const OLECHAR* sz); +BSTR SysAllocStringByteLen (char *psz, unsigned int len); +BSTR SysAllocStringLen (const OLECHAR *pch, unsigned int cch); +void SysFreeString (BSTR bstr); +int SysReAllocString (BSTR *pbstr, const OLECHAR *psz); +int SysReAllocStringLen (BSTR *pbstr, const OLECHAR *psz, unsigned int cch); +unsigned int SysStringByteLen (BSTR bstr); +unsigned int SysStringLen (BSTR bstr); +} + +/** + * 'Constructor' for the component class. + * This constructor, as opposed to NS_GENERIC_FACTORY_CONSTRUCTOR, + * assumes that the component class is derived from the CComObjectRootEx<> + * template, so it calls FinalConstruct() right after object creation + * and ensures that FinalRelease() will be called right before destruction. + * The result from FinalConstruct() is returned to the caller. + */ +#define NS_GENERIC_FACTORY_CONSTRUCTOR_WITH_RC(_InstanceClass) \ +static NS_IMETHODIMP \ +_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ + void **aResult) \ +{ \ + nsresult rv; \ + \ + *aResult = NULL; \ + if (NULL != aOuter) { \ + rv = NS_ERROR_NO_AGGREGATION; \ + return rv; \ + } \ + \ + CComObject <_InstanceClass> *inst = new CComObject <_InstanceClass>(); \ + if (NULL == inst) { \ + rv = NS_ERROR_OUT_OF_MEMORY; \ + return rv; \ + } \ + \ + NS_ADDREF(inst); /* protect FinalConstruct() */ \ + rv = inst->FinalConstruct(); \ + if (NS_SUCCEEDED(rv)) \ + rv = inst->QueryInterface(aIID, aResult); \ + NS_RELEASE(inst); \ + \ + return rv; \ +} + +/** + * 'Constructor' that uses an existing getter function that gets a singleton. + * The getter function must have the following prototype: + * nsresult _GetterProc (_InstanceClass **inst) + * This constructor, as opposed to NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR, + * lets the getter function return a result code that is passed back to the + * caller that tries to instantiate the object. + * NOTE: assumes that getter does an AddRef - so additional AddRef is not done. + */ +#define NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR_WITH_RC(_InstanceClass, _GetterProc) \ +static NS_IMETHODIMP \ +_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ + void **aResult) \ +{ \ + nsresult rv; \ + \ + _InstanceClass * inst = NULL; /* initialized to shut up gcc */ \ + \ + *aResult = NULL; \ + if (NULL != aOuter) { \ + rv = NS_ERROR_NO_AGGREGATION; \ + return rv; \ + } \ + \ + rv = _GetterProc(&inst); \ + if (NS_FAILED(rv)) \ + return rv; \ + \ + /* sanity check */ \ + if (NULL == inst) \ + return NS_ERROR_OUT_OF_MEMORY; \ + \ + /* NS_ADDREF(inst); */ \ + if (NS_SUCCEEDED(rv)) { \ + rv = inst->QueryInterface(aIID, aResult); \ + } \ + NS_RELEASE(inst); \ + \ + return rv; \ +} + +#endif /* !defined (VBOX_WITH_XPCOM) */ + +/** + * Declares a wchar_t string literal from the argument. + * Necessary to overcome MSC / GCC differences. + * @param s expression to stringify + */ +#if defined (_MSC_VER) +# define WSTR_LITERAL(s) L#s +#elif defined (__GNUC__) +# define WSTR_LITERAL(s) L""#s +#else +# error "Unsupported compiler!" +#endif + +namespace com +{ + +// use this macro to implement scriptable interfaces +#ifdef RT_OS_WINDOWS +#define VBOX_SCRIPTABLE_IMPL(iface) \ + public IDispatchImpl<iface, &IID_##iface, &LIBID_VirtualBox, \ + kTypeLibraryMajorVersion, kTypeLibraryMinorVersion> + +#define VBOX_SCRIPTABLE_DISPATCH_IMPL(iface) \ + STDMETHOD(QueryInterface)(REFIID riid , void **ppObj) \ + { \ + if (riid == IID_##iface) \ + { \ + *ppObj = (iface*)this; \ + AddRef(); \ + return S_OK; \ + } \ + if (riid == IID_IUnknown) \ + { \ + *ppObj = (IUnknown*)this; \ + AddRef(); \ + return S_OK; \ + } \ + if (riid == IID_IDispatch) \ + { \ + *ppObj = (IDispatch*)this; \ + AddRef(); \ + return S_OK; \ + } \ + *ppObj = NULL; \ + return E_NOINTERFACE; \ + } + + +#define VBOX_DEFAULT_INTERFACE_ENTRIES(iface) \ + COM_INTERFACE_ENTRY(ISupportErrorInfo) \ + COM_INTERFACE_ENTRY(iface) \ + COM_INTERFACE_ENTRY2(IDispatch,iface) \ + COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pUnkMarshaler.p) +#else +#define VBOX_SCRIPTABLE_IMPL(iface) \ + public iface +#define VBOX_SCRIPTABLE_DISPATCH_IMPL(iface) +#define VBOX_DEFAULT_INTERFACE_ENTRIES(iface) +#endif + + +} /* namespace com */ + +#endif /* ___VBox_com_defs_h */ diff --git a/include/VBox/com/errorprint.h b/include/VBox/com/errorprint.h new file mode 100644 index 00000000..2ee11676 --- /dev/null +++ b/include/VBox/com/errorprint.h @@ -0,0 +1,261 @@ +/** @file + * MS COM / XPCOM Abstraction Layer: + * Error printing macros using shared functions defined in shared glue code. + * Use these CHECK_* macros for efficient error checking around calling COM methods. + */ + +/* + * Copyright (C) 2009 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_com_errorprint_h +#define ___VBox_com_errorprint_h + +#include <VBox/com/ErrorInfo.h> + +namespace com +{ + +// shared prototypes; these are defined in shared glue code and are +// compiled only once for all front-ends +void GluePrintErrorInfo(const com::ErrorInfo &info); +void GluePrintErrorContext(const char *pcszContext, const char *pcszSourceFile, uint32_t ulLine); +void GluePrintRCMessage(HRESULT rc); +void GlueHandleComError(ComPtr<IUnknown> iface, + const char *pcszContext, + HRESULT rc, + const char *pcszSourceFile, + uint32_t ulLine); +void GlueHandleComErrorProgress(ComPtr<IProgress> progress, + const char *pcszContext, + HRESULT rc, + const char *pcszSourceFile, + uint32_t ulLine); + +/** + * Calls the given method of the given interface and then checks if the return + * value (COM result code) indicates a failure. If so, prints the failed + * function/line/file, the description of the result code and attempts to + * query the extended error information on the current thread (using + * com::ErrorInfo) if the interface reports that it supports error information. + * + * Used by command line tools or for debugging and assumes the |HRESULT rc| + * variable is accessible for assigning in the current scope. + */ +#define CHECK_ERROR(iface, method) \ + do { \ + rc = iface->method; \ + if (FAILED(rc)) \ + com::GlueHandleComError(iface, #method, rc, __FILE__, __LINE__); \ + } while (0) + +/** + * Same as CHECK_ERROR except that it also executes the statement |stmt| on + * failure. + */ +#define CHECK_ERROR_STMT(iface, method, stmt) \ + do { \ + rc = iface->method; \ + if (FAILED(rc)) \ + { \ + com::GlueHandleComError(iface, #method, rc, __FILE__, __LINE__); \ + stmt; \ + } \ + } while (0) + +/** + * Same as CHECK_ERROR_STMT except that it uses an internal variable |hrcCheck| + * for holding the result. + */ +#define CHECK_ERROR2_STMT(iface, method, stmt) \ + do { \ + HRESULT hrcCheck = iface->method; \ + if (FAILED(hrcCheck)) \ + { \ + com::GlueHandleComError(iface, #method, hrcCheck, __FILE__, __LINE__); \ + stmt; \ + } \ + } while (0) + + +/** + * Does the same as CHECK_ERROR(), but executes the |break| statement on + * failure. + */ +#ifdef __GNUC__ +# define CHECK_ERROR_BREAK(iface, method) \ + __extension__ \ + ({ \ + rc = iface->method; \ + if (FAILED(rc)) \ + { \ + com::GlueHandleComError(iface, #method, rc, __FILE__, __LINE__); \ + break; \ + } \ + }) +#else +# define CHECK_ERROR_BREAK(iface, method) \ + if (1) \ + { \ + rc = iface->method; \ + if (FAILED(rc)) \ + { \ + com::GlueHandleComError(iface, #method, rc, __FILE__, __LINE__); \ + break; \ + } \ + } \ + else do {} while (0) +#endif + +/** + * Does the same as CHECK_ERROR(), but executes the |return ret| statement on + * failure. + */ +#define CHECK_ERROR_RET(iface, method, ret) \ + do { \ + rc = iface->method; \ + if (FAILED(rc)) \ + { \ + com::GlueHandleComError(iface, #method, rc, __FILE__, __LINE__); \ + return (ret); \ + } \ + } while (0) + +/** + * Does the same as CHECK_ERROR(), but returns @a ret on failure. + * + * Unlike CHECK_ERROR and CHECK_ERROR_RET, this macro does not presuppose a + * |rc| variable but instead employs a local variable |hrcCheck| in its own + * scope. This |hrcCheck| variable can be referenced by the @a rcRet + * parameter. + * + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @param rcRet What to return on failure. Use |hrcCheck| to return + * the status code of the method call. + */ +#define CHECK_ERROR2_RET(iface, method, rcRet) \ + do { \ + HRESULT hrcCheck = iface->method; \ + if (FAILED(hrcCheck)) \ + { \ + com::GlueHandleComError(iface, #method, hrcCheck, __FILE__, __LINE__); \ + return (rcRet); \ + } \ + } while (0) + + +/** + * Check the progress object for an error and if there is one print out the + * extended error information. + */ +#define CHECK_PROGRESS_ERROR(progress, msg) \ + do { \ + LONG iRc; \ + rc = progress->COMGETTER(ResultCode)(&iRc); \ + if (FAILED(iRc)) \ + { \ + rc = iRc; \ + RTMsgError msg; \ + com::GlueHandleComErrorProgress(progress, __PRETTY_FUNCTION__, iRc, __FILE__, __LINE__); \ + } \ + } while (0) + +/** + * Does the same as CHECK_PROGRESS_ERROR(), but executes the |break| statement + * on failure. + */ +#ifdef __GNUC__ +# define CHECK_PROGRESS_ERROR_BREAK(progress, msg) \ + __extension__ \ + ({ \ + LONG iRc; \ + rc = progress->COMGETTER(ResultCode)(&iRc); \ + if (FAILED(iRc)) \ + { \ + rc = iRc; \ + RTMsgError msg; \ + com::GlueHandleComErrorProgress(progress, __PRETTY_FUNCTION__, iRc, __FILE__, __LINE__); \ + break; \ + } \ + }) +#else +# define CHECK_PROGRESS_ERROR_BREAK(progress, msg) \ + if (1) \ + { \ + LONG iRc; \ + rc = progress->COMGETTER(ResultCode)(&iRc); \ + if (FAILED(iRc)) \ + { \ + rc = iRc; \ + RTMsgError msg; \ + com::GlueHandleComErrorProgress(progress, __PRETTY_FUNCTION__, iRc, __FILE__, __LINE__); \ + break; \ + } \ + } \ + else do {} while (0) +#endif + +/** + * Does the same as CHECK_PROGRESS_ERROR(), but executes the |return ret| + * statement on failure. + */ +#define CHECK_PROGRESS_ERROR_RET(progress, msg, ret) \ + do { \ + LONG iRc; \ + progress->COMGETTER(ResultCode)(&iRc); \ + if (FAILED(iRc)) \ + { \ + RTMsgError msg; \ + com::GlueHandleComErrorProgress(progress, __PRETTY_FUNCTION__, iRc, __FILE__, __LINE__); \ + return (ret); \ + } \ + } while (0) + +/** + * Asserts the given expression is true. When the expression is false, prints + * a line containing the failed function/line/file; otherwise does nothing. + */ +#define ASSERT(expr) \ + do { \ + if (!(expr)) \ + { \ + RTPrintf ("[!] ASSERTION FAILED at line %d: %s\n", __LINE__, #expr); \ + Log (("[!] ASSERTION FAILED at line %d: %s\n", __LINE__, #expr)); \ + } \ + } while (0) + +#endif + +/** + * Does the same as ASSERT(), but executes the |return ret| statement if the + * expression to assert is false; + */ +#define ASSERT_RET(expr, ret) \ + do { ASSERT(expr); if (!(expr)) return (ret); } while (0) + +/** + * Does the same as ASSERT(), but executes the |break| statement if the + * expression to assert is false; + */ +#define ASSERT_BREAK(expr, ret) \ + if (1) { ASSERT(expr); if (!(expr)) break; } else do {} while (0) + +} /* namespace com */ diff --git a/include/VBox/com/list.h b/include/VBox/com/list.h new file mode 100644 index 00000000..11a137b5 --- /dev/null +++ b/include/VBox/com/list.h @@ -0,0 +1,197 @@ +/* $Id: list.h $ */ +/** @file + * MS COM / XPCOM Abstraction Layer - List classes declaration. + */ + +/* + * Copyright (C) 2011 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_com_list_h +#define ___VBox_com_list_h + +#include <VBox/com/ptr.h> +#include <VBox/com/string.h> +#include <iprt/cpp/list.h> + +/** + * Specialized list class for using with com::ComPtr<C> + * + * @note: This is necessary cause ComPtr<IFACE> has a size of 8. + */ +template <typename C> +class RTCList< ComPtr<C> >: public RTCListBase< ComPtr<C>, ComPtr<C>*, false> +{ + /* Traits */ + typedef ComPtr<C> T; + typedef T *ITYPE; + static const bool MT = false; + typedef RTCListBase<T, ITYPE, MT> BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacitiy The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCList(size_t cCapacity = BASE::DefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** + * Specialized list class for using with com::ComObjPtr<C> + * + * @note: This is necessary cause ComObjPtr<IFACE> has a size of 8. + */ +template <typename C> +class RTCList< ComObjPtr<C> >: public RTCListBase< ComObjPtr<C>, ComObjPtr<C>*, false> +{ + /* Traits */ + typedef ComObjPtr<C> T; + typedef T *ITYPE; + static const bool MT = false; + typedef RTCListBase<T, ITYPE, MT> BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacitiy The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCList(size_t cCapacity = BASE::DefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** + * Specialized list class for using with com::Utf8Str. + * + * The class offers methods for importing com::SafeArray's of com::Bstr's. + */ +template <> +class RTCList<Utf8Str>: public RTCListBase<Utf8Str, Utf8Str*, false> +{ + /* Traits */ + typedef Utf8Str T; + typedef T *ITYPE; + static const bool MT = false; + typedef RTCListBase<T, ITYPE, MT> BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacitiy The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCList(size_t cCapacity = BASE::DefaultCapacity) + : BASE(cCapacity) {} + + /** + * Creates a copy of another list. + * + * The other list will be fully copied and the capacity will be the same as + * the size of the other list. The com::Bstr's are silently converted to + * com::Utf8Str's. + * + * @param other The list to copy. + * @throws std::bad_alloc + */ + RTCList(ComSafeArrayIn(IN_BSTR, other)) + { + com::SafeArray<IN_BSTR> sfaOther(ComSafeArrayInArg(other)); + realloc(sfaOther.size()); + m_cSize = sfaOther.size(); + for (size_t i = 0; i < m_cSize; ++i) + RTCListHelper<T, ITYPE>::set(m_pArray, i, T(sfaOther[i])); + } + + /** + * Creates a copy of another list. + * + * The other list will be fully copied and the capacity will be the same as + * the size of the other list. The com::Bstr's are silently converted to + * com::Utf8Str's. + * + * @param other The list to copy. + * @throws std::bad_alloc + */ + RTCList(const com::SafeArray<IN_BSTR> &other) + : BASE(other.size()) + { + for (size_t i = 0; i < m_cSize; ++i) + RTCListHelper<T, ITYPE>::set(m_pArray, i, T(other[i])); + } + + /** + * Copy the items of the other list into this list. All previous items of + * this list are deleted. + * + * @param other The list to copy. + * @return a reference to this list. + * @throws std::bad_alloc + */ + RTCListBase<T, ITYPE, MT> &operator=(const com::SafeArray<IN_BSTR> &other) + { + m_guard.enterWrite(); + /* Values cleanup */ + RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cSize); + /* Copy */ + if (other.size() != m_cCapacity) + realloc_no_elements_clean(other.size()); + m_cSize = other.size(); + for (size_t i = 0; i < other.size(); ++i) + RTCListHelper<T, ITYPE>::set(m_pArray, i, T(other[i])); + m_guard.leaveWrite(); + + return *this; + } + + /** + * Implicit conversion to a RTCString list. + * + * This allows the usage of the RTCString::join method with this list type. + * + * @return a converted const reference to this list. + */ + operator const RTCList<RTCString, RTCString*>&() + { + return *reinterpret_cast<RTCList<RTCString, RTCString*> *>(this); + } + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +#endif /* !___VBox_com_list_h */ + diff --git a/include/VBox/com/listeners.h b/include/VBox/com/listeners.h new file mode 100644 index 00000000..419b18fa --- /dev/null +++ b/include/VBox/com/listeners.h @@ -0,0 +1,171 @@ +/* $Id: listeners.h $ */ +/** @file + * Listeners helpers. + */ + +/* + * Copyright (C) 2010-2011 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_com_listeners_h +#define ___VBox_com_listeners_h + +#include <VBox/com/com.h> +#include <VBox/com/VirtualBox.h> + +#ifdef VBOX_WITH_XPCOM +# define NS_IMPL_QUERY_HEAD_INLINE() \ +NS_IMETHODIMP QueryInterface(REFNSIID aIID, void **aInstancePtr) \ +{ \ + NS_ASSERTION(aInstancePtr, "QueryInterface requires a non-NULL destination!"); \ + nsISupports *foundInterface; + +# define NS_INTERFACE_MAP_BEGIN_INLINE() NS_IMPL_QUERY_HEAD_INLINE() + +# define NS_IMPL_QUERY_INTERFACE1_INLINE(a_i1) \ + NS_INTERFACE_MAP_BEGIN_INLINE() \ + NS_INTERFACE_MAP_ENTRY(a_i1) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, a_i1) \ + NS_INTERFACE_MAP_END +#endif + +template <class T, class TParam = void *> +class ListenerImpl : + public CComObjectRootEx<CComMultiThreadModel>, + VBOX_SCRIPTABLE_IMPL(IEventListener) +{ + T* mListener; + +#ifdef RT_OS_WINDOWS + /* FTM stuff */ + CComPtr <IUnknown> m_pUnkMarshaler; +#else + nsAutoRefCnt mRefCnt; + NS_DECL_OWNINGTHREAD +#endif + +public: + ListenerImpl() + { + } + + virtual ~ListenerImpl() + { + } + + HRESULT init(T* aListener, TParam param) + { + mListener = aListener; + return mListener->init(param); + } + + HRESULT init(T* aListener) + { + mListener = aListener; + return mListener->init(); + } + + void uninit() + { + if (mListener) + { + mListener->uninit(); + delete mListener; + mListener = 0; + } + } + + HRESULT FinalConstruct() + { +#ifdef RT_OS_WINDOWS + return CoCreateFreeThreadedMarshaler(this, &m_pUnkMarshaler.p); +#else + return S_OK; +#endif + } + + void FinalRelease() + { + uninit(); +#ifdef RT_OS_WINDOWS + m_pUnkMarshaler.Release(); +#endif + } + + T* getWrapped() + { + return mListener; + } + + DECLARE_NOT_AGGREGATABLE(ListenerImpl) + + DECLARE_PROTECT_FINAL_CONSTRUCT() + +#ifdef RT_OS_WINDOWS + BEGIN_COM_MAP(ListenerImpl) + COM_INTERFACE_ENTRY(IEventListener) + COM_INTERFACE_ENTRY2(IDispatch, IEventListener) + COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pUnkMarshaler.p) + END_COM_MAP() +#else + NS_IMETHOD_(nsrefcnt) AddRef(void) + { + NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); + nsrefcnt count; + count = PR_AtomicIncrement((PRInt32*)&mRefCnt); + NS_LOG_ADDREF(this, count, "ListenerImpl", sizeof(*this)); + return count; + } + + NS_IMETHOD_(nsrefcnt) Release(void) + { + nsrefcnt count; + NS_PRECONDITION(0 != mRefCnt, "dup release"); + count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); + NS_LOG_RELEASE(this, count, "ListenerImpl"); + if (0 == count) { + mRefCnt = 1; /* stabilize */ + /* enable this to find non-threadsafe destructors: */ + /* NS_ASSERT_OWNINGTHREAD(_class); */ + NS_DELETEXPCOM(this); + return 0; + } + return count; + } + + NS_IMPL_QUERY_INTERFACE1_INLINE(IEventListener) +#endif + + + STDMETHOD(HandleEvent)(IEvent * aEvent) + { + VBoxEventType_T aType = VBoxEventType_Invalid; + aEvent->COMGETTER(Type)(&aType); + return mListener->HandleEvent(aType, aEvent); + } +}; + +#ifdef VBOX_WITH_XPCOM +# define VBOX_LISTENER_DECLARE(klazz) NS_DECL_CLASSINFO(klazz) +#else +# define VBOX_LISTENER_DECLARE(klazz) +#endif + +#endif diff --git a/include/VBox/com/mtlist.h b/include/VBox/com/mtlist.h new file mode 100644 index 00000000..c4142c5f --- /dev/null +++ b/include/VBox/com/mtlist.h @@ -0,0 +1,197 @@ +/* $Id: mtlist.h $ */ +/** @file + * MS COM / XPCOM Abstraction Layer - Thread-safe list classes declaration. + */ + +/* + * Copyright (C) 2011 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_com_mtlist_h +#define ___VBox_com_mtlist_h + +#include <VBox/com/ptr.h> +#include <VBox/com/string.h> +#include <iprt/cpp/mtlist.h> + +/** + * Specialized thread-safe list class for using with com::ComPtr<C> + * + * @note: This is necessary cause ComPtr<IFACE> has a size of 8. + */ +template <typename C> +class RTCMTList< ComPtr<C> >: public RTCListBase< ComPtr<C>, ComPtr<C>*, true> +{ + /* Traits */ + typedef ComPtr<C> T; + typedef T *ITYPE; + static const bool MT = true; + typedef RTCListBase<T, ITYPE, MT> BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacitiy The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCList(size_t cCapacity = BASE::DefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** + * Specialized thread-safe list class for using with com::ComObjPtr<C> + * + * @note: This is necessary cause ComObjPtr<IFACE> has a size of 8. + */ +template <typename C> +class RTCMTList< ComObjPtr<C> >: public RTCListBase< ComObjPtr<C>, ComObjPtr<C>*, true> +{ + /* Traits */ + typedef ComObjPtr<C> T; + typedef T *ITYPE; + static const bool MT = true; + typedef RTCListBase<T, ITYPE, MT> BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacitiy The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCList(size_t cCapacity = BASE::DefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** + * Specialized thread-safe list class for using with com::Utf8Str. + * + * The class offers methods for importing com::SafeArray's of com::Bstr's. + */ +template <> +class RTCMTList<Utf8Str>: public RTCListBase<Utf8Str, Utf8Str*, true> +{ + /* Traits */ + typedef Utf8Str T; + typedef T *ITYPE; + static const bool MT = true; + typedef RTCListBase<T, ITYPE, MT> BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacitiy The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCMTList(size_t cCapacity = BASE::DefaultCapacity) + : BASE(cCapacity) {} + + /** + * Creates a copy of another list. + * + * The other list will be fully copied and the capacity will be the same as + * the size of the other list. The com::Bstr's are silently converted to + * com::Utf8Str's. + * + * @param other The list to copy. + * @throws std::bad_alloc + */ + RTCMTList(ComSafeArrayIn(IN_BSTR, other)) + { + com::SafeArray<IN_BSTR> sfaOther(ComSafeArrayInArg(other)); + realloc(sfaOther.size()); + m_cSize = sfaOther.size(); + for (size_t i = 0; i < m_cSize; ++i) + RTCListHelper<T, ITYPE>::set(m_pArray, i, T(sfaOther[i])); + } + + /** + * Creates a copy of another list. + * + * The other list will be fully copied and the capacity will be the same as + * the size of the other list. The com::Bstr's are silently converted to + * com::Utf8Str's. + * + * @param other The list to copy. + * @throws std::bad_alloc + */ + RTCMTList(const com::SafeArray<IN_BSTR> &other) + : BASE(other.size()) + { + for (size_t i = 0; i < m_cSize; ++i) + RTCListHelper<T, ITYPE>::set(m_pArray, i, T(other[i])); + } + + /** + * Copy the items of the other list into this list. All previous items of + * this list are deleted. + * + * @param other The list to copy. + * @return a reference to this list. + * @throws std::bad_alloc + */ + RTCListBase<T, ITYPE, MT> &operator=(const com::SafeArray<IN_BSTR> &other) + { + m_guard.enterWrite(); + /* Values cleanup */ + RTCListHelper<T, ITYPE>::eraseRange(m_pArray, 0, m_cSize); + /* Copy */ + if (other.size() != m_cCapacity) + realloc_no_elements_clean(other.size()); + m_cSize = other.size(); + for (size_t i = 0; i < other.size(); ++i) + RTCListHelper<T, ITYPE>::set(m_pArray, i, T(other[i])); + m_guard.leaveWrite(); + + return *this; + } + + /** + * Implicit conversion to a RTCString list. + * + * This allows the usage of the RTCString::join method with this list type. + * + * @return a converted const reference to this list. + */ + operator const RTCMTList<RTCString, RTCString*>&() + { + return *reinterpret_cast<RTCMTList<RTCString, RTCString*> *>(this); + } + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +#endif /* !___VBox_com_mtlist_h */ + diff --git a/include/VBox/com/ptr.h b/include/VBox/com/ptr.h new file mode 100644 index 00000000..1942274b --- /dev/null +++ b/include/VBox/com/ptr.h @@ -0,0 +1,493 @@ +/** @file + * MS COM / XPCOM Abstraction Layer: + * Smart COM pointer classes declaration + */ + +/* + * Copyright (C) 2006-2010 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_com_ptr_h +#define ___VBox_com_ptr_h + +/* Make sure all the stdint.h macros are included - must come first! */ +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#if !defined (VBOX_WITH_XPCOM) + #include <atlbase.h> + #ifndef _ATL_IIDOF + # define _ATL_IIDOF(c) __uuidof(c) + #endif +#else + #include <nsISupportsUtils.h> + +#endif /* !defined (VBOX_WITH_XPCOM) */ + +#include <VBox/com/defs.h> + +#ifdef VBOX_WITH_XPCOM + +namespace com +{ +// declare a couple of XPCOM helper methods (defined in glue/com.cpp) +// so we don't have to include a ton of XPCOM implementation headers here +HRESULT GlueCreateObjectOnServer(const CLSID &clsid, + const char *serverName, + const nsIID &id, + void** ppobj); +HRESULT GlueCreateInstance(const CLSID &clsid, + const nsIID &id, + void** ppobj); +} + +#endif // VBOX_WITH_XPCOM + +/** + * COM autopointer class which takes care of all required reference counting. + * + * This automatically calls the required basic COM methods on COM pointers + * given to it: + * + * -- AddRef() gets called automatically whenever a new COM pointer is assigned + * to the ComPtr instance (either in the copy constructor or by assignment); + * + * -- Release() gets called automatically by the destructor and when an existing + * object gets released in assignment; + * + * -- QueryInterface() gets called automatically when COM pointers get converted + * from one interface to another. + * + * Example usage: + * + * @code + * + * { + * ComPtr<IMachine> pMachine = findMachine("blah"); // calls AddRef() + * ComPtr<IUnknown> pUnknown = pMachine; // calls QueryInterface() + * } # ComPtr destructor of both instances calls Release() + * + * @endcode + */ +template <class T> +class ComPtr +{ +public: + + /** + * Default constructor, sets up a NULL pointer. + */ + ComPtr() + : m_p(NULL) + { } + + /** + * Destructor. Calls Release() on the contained COM object. + */ + ~ComPtr() + { + cleanup(); + } + + /** + * Copy constructor from another ComPtr of any interface. + * + * This calls QueryInterface(T) and can result in a NULL pointer if the input + * pointer p does not support the ComPtr interface T. + * + * Does not call AddRef explicitly because if QueryInterface succeeded, then + * the refcount will have been increased by one already . + */ + template <class T2> + ComPtr(const ComPtr<T2> &that) + { + m_p = NULL; + if (!that.isNull()) + that->QueryInterface(COM_IIDOF(T), (void**)&m_p); + } + + /** + * Specialization: copy constructor from another ComPtr<T>. Calls AddRef(). + */ + ComPtr(const ComPtr &that) + { + copyFrom(that.m_p); + } + + /** + * Copy constructor from another interface pointer of any interface. + * + * This calls QueryInterface(T) and can result in a NULL pointer if the input + * pointer p does not support the ComPtr interface T. + * + * Does not call AddRef explicitly because if QueryInterface succeeded, then + * the refcount will have been increased by one already . + */ + template <class T2> + ComPtr(T2 *p) + { + m_p = NULL; + if (p) + p->QueryInterface(COM_IIDOF(T), (void**)&m_p); + } + + /** + * Specialization: copy constructor from a plain T* pointer. Calls AddRef(). + */ + ComPtr(T *that_p) + { + copyFrom(that_p); + } + + /** + * Assignment from another ComPtr of any interface. + * + * This calls QueryInterface(T) and can result in a NULL pointer if the input + * pointer p does not support the ComPtr interface T. + * + * Does not call AddRef explicitly because if QueryInterface succeeded, then + * the refcount will have been increased by one already . + */ + template <class T2> + ComPtr& operator=(const ComPtr<T2> &that) + { + return operator=((T2*)that); + } + + /** + * Specialization of the previous: assignment from another ComPtr<T>. + * Calls Release() on the previous member pointer, if any, and AddRef() on the new one. + */ + ComPtr& operator=(const ComPtr &that) + { + return operator=((T*)that); + } + + /** + * Assignment from another interface pointer of any interface. + * + * This calls QueryInterface(T) and can result in a NULL pointer if the input + * pointer p does not support the ComPtr interface T. + * + * Does not call AddRef explicitly because if QueryInterface succeeded, then + * the refcount will have been increased by one already . + */ + template <class T2> + ComPtr& operator=(T2 *p) + { + cleanup(); + if (p) + p->QueryInterface(COM_IIDOF(T), (void**)&m_p); + return *this; + } + + /** + * Specialization of the previous: assignment from a plain T* pointer. + * Calls Release() on the previous member pointer, if any, and AddRef() on the new one. + */ + ComPtr& operator=(T *p) + { + cleanup(); + copyFrom(p); + return *this; + } + + /** + * Resets the ComPtr to NULL. Works like a NULL assignment except it avoids the templates. + */ + void setNull() + { + cleanup(); + } + + /** + * Returns true if the pointer is NULL. + */ + bool isNull() const + { + return (m_p == NULL); + } + + bool operator<(T* p) const + { + return m_p < p; + } + + /** + * Conversion operator, most often used to pass ComPtr instances as + * parameters to COM method calls. + */ + operator T*() const + { + return m_p; + } + + /** + * Dereferences the instance (redirects the -> operator to the managed + * pointer). + */ + T* operator->() const + { + return m_p; + } + + /** + * Special method which allows using a ComPtr as an output argument of a COM method. + * The ComPtr will then accept the method's interface pointer without calling AddRef() + * itself, since by COM convention this must has been done by the method which created + * the object that is being accepted. + * + * The ComPtr destructor will then still invoke Release() so that the returned object + * can get cleaned up properly. + */ + T** asOutParam() + { + cleanup(); + return &m_p; + } + + /** + * Converts the contained pointer to a different interface + * by calling QueryInterface() on it. + * @param pp + * @return + */ + template <class T2> + HRESULT queryInterfaceTo(T2 **pp) const + { + if (pp) + { + if (m_p) + return m_p->QueryInterface(COM_IIDOF(T2), (void**)pp); + else + { + *pp = NULL; + return S_OK; + } + } + + return E_INVALIDARG; + } + + /** + * Equality test operator. By COM definition, two COM objects are considered + * equal if their IUnknown interface pointers are equal. + */ + template <class T2> + bool operator==(T2* p) + { + IUnknown *p1 = NULL; + bool fNeedsRelease1 = false; + if (m_p) + fNeedsRelease1 = (SUCCEEDED(m_p->QueryInterface(COM_IIDOF(IUnknown), (void**)&p1))); + + IUnknown *p2 = NULL; + bool fNeedsRelease2 = false; + if (p) + fNeedsRelease2 = (SUCCEEDED(p->QueryInterface(COM_IIDOF(IUnknown), (void**)&p2))); + + bool f = p1 == p2; + if (fNeedsRelease1) + p1->Release(); + if (fNeedsRelease2) + p2->Release(); + return f; + } + + /** + * Creates an in-process object of the given class ID and starts to + * manage a reference to the created object in case of success. + */ + HRESULT createInprocObject(const CLSID &clsid) + { + HRESULT rc; + T *obj = NULL; +#if !defined (VBOX_WITH_XPCOM) + rc = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, _ATL_IIDOF(T), + (void**)&obj); +#else /* !defined (VBOX_WITH_XPCOM) */ + using namespace com; + rc = GlueCreateInstance(clsid, NS_GET_IID(T), (void**)&obj); +#endif /* !defined (VBOX_WITH_XPCOM) */ + *this = obj; + if (SUCCEEDED(rc)) + obj->Release(); + return rc; + } + + /** + * Creates a local (out-of-process) object of the given class ID and starts + * to manage a reference to the created object in case of success. + * + * Note: In XPCOM, the out-of-process functionality is currently emulated + * through in-process wrapper objects (that start a dedicated process and + * redirect all object requests to that process). For this reason, this + * method is fully equivalent to #createInprocObject() for now. + */ + HRESULT createLocalObject(const CLSID &clsid) + { +#if !defined (VBOX_WITH_XPCOM) + HRESULT rc; + T *obj = NULL; + rc = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, _ATL_IIDOF(T), + (void**)&obj); + *this = obj; + if (SUCCEEDED(rc)) + obj->Release(); + return rc; +#else /* !defined (VBOX_WITH_XPCOM) */ + return createInprocObject(clsid); +#endif /* !defined (VBOX_WITH_XPCOM) */ + } + +#ifdef VBOX_WITH_XPCOM + /** + * Creates an object of the given class ID on the specified server and + * starts to manage a reference to the created object in case of success. + * + * @param serverName Name of the server to create an object within. + */ + HRESULT createObjectOnServer(const CLSID &clsid, const char *serverName) + { + T *obj = NULL; + HRESULT rc = GlueCreateObjectOnServer(clsid, serverName, NS_GET_IID(T), (void**)&obj); + *this = obj; + if (SUCCEEDED(rc)) + obj->Release(); + return rc; + } +#endif + +protected: + void copyFrom(T* p) + { + m_p = p; + if (m_p) + m_p->AddRef(); + } + + void cleanup() + { + if (m_p) + { + m_p->Release(); + m_p = NULL; + } + } + + T *m_p; +}; + +/** + * ComObjPtr is a more specialized variant of ComPtr designed to be used for implementation + * objects. For example, use ComPtr<IMachine> for a client pointer that calls the interface + * but ComObjPtr<Machine> for a pointer to an implementation object. + * + * The methods behave the same except that ComObjPtr has the additional createObject() + * method which allows for instantiating a new implementation object. + * + * Note: To convert a ComObjPtr<InterfaceImpl> to a ComObj<IInterface> you have + * to query the interface. See the following example code for the IProgress + * interface: + * + * @code + * + * { + * ComObjPtr<Progress> pProgress; // create the server side object + * pProgress.createObject(); // ... + * pProgress->init(...); // ... + * ComPtr<IProgress> pProgress2; // create an interface pointer + * pProgress.queryInterfaceTo(pProgress2.asOutParam()); // transfer the interface + * } + * + * @endcode + */ +template <class T> +class ComObjPtr : public ComPtr<T> +{ +public: + + ComObjPtr() + : ComPtr<T>() + {} + + ComObjPtr(const ComObjPtr &that) + : ComPtr<T>(that) + {} + + ComObjPtr(T *that_p) + : ComPtr<T>(that_p) + {} + + ComObjPtr& operator=(const ComObjPtr &that) + { + ComPtr<T>::operator=(that); + return *this; + } + + ComObjPtr& operator=(T *that_p) + { + ComPtr<T>::operator=(that_p); + return *this; + } + + /** + * Creates a new server-side object of the given component class and + * immediately starts to manage a pointer to the created object (the + * previous pointer, if any, is of course released when appropriate). + * + * @note Win32: when VBOX_COM_OUTOFPROC_MODULE is defined, the created + * object doesn't increase the lock count of the server module, as it + * does otherwise. + */ + HRESULT createObject() + { + HRESULT rc; +#if !defined (VBOX_WITH_XPCOM) +# ifdef VBOX_COM_OUTOFPROC_MODULE + CComObjectNoLock<T> *obj = new CComObjectNoLock<T>(); + if (obj) + { + obj->InternalFinalConstructAddRef(); + rc = obj->FinalConstruct(); + obj->InternalFinalConstructRelease(); + } + else + rc = E_OUTOFMEMORY; +# else + CComObject<T> *obj = NULL; + rc = CComObject<T>::CreateInstance(&obj); +# endif +#else /* !defined (VBOX_WITH_XPCOM) */ + CComObject<T> *obj = new CComObject<T>(); + if (obj) + rc = obj->FinalConstruct(); + else + rc = E_OUTOFMEMORY; +#endif /* !defined (VBOX_WITH_XPCOM) */ + *this = obj; + return rc; + } +}; +#endif diff --git a/include/VBox/com/string.h b/include/VBox/com/string.h new file mode 100644 index 00000000..3462818e --- /dev/null +++ b/include/VBox/com/string.h @@ -0,0 +1,810 @@ +/* $Id: string.h $ */ +/** @file + * MS COM / XPCOM Abstraction Layer - Smart string classes declaration. + */ + +/* + * Copyright (C) 2006-2012 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef ___VBox_com_string_h +#define ___VBox_com_string_h + +/* Make sure all the stdint.h macros are included - must come first! */ +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#if defined(VBOX_WITH_XPCOM) +# include <nsMemory.h> +#endif + +#include "VBox/com/defs.h" +#include "VBox/com/assert.h" + +#include <iprt/mem.h> +#include <iprt/cpp/ministring.h> + +namespace com +{ + +class Utf8Str; + +// global constant in glue/string.cpp that represents an empty BSTR +extern const BSTR g_bstrEmpty; + +/** + * String class used universally in Main for COM-style Utf-16 strings. + * + * Unfortunately COM on Windows uses UTF-16 everywhere, requiring conversions + * back and forth since most of VirtualBox and our libraries use UTF-8. + * + * To make things more obscure, on Windows, a COM-style BSTR is not just a + * pointer to a null-terminated wide character array, but the four bytes (32 + * bits) BEFORE the memory that the pointer points to are a length DWORD. One + * must therefore avoid pointer arithmetic and always use SysAllocString and + * the like to deal with BSTR pointers, which manage that DWORD correctly. + * + * For platforms other than Windows, we provide our own versions of the Sys* + * functions in Main/xpcom/helpers.cpp which do NOT use length prefixes though + * to be compatible with how XPCOM allocates string parameters to public + * functions. + * + * The Bstr class hides all this handling behind a std::string-like interface + * and also provides automatic conversions to RTCString and Utf8Str instances. + * + * The one advantage of using the SysString* routines is that this makes it + * possible to use it as a type of member variables of COM/XPCOM components and + * pass their values to callers through component methods' output parameters + * using the #cloneTo() operation. Also, the class can adopt (take ownership + * of) string buffers returned in output parameters of COM methods using the + * #asOutParam() operation and correctly free them afterwards. + * + * Starting with VirtualBox 3.2, like Utf8Str, Bstr no longer differentiates + * between NULL strings and empty strings. In other words, Bstr("") and + * Bstr(NULL) behave the same. In both cases, Bstr allocates no memory, + * reports a zero length and zero allocated bytes for both, and returns an + * empty C wide string from raw(). + * + * @note All Bstr methods ASSUMES valid UTF-16 or UTF-8 input strings. + * The VirtualBox policy in this regard is to validate strings coming + * from external sources before passing them to Bstr or Utf8Str. + */ +class Bstr +{ +public: + + Bstr() + : m_bstr(NULL) + { } + + Bstr(const Bstr &that) + { + copyFrom((const OLECHAR *)that.m_bstr); + } + + Bstr(CBSTR that) + { + copyFrom((const OLECHAR *)that); + } + +#if defined(VBOX_WITH_XPCOM) + Bstr(const wchar_t *that) + { + AssertCompile(sizeof(wchar_t) == sizeof(OLECHAR)); + copyFrom((const OLECHAR *)that); + } +#endif + + Bstr(const RTCString &that) + { + copyFrom(that.c_str()); + } + + Bstr(const char *that) + { + copyFrom(that); + } + + Bstr(const char *a_pThat, size_t a_cchMax) + { + copyFromN(a_pThat, a_cchMax); + } + + ~Bstr() + { + setNull(); + } + + Bstr& operator=(const Bstr &that) + { + cleanup(); + copyFrom((const OLECHAR *)that.m_bstr); + return *this; + } + + Bstr& operator=(CBSTR that) + { + cleanup(); + copyFrom((const OLECHAR *)that); + return *this; + } + +#if defined(VBOX_WITH_XPCOM) + Bstr& operator=(const wchar_t *that) + { + cleanup(); + copyFrom((const OLECHAR *)that); + return *this; + } +#endif + + Bstr& setNull() + { + cleanup(); + return *this; + } + +#ifdef _MSC_VER +# if _MSC_VER >= 1400 + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +# endif +#else + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +#endif + + /** Case sensitivity selector. */ + enum CaseSensitivity + { + CaseSensitive, + CaseInsensitive + }; + + /** + * Compares the member string to str. + * @param str + * @param cs Whether comparison should be case-sensitive. + * @return + */ + int compare(CBSTR str, CaseSensitivity cs = CaseSensitive) const + { + if (cs == CaseSensitive) + return ::RTUtf16Cmp((PRTUTF16)m_bstr, (PRTUTF16)str); + return ::RTUtf16LocaleICmp((PRTUTF16)m_bstr, (PRTUTF16)str); + } + + int compare(BSTR str, CaseSensitivity cs = CaseSensitive) const + { + return compare((CBSTR)str, cs); + } + + int compare(const Bstr &that, CaseSensitivity cs = CaseSensitive) const + { + return compare(that.m_bstr, cs); + } + + bool operator==(const Bstr &that) const { return !compare(that.m_bstr); } + bool operator!=(const Bstr &that) const { return !!compare(that.m_bstr); } + bool operator==(CBSTR that) const { return !compare(that); } + bool operator==(BSTR that) const { return !compare(that); } + + bool operator!=(CBSTR that) const { return !!compare(that); } + bool operator!=(BSTR that) const { return !!compare(that); } + bool operator<(const Bstr &that) const { return compare(that.m_bstr) < 0; } + bool operator<(CBSTR that) const { return compare(that) < 0; } + bool operator<(BSTR that) const { return compare(that) < 0; } + + /** + * Returns true if the member string has no length. + * This is true for instances created from both NULL and "" input strings. + * + * @note Always use this method to check if an instance is empty. Do not + * use length() because that may need to run through the entire string + * (Bstr does not cache string lengths). + */ + bool isEmpty() const { return m_bstr == NULL || *m_bstr == 0; } + + /** + * Returns true if the member string has a length of one or more. + * + * @returns true if not empty, false if empty (NULL or ""). + */ + bool isNotEmpty() const { return m_bstr != NULL && *m_bstr != 0; } + + size_t length() const { return isEmpty() ? 0 : ::RTUtf16Len((PRTUTF16)m_bstr); } + +#if defined(VBOX_WITH_XPCOM) + /** + * Returns a pointer to the raw member UTF-16 string. If the member string is empty, + * returns a pointer to a global variable containing an empty BSTR with a proper zero + * length prefix so that Windows is happy. + */ + CBSTR raw() const + { + if (m_bstr) + return m_bstr; + + return g_bstrEmpty; + } +#else + /** + * Windows-only hack, as the automatically generated headers use BSTR. + * So if we don't want to cast like crazy we have to be more loose than + * on XPCOM. + * + * Returns a pointer to the raw member UTF-16 string. If the member string is empty, + * returns a pointer to a global variable containing an empty BSTR with a proper zero + * length prefix so that Windows is happy. + */ + BSTR raw() const + { + if (m_bstr) + return m_bstr; + + return g_bstrEmpty; + } +#endif + + /** + * Returns a non-const raw pointer that allows to modify the string directly. + * As opposed to raw(), this DOES return NULL if the member string is empty + * because we cannot return a mutable pointer to the global variable with the + * empty string. + * + * @warning + * Be sure not to modify data beyond the allocated memory! The + * guaranteed size of the allocated memory is at least #length() + * bytes after creation and after every assignment operation. + */ + BSTR mutableRaw() { return m_bstr; } + + /** + * Intended to assign copies of instances to |BSTR| out parameters from + * within the interface method. Transfers the ownership of the duplicated + * string to the caller. + * + * If the member string is empty, this allocates an empty BSTR in *pstr + * (i.e. makes it point to a new buffer with a null byte). + * + * @deprecated Use cloneToEx instead to avoid throwing exceptions. + */ + void cloneTo(BSTR *pstr) const + { + if (pstr) + { + *pstr = ::SysAllocString((const OLECHAR *)raw()); // raw() returns a pointer to "" if empty +#ifdef RT_EXCEPTIONS_ENABLED + if (!*pstr) + throw std::bad_alloc(); +#endif + } + } + + /** + * A version of cloneTo that does not throw any out of memory exceptions, but + * returns E_OUTOFMEMORY intead. + * @returns S_OK or E_OUTOFMEMORY. + */ + HRESULT cloneToEx(BSTR *pstr) const + { + if (!pstr) + return S_OK; + *pstr = ::SysAllocString((const OLECHAR *)raw()); // raw() returns a pointer to "" if empty + return pstr ? S_OK : E_OUTOFMEMORY; + } + + /** + * Intended to assign instances to |BSTR| out parameters from within the + * interface method. Transfers the ownership of the original string to the + * caller and resets the instance to null. + * + * As opposed to cloneTo(), this method doesn't create a copy of the + * string. + * + * If the member string is empty, this allocates an empty BSTR in *pstr + * (i.e. makes it point to a new buffer with a null byte). + * + * @param pbstrDst The BSTR variable to detach the string to. + * + * @throws std::bad_alloc if we failed to allocate a new empty string. + */ + void detachTo(BSTR *pbstrDst) + { + if (m_bstr) + { + *pbstrDst = m_bstr; + m_bstr = NULL; + } + else + { + // allocate null BSTR + *pbstrDst = ::SysAllocString((const OLECHAR *)g_bstrEmpty); +#ifdef RT_EXCEPTIONS_ENABLED + if (!*pbstrDst) + throw std::bad_alloc(); +#endif + } + } + + /** + * A version of detachTo that does not throw exceptions on out-of-memory + * conditions, but instead returns E_OUTOFMEMORY. + * + * @param pbstrDst The BSTR variable to detach the string to. + * @returns S_OK or E_OUTOFMEMORY. + */ + HRESULT detachToEx(BSTR *pbstrDst) + { + if (m_bstr) + { + *pbstrDst = m_bstr; + m_bstr = NULL; + } + else + { + // allocate null BSTR + *pbstrDst = ::SysAllocString((const OLECHAR *)g_bstrEmpty); + if (!*pbstrDst) + return E_OUTOFMEMORY; + } + return S_OK; + } + + /** + * Intended to pass instances as |BSTR| out parameters to methods. + * Takes the ownership of the returned data. + */ + BSTR *asOutParam() + { + cleanup(); + return &m_bstr; + } + + /** + * Static immutable empty-string object. May be used for comparison purposes. + */ + static const Bstr Empty; + +protected: + + void cleanup() + { + if (m_bstr) + { + ::SysFreeString(m_bstr); + m_bstr = NULL; + } + } + + /** + * Protected internal helper to copy a string. This ignores the previous object + * state, so either call this from a constructor or call cleanup() first. + * + * This variant copies from a zero-terminated UTF-16 string (which need not + * be a BSTR, i.e. need not have a length prefix). + * + * If the source is empty, this sets the member string to NULL. + * + * @param a_bstrSrc The source string. The caller guarantees + * that this is valid UTF-16. + * + * @throws std::bad_alloc - the object is representing an empty string. + */ + void copyFrom(const OLECHAR *a_bstrSrc) + { + if (a_bstrSrc && *a_bstrSrc) + { + m_bstr = ::SysAllocString(a_bstrSrc); +#ifdef RT_EXCEPTIONS_ENABLED + if (!m_bstr) + throw std::bad_alloc(); +#endif + } + else + m_bstr = NULL; + } + + /** + * Protected internal helper to copy a string. This ignores the previous object + * state, so either call this from a constructor or call cleanup() first. + * + * This variant copies and converts from a zero-terminated UTF-8 string. + * + * If the source is empty, this sets the member string to NULL. + * + * @param a_pszSrc The source string. The caller guarantees + * that this is valid UTF-8. + * + * @throws std::bad_alloc - the object is representing an empty string. + */ + void copyFrom(const char *a_pszSrc) + { + copyFromN(a_pszSrc, RTSTR_MAX); + } + + /** + * Variant of copyFrom for sub-string constructors. + * + * @param a_pszSrc The source string. The caller guarantees + * that this is valid UTF-8. + * @param a_cchMax The maximum number of chars (not + * codepoints) to copy. If you pass RTSTR_MAX + * it'll be exactly like copyFrom(). + * + * @throws std::bad_alloc - the object is representing an empty string. + */ + void copyFromN(const char *a_pszSrc, size_t a_cchSrc); + + BSTR m_bstr; + + friend class Utf8Str; /* to access our raw_copy() */ +}; + +/* symmetric compare operators */ +inline bool operator==(CBSTR l, const Bstr &r) { return r.operator==(l); } +inline bool operator!=(CBSTR l, const Bstr &r) { return r.operator!=(l); } +inline bool operator==(BSTR l, const Bstr &r) { return r.operator==(l); } +inline bool operator!=(BSTR l, const Bstr &r) { return r.operator!=(l); } + + + + +/** + * String class used universally in Main for UTF-8 strings. + * + * This is based on RTCString, to which some functionality has been + * moved. Here we keep things that are specific to Main, such as conversions + * with UTF-16 strings (Bstr). + * + * Like RTCString, Utf8Str does not differentiate between NULL strings + * and empty strings. In other words, Utf8Str("") and Utf8Str(NULL) behave the + * same. In both cases, RTCString allocates no memory, reports + * a zero length and zero allocated bytes for both, and returns an empty + * C string from c_str(). + * + * @note All Utf8Str methods ASSUMES valid UTF-8 or UTF-16 input strings. + * The VirtualBox policy in this regard is to validate strings coming + * from external sources before passing them to Utf8Str or Bstr. + */ +class Utf8Str : public RTCString +{ +public: + + Utf8Str() {} + + Utf8Str(const RTCString &that) + : RTCString(that) + {} + + Utf8Str(const char *that) + : RTCString(that) + {} + + Utf8Str(const Bstr &that) + { + copyFrom(that.raw()); + } + + Utf8Str(CBSTR that) + { + copyFrom(that); + } + + Utf8Str(const char *a_pszSrc, size_t a_cchSrc) + : RTCString(a_pszSrc, a_cchSrc) + { + } + + /** + * Constructs a new string given the format string and the list of the + * arguments for the format string. + * + * @param a_pszFormat Pointer to the format string (UTF-8), + * @see pg_rt_str_format. + * @param a_va Argument vector containing the arguments + * specified by the format string. + * @sa RTCString::printfV + */ + Utf8Str(const char *a_pszFormat, va_list a_va) + : RTCString(a_pszFormat, a_va) + { + } + + Utf8Str& operator=(const RTCString &that) + { + RTCString::operator=(that); + return *this; + } + + Utf8Str& operator=(const char *that) + { + RTCString::operator=(that); + return *this; + } + + Utf8Str& operator=(const Bstr &that) + { + cleanup(); + copyFrom(that.raw()); + return *this; + } + + Utf8Str& operator=(CBSTR that) + { + cleanup(); + copyFrom(that); + return *this; + } + + bool operator<(const RTCString &that) const { return RTCString::operator<(that); } + + /** + * Extended assignment method that returns a COM status code instead of an + * exception on failure. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param a_rSrcStr The source string + */ + HRESULT assignEx(Utf8Str const &a_rSrcStr) + { + return copyFromExNComRC(a_rSrcStr.m_psz, a_rSrcStr.m_cch); + } + + /** + * Extended assignment method that returns a COM status code instead of an + * exception on failure. + * + * @returns S_OK, E_OUTOFMEMORY or E_INVALIDARG. + * @param a_pcszSrc The source string + * @param a_offSrc The character (byte) offset of the substring. + * @param a_cchSrc The number of characters (bytes) to copy from the source + * string. + */ + HRESULT assignEx(Utf8Str const &a_rSrcStr, size_t a_offSrc, size_t a_cchSrc) + { + if ( a_offSrc + a_cchSrc > a_rSrcStr.m_cch + || a_offSrc > a_rSrcStr.m_cch) + return E_INVALIDARG; + return copyFromExNComRC(a_rSrcStr.m_psz, a_rSrcStr.m_cch); + } + + /** + * Extended assignment method that returns a COM status code instead of an + * exception on failure. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param a_pcszSrc The source string + */ + HRESULT assignEx(const char *a_pcszSrc) + { + return copyFromExNComRC(a_pcszSrc, a_pcszSrc ? strlen(a_pcszSrc) : 0); + } + + /** + * Extended assignment method that returns a COM status code instead of an + * exception on failure. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param a_pcszSrc The source string + * @param a_cchSrc The number of characters (bytes) to copy from the source + * string. + */ + HRESULT assignEx(const char *a_pcszSrc, size_t a_cchSrc) + { + return copyFromExNComRC(a_pcszSrc, a_cchSrc); + } + + RTMEMEF_NEW_AND_DELETE_OPERATORS(); + +#if defined(VBOX_WITH_XPCOM) + /** + * Intended to assign instances to |char *| out parameters from within the + * interface method. Transfers the ownership of the duplicated string to the + * caller. + * + * This allocates a single 0 byte in the target if the member string is empty. + * + * This uses XPCOM memory allocation and thus only works on XPCOM. MSCOM doesn't + * like char* strings anyway. + */ + void cloneTo(char **pstr) const; + + /** + * A version of cloneTo that does not throw allocation errors but returns + * E_OUTOFMEMORY instead. + * @returns S_OK or E_OUTOFMEMORY (COM status codes). + */ + HRESULT cloneToEx(char **pstr) const; +#endif + + /** + * Intended to assign instances to |BSTR| out parameters from within the + * interface method. Transfers the ownership of the duplicated string to the + * caller. + */ + void cloneTo(BSTR *pstr) const + { + if (pstr) + { + Bstr bstr(*this); + bstr.cloneTo(pstr); + } + } + + /** + * A version of cloneTo that does not throw allocation errors but returns + * E_OUTOFMEMORY instead. + * + * @param pbstr Where to store a clone of the string. + * @returns S_OK or E_OUTOFMEMORY (COM status codes). + */ + HRESULT cloneToEx(BSTR *pbstr) const + { + if (!pbstr) + return S_OK; + Bstr bstr(*this); + return bstr.detachToEx(pbstr); + } + + /** + * Safe assignment from BSTR. + * + * @param pbstrSrc The source string. + * @returns S_OK or E_OUTOFMEMORY (COM status codes). + */ + HRESULT cloneEx(CBSTR pbstrSrc) + { + cleanup(); + return copyFromEx(pbstrSrc); + } + + /** + * Removes a trailing slash from the member string, if present. + * Calls RTPathStripTrailingSlash() without having to mess with mutableRaw(). + */ + Utf8Str& stripTrailingSlash(); + + /** + * Removes a trailing filename from the member string, if present. + * Calls RTPathStripFilename() without having to mess with mutableRaw(). + */ + Utf8Str& stripFilename(); + + /** + * Removes the path component from the member string, if present. + * Calls RTPathFilename() without having to mess with mutableRaw(). + */ + Utf8Str& stripPath(); + + /** + * Removes a trailing file name extension from the member string, if present. + * Calls RTPathStripExt() without having to mess with mutableRaw(). + */ + Utf8Str& stripExt(); + + /** + * Static immutable empty-string object. May be used for comparison purposes. + */ + static const Utf8Str Empty; +protected: + + void copyFrom(CBSTR a_pbstr); + HRESULT copyFromEx(CBSTR a_pbstr); + HRESULT copyFromExNComRC(const char *a_pcszSrc, size_t a_cchSrc); + + friend class Bstr; /* to access our raw_copy() */ +}; + +/** + * Class with RTCString::printf as constructor for your convenience. + * + * Constructing a Utf8Str string object from a format string and a variable + * number of arguments can easily be confused with the other Utf8Str + * constructures, thus this child class. + * + * The usage of this class is like the following: + * @code + Utf8StrFmt strName("program name = %s", argv[0]); + @endcode + */ +class Utf8StrFmt : public Utf8Str +{ +public: + + /** + * Constructs a new string given the format string and the list of the + * arguments for the format string. + * + * @param a_pszFormat Pointer to the format string (UTF-8), + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + */ + explicit Utf8StrFmt(const char *a_pszFormat, ...) + { + va_list va; + va_start(va, a_pszFormat); + printfV(a_pszFormat, va); + va_end(va); + } + + RTMEMEF_NEW_AND_DELETE_OPERATORS(); + +protected: + Utf8StrFmt() + { } + +private: +}; + +/** + * The BstrFmt class is a shortcut to <tt>Bstr(Utf8StrFmt(...))</tt>. + */ +class BstrFmt : public Bstr +{ +public: + + /** + * Constructs a new string given the format string and the list of the + * arguments for the format string. + * + * @param aFormat printf-like format string (in UTF-8 encoding). + * @param ... List of the arguments for the format string. + */ + explicit BstrFmt(const char *aFormat, ...) + { + va_list args; + va_start(args, aFormat); + copyFrom(Utf8Str(aFormat, args).c_str()); + va_end(args); + } + + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** + * The BstrFmtVA class is a shortcut to <tt>Bstr(Utf8Str(format,va))</tt>. + */ +class BstrFmtVA : public Bstr +{ +public: + + /** + * Constructs a new string given the format string and the list of the + * arguments for the format string. + * + * @param aFormat printf-like format string (in UTF-8 encoding). + * @param aArgs List of arguments for the format string + */ + BstrFmtVA(const char *aFormat, va_list aArgs) + { + copyFrom(Utf8Str(aFormat, aArgs).c_str()); + } + + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +} /* namespace com */ + +#endif /* !___VBox_com_string_h */ + |