VirtualBox

source: vbox/trunk/include/VBox/com/array.h@ 60077

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

introduced RT_GNUC_PREREQ

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 51.1 KB
Line 
1/** @file
2 * MS COM / XPCOM Abstraction Layer - Safe array helper class declaration.
3 */
4
5/*
6 * Copyright (C) 2006-2015 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * The contents of this file may alternatively be used under the terms
17 * of the Common Development and Distribution License Version 1.0
18 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
19 * VirtualBox OSE distribution, in which case the provisions of the
20 * CDDL are applicable instead of those of the GPL.
21 *
22 * You may elect to license modified versions of this file under the
23 * terms and conditions of either the GPL or the CDDL or both.
24 */
25
26#ifndef ___VBox_com_array_h
27#define ___VBox_com_array_h
28
29
30/** @defgroup grp_com_arrays COM/XPCOM Arrays
31 * @ingroup grp_com
32 * @{
33 *
34 * The COM/XPCOM array support layer provides a cross-platform way to pass
35 * arrays to and from COM interface methods and consists of the com::SafeArray
36 * template and a set of ComSafeArray* macros part of which is defined in
37 * VBox/com/defs.h.
38 *
39 * This layer works with interface attributes and method parameters that have
40 * the 'safearray="yes"' attribute in the XIDL definition:
41 * @code
42
43 <interface name="ISomething" ...>
44
45 <method name="testArrays">
46 <param name="inArr" type="long" dir="in" safearray="yes"/>
47 <param name="outArr" type="long" dir="out" safearray="yes"/>
48 <param name="retArr" type="long" dir="return" safearray="yes"/>
49 </method>
50
51 </interface>
52
53 * @endcode
54 *
55 * Methods generated from this and similar definitions are implemented in
56 * component classes using the following declarations:
57 * @code
58
59 STDMETHOD(TestArrays)(ComSafeArrayIn(LONG, aIn),
60 ComSafeArrayOut(LONG, aOut),
61 ComSafeArrayOut(LONG, aRet));
62
63 * @endcode
64 *
65 * And the following function bodies:
66 * @code
67
68 STDMETHODIMP Component::TestArrays(ComSafeArrayIn(LONG, aIn),
69 ComSafeArrayOut(LONG, aOut),
70 ComSafeArrayOut(LONG, aRet))
71 {
72 if (ComSafeArrayInIsNull(aIn))
73 return E_INVALIDARG;
74 if (ComSafeArrayOutIsNull(aOut))
75 return E_POINTER;
76 if (ComSafeArrayOutIsNull(aRet))
77 return E_POINTER;
78
79 // Use SafeArray to access the input array parameter
80
81 com::SafeArray<LONG> in(ComSafeArrayInArg(aIn));
82
83 for (size_t i = 0; i < in.size(); ++ i)
84 LogFlow(("*** in[%u]=%d\n", i, in[i]));
85
86 // Use SafeArray to create the return array (the same technique is used
87 // for output array parameters)
88
89 SafeArray<LONG> ret(in.size() * 2);
90 for (size_t i = 0; i < in.size(); ++ i)
91 {
92 ret[i] = in[i];
93 ret[i + in.size()] = in[i] * 10;
94 }
95
96 ret.detachTo(ComSafeArrayOutArg(aRet));
97
98 return S_OK;
99 }
100
101 * @endcode
102 *
103 * Such methods can be called from the client code using the following pattern:
104 * @code
105
106 ComPtr<ISomething> component;
107
108 // ...
109
110 com::SafeArray<LONG> in(3);
111 in[0] = -1;
112 in[1] = -2;
113 in[2] = -3;
114
115 com::SafeArray<LONG> out;
116 com::SafeArray<LONG> ret;
117
118 HRESULT rc = component->TestArrays(ComSafeArrayAsInParam(in),
119 ComSafeArrayAsOutParam(out),
120 ComSafeArrayAsOutParam(ret));
121
122 if (SUCCEEDED(rc))
123 for (size_t i = 0; i < ret.size(); ++ i)
124 printf("*** ret[%u]=%d\n", i, ret[i]);
125
126 * @endcode
127 *
128 * For interoperability with standard C++ containers, there is a template
129 * constructor that takes such a container as argument and performs a deep copy
130 * of its contents. This can be used in method implementations like this:
131 * @code
132
133 STDMETHODIMP Component::COMGETTER(Values)(ComSafeArrayOut(int, aValues))
134 {
135 // ... assume there is a |std::list<int> mValues| data member
136
137 com::SafeArray<int> values(mValues);
138 values.detachTo(ComSafeArrayOutArg(aValues));
139
140 return S_OK;
141 }
142
143 * @endcode
144 *
145 * The current implementation of the SafeArray layer supports all types normally
146 * allowed in XIDL as array element types (including 'wstring' and 'uuid').
147 * However, 'pointer-to-...' types (e.g. 'long *', 'wstring *') are not
148 * supported and therefore cannot be used as element types.
149 *
150 * Note that for GUID arrays you should use SafeGUIDArray and
151 * SafeConstGUIDArray, customized SafeArray<> specializations.
152 *
153 * Also note that in order to pass input BSTR array parameters declared
154 * using the ComSafeArrayIn(IN_BSTR, aParam) macro to the SafeArray<>
155 * constructor using the ComSafeArrayInArg() macro, you should use IN_BSTR
156 * as the SafeArray<> template argument, not just BSTR.
157 *
158 * Arrays of interface pointers are also supported but they require to use a
159 * special SafeArray implementation, com::SafeIfacePointer, which takes the
160 * interface class name as a template argument (e.g.
161 * com::SafeIfacePointer\<IUnknown\>). This implementation functions
162 * identically to com::SafeArray.
163 */
164
165#ifdef VBOX_WITH_XPCOM
166# include <nsMemory.h>
167#endif
168
169 /* Type traits are a C++ 11 feature, so not available everywhere (yet).
170 * Only GCC 4.6 or newer and MSVC++ 16.0 (Visual Studio 2010) or newer. */
171#if RT_GNUC_PREREQ(4, 6) || (defined(_MSC_VER) && (_MSC_VER >= 1600))
172# define VBOX_WITH_TYPE_TRAITS
173#endif
174
175#ifdef VBOX_WITH_TYPE_TRAITS
176# include <type_traits>
177#endif
178
179#include "VBox/com/defs.h"
180#include "VBox/com/ptr.h"
181#include "VBox/com/assert.h"
182#include "iprt/cpp/list.h"
183
184#ifdef VBOX_WITH_XPCOM
185
186/**
187 * Wraps the given com::SafeArray instance to generate an expression that is
188 * suitable for passing it to functions that take input safearray parameters
189 * declared using the ComSafeArrayIn macro.
190 *
191 * @param aArray com::SafeArray instance to pass as an input parameter.
192 */
193#define ComSafeArrayAsInParam(aArray) \
194 (aArray).size(), (aArray).__asInParam_Arr((aArray).raw())
195
196/**
197 * Wraps the given com::SafeArray instance to generate an expression that is
198 * suitable for passing it to functions that take output safearray parameters
199 * declared using the ComSafeArrayOut macro.
200 *
201 * @param aArray com::SafeArray instance to pass as an output parameter.
202 */
203#define ComSafeArrayAsOutParam(aArray) \
204 (aArray).__asOutParam_Size(), (aArray).__asOutParam_Arr()
205
206#else /* !VBOX_WITH_XPCOM */
207
208#define ComSafeArrayAsInParam(aArray) (aArray).__asInParam()
209
210#define ComSafeArrayAsOutParam(aArray) (aArray).__asOutParam()
211
212#endif /* !VBOX_WITH_XPCOM */
213
214/**
215 *
216 */
217namespace com
218{
219
220#ifdef VBOX_WITH_XPCOM
221
222////////////////////////////////////////////////////////////////////////////////
223
224/**
225 * Provides various helpers for SafeArray.
226 *
227 * @param T Type of array elements.
228 */
229template<typename T>
230struct SafeArrayTraits
231{
232protected:
233
234 /** Initializes memory for aElem. */
235 static void Init(T &aElem) { aElem = 0; }
236
237 /** Initializes memory occupied by aElem. */
238 static void Uninit(T &aElem) { aElem = 0; }
239
240 /** Creates a deep copy of aFrom and stores it in aTo. */
241 static void Copy(const T &aFrom, T &aTo) { aTo = aFrom; }
242
243public:
244
245 /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard (that
246 * in particular forbid casts of 'char **' to 'const char **'). Then initial
247 * reason for this magic is that XPIDL declares input strings
248 * (char/PRUnichar pointers) as const but doesn't do so for pointers to
249 * arrays. */
250 static T *__asInParam_Arr(T *aArr) { return aArr; }
251 static T *__asInParam_Arr(const T *aArr) { return const_cast<T *>(aArr); }
252};
253
254template<typename T>
255struct SafeArrayTraits<T *>
256{
257 // Arbitrary pointers are not supported
258};
259
260template<>
261struct SafeArrayTraits<PRUnichar *>
262{
263protected:
264
265 static void Init(PRUnichar * &aElem) { aElem = NULL; }
266
267 static void Uninit(PRUnichar * &aElem)
268 {
269 if (aElem)
270 {
271 ::SysFreeString(aElem);
272 aElem = NULL;
273 }
274 }
275
276 static void Copy(const PRUnichar * aFrom, PRUnichar * &aTo)
277 {
278 AssertCompile(sizeof(PRUnichar) == sizeof(OLECHAR));
279 aTo = aFrom ? ::SysAllocString((const OLECHAR *)aFrom) : NULL;
280 }
281
282public:
283
284 /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard */
285 static const PRUnichar **__asInParam_Arr(PRUnichar **aArr)
286 {
287 return const_cast<const PRUnichar **>(aArr);
288 }
289 static const PRUnichar **__asInParam_Arr(const PRUnichar **aArr) { return aArr; }
290};
291
292template<>
293struct SafeArrayTraits<const PRUnichar *>
294{
295protected:
296
297 static void Init(const PRUnichar * &aElem) { aElem = NULL; }
298 static void Uninit(const PRUnichar * &aElem)
299 {
300 if (aElem)
301 {
302 ::SysFreeString(const_cast<PRUnichar *>(aElem));
303 aElem = NULL;
304 }
305 }
306
307 static void Copy(const PRUnichar * aFrom, const PRUnichar * &aTo)
308 {
309 AssertCompile(sizeof(PRUnichar) == sizeof(OLECHAR));
310 aTo = aFrom ? ::SysAllocString((const OLECHAR *)aFrom) : NULL;
311 }
312
313public:
314
315 /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard */
316 static const PRUnichar **__asInParam_Arr(const PRUnichar **aArr) { return aArr; }
317};
318
319template<>
320struct SafeArrayTraits<nsID *>
321{
322protected:
323
324 static void Init(nsID * &aElem) { aElem = NULL; }
325
326 static void Uninit(nsID * &aElem)
327 {
328 if (aElem)
329 {
330 ::nsMemory::Free(aElem);
331 aElem = NULL;
332 }
333 }
334
335 static void Copy(const nsID * aFrom, nsID * &aTo)
336 {
337 if (aFrom)
338 {
339 aTo = (nsID *) ::nsMemory::Alloc(sizeof(nsID));
340 if (aTo)
341 *aTo = *aFrom;
342 }
343 else
344 aTo = NULL;
345 }
346
347 /* This specification is also reused for SafeConstGUIDArray, so provide a
348 * no-op Init() and Uninit() which are necessary for SafeArray<> but should
349 * be never called in context of SafeConstGUIDArray. */
350
351 static void Init(const nsID * &aElem) { NOREF(aElem); AssertFailed(); }
352 static void Uninit(const nsID * &aElem) { NOREF(aElem); AssertFailed(); }
353
354public:
355
356 /** Magic to workaround strict rules of par. 4.4.4 of the C++ standard. */
357 static const nsID **__asInParam_Arr(nsID **aArr)
358 {
359 return const_cast<const nsID **>(aArr);
360 }
361 static const nsID **__asInParam_Arr(const nsID **aArr) { return aArr; }
362};
363
364#else /* !VBOX_WITH_XPCOM */
365
366////////////////////////////////////////////////////////////////////////////////
367
368struct SafeArrayTraitsBase
369{
370protected:
371
372 static SAFEARRAY *CreateSafeArray(VARTYPE aVarType, SAFEARRAYBOUND *aBound)
373 { return SafeArrayCreate(aVarType, 1, aBound); }
374};
375
376/**
377 * Provides various helpers for SafeArray.
378 *
379 * @param T Type of array elements.
380 *
381 * Specializations of this template must provide the following methods:
382 *
383 // Returns the VARTYPE of COM SafeArray elements to be used for T
384 static VARTYPE VarType();
385
386 // Returns the number of VarType() elements necessary for aSize
387 // elements of T
388 static ULONG VarCount(size_t aSize);
389
390 // Returns the number of elements of T that fit into the given number of
391 // VarType() elements (opposite to VarCount(size_t aSize)).
392 static size_t Size(ULONG aVarCount);
393
394 // Creates a deep copy of aFrom and stores it in aTo
395 static void Copy(ULONG aFrom, ULONG &aTo);
396 */
397template<typename T>
398struct SafeArrayTraits : public SafeArrayTraitsBase
399{
400protected:
401
402 // Arbitrary types are treated as passed by value and each value is
403 // represented by a number of VT_Ix type elements where VT_Ix has the
404 // biggest possible bitness necessary to represent T w/o a gap. COM enums
405 // fall into this category.
406
407 static VARTYPE VarType()
408 {
409#ifdef VBOX_WITH_TYPE_TRAITS
410 if ( std::is_integral<T>::value
411 && !std::is_signed<T>::value)
412 {
413 if (sizeof(T) % 8 == 0) return VT_UI8;
414 if (sizeof(T) % 4 == 0) return VT_UI4;
415 if (sizeof(T) % 2 == 0) return VT_UI2;
416 return VT_UI1;
417 }
418#endif
419 if (sizeof(T) % 8 == 0) return VT_I8;
420 if (sizeof(T) % 4 == 0) return VT_I4;
421 if (sizeof(T) % 2 == 0) return VT_I2;
422 return VT_I1;
423 }
424
425 /*
426 * Fallback method in case type traits (VBOX_WITH_TYPE_TRAITS)
427 * are not available. Always returns unsigned types.
428 */
429 static VARTYPE VarTypeUnsigned()
430 {
431 if (sizeof(T) % 8 == 0) return VT_UI8;
432 if (sizeof(T) % 4 == 0) return VT_UI4;
433 if (sizeof(T) % 2 == 0) return VT_UI2;
434 return VT_UI1;
435 }
436
437 static ULONG VarCount(size_t aSize)
438 {
439 if (sizeof(T) % 8 == 0) return (ULONG)((sizeof(T) / 8) * aSize);
440 if (sizeof(T) % 4 == 0) return (ULONG)((sizeof(T) / 4) * aSize);
441 if (sizeof(T) % 2 == 0) return (ULONG)((sizeof(T) / 2) * aSize);
442 return (ULONG)(sizeof(T) * aSize);
443 }
444
445 static size_t Size(ULONG aVarCount)
446 {
447 if (sizeof(T) % 8 == 0) return (size_t)(aVarCount * 8) / sizeof(T);
448 if (sizeof(T) % 4 == 0) return (size_t)(aVarCount * 4) / sizeof(T);
449 if (sizeof(T) % 2 == 0) return (size_t)(aVarCount * 2) / sizeof(T);
450 return (size_t) aVarCount / sizeof(T);
451 }
452
453 static void Copy(T aFrom, T &aTo) { aTo = aFrom; }
454};
455
456template<typename T>
457struct SafeArrayTraits<T *>
458{
459 // Arbitrary pointer types are not supported
460};
461
462/* Although the generic SafeArrayTraits template would work for all integers,
463 * we specialize it for some of them in order to use the correct VT_ type */
464
465template<>
466struct SafeArrayTraits<LONG> : public SafeArrayTraitsBase
467{
468protected:
469
470 static VARTYPE VarType() { return VT_I4; }
471 static ULONG VarCount(size_t aSize) { return (ULONG)aSize; }
472 static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; }
473
474 static void Copy(LONG aFrom, LONG &aTo) { aTo = aFrom; }
475};
476
477template<>
478struct SafeArrayTraits<ULONG> : public SafeArrayTraitsBase
479{
480protected:
481
482 static VARTYPE VarType() { return VT_UI4; }
483 static ULONG VarCount(size_t aSize) { return (ULONG)aSize; }
484 static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; }
485
486 static void Copy(ULONG aFrom, ULONG &aTo) { aTo = aFrom; }
487};
488
489template<>
490struct SafeArrayTraits<LONG64> : public SafeArrayTraitsBase
491{
492protected:
493
494 static VARTYPE VarType() { return VT_I8; }
495 static ULONG VarCount(size_t aSize) { return (ULONG)aSize; }
496 static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; }
497
498 static void Copy(LONG64 aFrom, LONG64 &aTo) { aTo = aFrom; }
499};
500
501template<>
502struct SafeArrayTraits<ULONG64> : public SafeArrayTraitsBase
503{
504protected:
505
506 static VARTYPE VarType() { return VT_UI8; }
507 static ULONG VarCount(size_t aSize) { return (ULONG)aSize; }
508 static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; }
509
510 static void Copy(ULONG64 aFrom, ULONG64 &aTo) { aTo = aFrom; }
511};
512
513template<>
514struct SafeArrayTraits<BSTR> : public SafeArrayTraitsBase
515{
516protected:
517
518 static VARTYPE VarType() { return VT_BSTR; }
519 static ULONG VarCount(size_t aSize) { return (ULONG)aSize; }
520 static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; }
521
522 static void Copy(BSTR aFrom, BSTR &aTo)
523 {
524 aTo = aFrom ? ::SysAllocString((const OLECHAR *)aFrom) : NULL;
525 }
526};
527
528template<>
529struct SafeArrayTraits<GUID> : public SafeArrayTraitsBase
530{
531protected:
532
533 /* Use the 64-bit unsigned integer type for GUID */
534 static VARTYPE VarType() { return VT_UI8; }
535
536 /* GUID is 128 bit, so we need two VT_UI8 */
537 static ULONG VarCount(size_t aSize)
538 {
539 AssertCompileSize(GUID, 16);
540 return (ULONG)(aSize * 2);
541 }
542
543 static size_t Size(ULONG aVarCount) { return (size_t)aVarCount / 2; }
544
545 static void Copy(GUID aFrom, GUID &aTo) { aTo = aFrom; }
546};
547
548/**
549 * Helper for SafeArray::__asOutParam() that automatically updates m.raw after a
550 * non-NULL m.arr assignment.
551 */
552class OutSafeArrayDipper
553{
554 OutSafeArrayDipper(SAFEARRAY **aArr, void **aRaw)
555 : arr(aArr), raw(aRaw) { Assert(*aArr == NULL && *aRaw == NULL); }
556
557 SAFEARRAY **arr;
558 void **raw;
559
560 template<class, class> friend class SafeArray;
561
562public:
563
564 ~OutSafeArrayDipper()
565 {
566 if (*arr != NULL)
567 {
568 HRESULT rc = SafeArrayAccessData(*arr, raw);
569 AssertComRC(rc);
570 }
571 }
572
573 operator SAFEARRAY **() { return arr; }
574};
575
576#endif /* !VBOX_WITH_XPCOM */
577
578////////////////////////////////////////////////////////////////////////////////
579
580/**
581 * The SafeArray class represents the safe array type used in COM to pass arrays
582 * to/from interface methods.
583 *
584 * This helper class hides all MSCOM/XPCOM specific implementation details and,
585 * together with ComSafeArrayIn, ComSafeArrayOut and ComSafeArrayRet macros,
586 * provides a platform-neutral way to handle safe arrays in the method
587 * implementation.
588 *
589 * When an instance of this class is destroyed, it automatically frees all
590 * resources occupied by individual elements of the array as well as by the
591 * array itself. However, when the value of an element is manually changed
592 * using #operator[] or by accessing array data through the #raw() pointer, it is
593 * the caller's responsibility to free resources occupied by the previous
594 * element's value.
595 *
596 * Also, objects of this class do not support copy and assignment operations and
597 * therefore cannot be returned from functions by value. In other words, this
598 * class is just a temporary storage for handling interface method calls and not
599 * intended to be used to store arrays as data members and such -- you should
600 * use normal list/vector classes for that.
601 *
602 * @note The current implementation supports only one-dimensional arrays.
603 *
604 * @note This class is not thread-safe.
605 */
606template<typename T, class Traits = SafeArrayTraits<T> >
607class SafeArray : public Traits
608{
609public:
610
611 /**
612 * Creates a null array.
613 */
614 SafeArray() {}
615
616 /**
617 * Creates a new array of the given size. All elements of the newly created
618 * array initialized with null values.
619 *
620 * @param aSize Initial number of elements in the array.
621 *
622 * @note If this object remains null after construction it means that there
623 * was not enough memory for creating an array of the requested size.
624 * The constructor will also assert in this case.
625 */
626 SafeArray(size_t aSize) { resize(aSize); }
627
628 /**
629 * Weakly attaches this instance to the existing array passed in a method
630 * parameter declared using the ComSafeArrayIn macro. When using this call,
631 * always wrap the parameter name in the ComSafeArrayInArg macro call like
632 * this:
633 * <pre>
634 * SafeArray safeArray(ComSafeArrayInArg(aArg));
635 * </pre>
636 *
637 * Note that this constructor doesn't take the ownership of the array. In
638 * particular, it means that operations that operate on the ownership (e.g.
639 * #detachTo()) are forbidden and will assert.
640 *
641 * @param aArg Input method parameter to attach to.
642 */
643 SafeArray(ComSafeArrayIn(T, aArg))
644 {
645 if (aArg)
646 {
647#ifdef VBOX_WITH_XPCOM
648
649 m.size = aArgSize;
650 m.arr = aArg;
651 m.isWeak = true;
652
653#else /* !VBOX_WITH_XPCOM */
654
655 SAFEARRAY *arg = aArg;
656
657 AssertReturnVoid(arg->cDims == 1);
658
659 VARTYPE vt;
660 HRESULT rc = SafeArrayGetVartype(arg, &vt);
661 AssertComRCReturnVoid(rc);
662# ifndef VBOX_WITH_TYPE_TRAITS
663 AssertMsgReturnVoid(
664 vt == VarType()
665 || vt == VarTypeUnsigned(),
666 ("Expected vartype %d or %d, got %d.\n",
667 VarType(), VarTypeUnsigned(), vt));
668# else /* !VBOX_WITH_TYPE_TRAITS */
669 AssertMsgReturnVoid(
670 vt == VarType(),
671 ("Expected vartype %d, got %d.\n",
672 VarType(), vt));
673# endif
674 rc = SafeArrayAccessData(arg, (void HUGEP **)&m.raw);
675 AssertComRCReturnVoid(rc);
676
677 m.arr = arg;
678 m.isWeak = true;
679
680#endif /* !VBOX_WITH_XPCOM */
681 }
682 }
683
684 /**
685 * Creates a deep copy of the given standard C++ container that stores
686 * T objects.
687 *
688 * @param aCntr Container object to copy.
689 *
690 * @tparam C Standard C++ container template class (normally deduced from
691 * @c aCntr).
692 */
693 template<template<typename, typename> class C, class A>
694 SafeArray(const C<T, A> & aCntr)
695 {
696 resize(aCntr.size());
697 AssertReturnVoid(!isNull());
698
699 size_t i = 0;
700 for (typename C<T, A>::const_iterator it = aCntr.begin();
701 it != aCntr.end(); ++ it, ++ i)
702#ifdef VBOX_WITH_XPCOM
703 SafeArray::Copy(*it, m.arr[i]);
704#else
705 Copy(*it, m.raw[i]);
706#endif
707 }
708
709 /**
710 * Creates a deep copy of the given standard C++ map that stores T objects
711 * as values.
712 *
713 * @param aMap Map object to copy.
714 *
715 * @tparam C Standard C++ map template class (normally deduced from
716 * @a aMap).
717 * @tparam L Standard C++ compare class (deduced from @a aMap).
718 * @tparam A Standard C++ allocator class (deduced from @a aMap).
719 * @tparam K Map key class (deduced from @a aMap).
720 */
721 template<template<typename, typename, typename, typename>
722 class C, class L, class A, class K>
723 SafeArray(const C<K, T, L, A> & aMap)
724 {
725 typedef C<K, T, L, A> Map;
726
727 resize(aMap.size());
728 AssertReturnVoid(!isNull());
729
730 int i = 0;
731 for (typename Map::const_iterator it = aMap.begin();
732 it != aMap.end(); ++ it, ++ i)
733#ifdef VBOX_WITH_XPCOM
734 Copy(it->second, m.arr[i]);
735#else
736 Copy(it->second, m.raw[i]);
737#endif
738 }
739
740 /**
741 * Destroys this instance after calling #setNull() to release allocated
742 * resources. See #setNull() for more details.
743 */
744 virtual ~SafeArray() { setNull(); }
745
746 /**
747 * Returns @c true if this instance represents a null array.
748 */
749 bool isNull() const { return m.arr == NULL; }
750
751 /**
752 * Returns @c true if this instance does not represents a null array.
753 */
754 bool isNotNull() const { return m.arr != NULL; }
755
756 /**
757 * Resets this instance to null and, if this instance is not a weak one,
758 * releases any resources occupied by the array data.
759 *
760 * @note This method destroys (cleans up) all elements of the array using
761 * the corresponding cleanup routine for the element type before the
762 * array itself is destroyed.
763 */
764 virtual void setNull() { m.uninit(); }
765
766 /**
767 * Returns @c true if this instance is weak. A weak instance doesn't own the
768 * array data and therefore operations manipulating the ownership (e.g.
769 * #detachTo()) are forbidden and will assert.
770 */
771 bool isWeak() const { return m.isWeak; }
772
773 /** Number of elements in the array. */
774 size_t size() const
775 {
776#ifdef VBOX_WITH_XPCOM
777 if (m.arr)
778 return m.size;
779 return 0;
780#else
781 if (m.arr)
782 return Size(m.arr->rgsabound[0].cElements);
783 return 0;
784#endif
785 }
786
787 /**
788 * Appends a copy of the given element at the end of the array.
789 *
790 * The array size is increased by one by this method and the additional
791 * space is allocated as needed.
792 *
793 * This method is handy in cases where you want to assign a copy of the
794 * existing value to the array element, for example:
795 * <tt>Bstr string; array.push_back(string);</tt>. If you create a string
796 * just to put it in the array, you may find #appendedRaw() more useful.
797 *
798 * @param aElement Element to append.
799 *
800 * @return @c true on success and @c false if there is not enough
801 * memory for resizing.
802 */
803 bool push_back(const T &aElement)
804 {
805 if (!ensureCapacity(size() + 1))
806 return false;
807
808#ifdef VBOX_WITH_XPCOM
809 SafeArray::Copy(aElement, m.arr[m.size]);
810 ++ m.size;
811#else
812 Copy(aElement, m.raw[size() - 1]);
813#endif
814 return true;
815 }
816
817 /**
818 * Appends an empty element at the end of the array and returns a raw
819 * pointer to it suitable for assigning a raw value (w/o constructing a
820 * copy).
821 *
822 * The array size is increased by one by this method and the additional
823 * space is allocated as needed.
824 *
825 * Note that in case of raw assignment, value ownership (for types with
826 * dynamically allocated data and for interface pointers) is transferred to
827 * the safe array object.
828 *
829 * This method is handy for operations like
830 * <tt>Bstr("foo").detachTo(array.appendedRaw());</tt>. Don't use it as
831 * an l-value (<tt>array.appendedRaw() = SysAllocString(L"tralala");</tt>)
832 * since this doesn't check for a NULL condition; use #resize() instead. If
833 * you need to assign a copy of the existing value instead of transferring
834 * the ownership, look at #push_back().
835 *
836 * @return Raw pointer to the added element or NULL if no memory.
837 */
838 T *appendedRaw()
839 {
840 if (!ensureCapacity(size() + 1))
841 return NULL;
842
843#ifdef VBOX_WITH_XPCOM
844 SafeArray::Init(m.arr[m.size]);
845 ++ m.size;
846 return &m.arr[m.size - 1];
847#else
848 /* nothing to do here, SafeArrayCreate() has performed element
849 * initialization */
850 return &m.raw[size() - 1];
851#endif
852 }
853
854 /**
855 * Resizes the array preserving its contents when possible. If the new size
856 * is larger than the old size, new elements are initialized with null
857 * values. If the new size is less than the old size, the contents of the
858 * array beyond the new size is lost.
859 *
860 * @param aNewSize New number of elements in the array.
861 * @return @c true on success and @c false if there is not enough
862 * memory for resizing.
863 */
864 bool resize(size_t aNewSize)
865 {
866 if (!ensureCapacity(aNewSize))
867 return false;
868
869#ifdef VBOX_WITH_XPCOM
870
871 if (m.size < aNewSize)
872 {
873 /* initialize the new elements */
874 for (size_t i = m.size; i < aNewSize; ++ i)
875 SafeArray::Init(m.arr[i]);
876 }
877
878 m.size = aNewSize;
879#else
880 /* nothing to do here, SafeArrayCreate() has performed element
881 * initialization */
882#endif
883 return true;
884 }
885
886 /**
887 * Reinitializes this instance by preallocating space for the given number
888 * of elements. The previous array contents is lost.
889 *
890 * @param aNewSize New number of elements in the array.
891 * @return @c true on success and @c false if there is not enough
892 * memory for resizing.
893 */
894 bool reset(size_t aNewSize)
895 {
896 m.uninit();
897 return resize(aNewSize);
898 }
899
900 /**
901 * Returns a pointer to the raw array data. Use this raw pointer with care
902 * as no type or bound checking is done for you in this case.
903 *
904 * @note This method returns @c NULL when this instance is null.
905 * @see #operator[]
906 */
907 T *raw()
908 {
909#ifdef VBOX_WITH_XPCOM
910 return m.arr;
911#else
912 return m.raw;
913#endif
914 }
915
916 /**
917 * Const version of #raw().
918 */
919 const T *raw() const
920 {
921#ifdef VBOX_WITH_XPCOM
922 return m.arr;
923#else
924 return m.raw;
925#endif
926 }
927
928 /**
929 * Array access operator that returns an array element by reference. A bit
930 * safer than #raw(): asserts and returns an invalid reference if this
931 * instance is null or if the index is out of bounds.
932 *
933 * @note For weak instances, this call will succeed but the behavior of
934 * changing the contents of an element of the weak array instance is
935 * undefined and may lead to a program crash on some platforms.
936 */
937 T &operator[] (size_t aIdx)
938 {
939 AssertReturn(m.arr != NULL, *((T *)NULL));
940 AssertReturn(aIdx < size(), *((T *)NULL));
941#ifdef VBOX_WITH_XPCOM
942 return m.arr[aIdx];
943#else
944 AssertReturn(m.raw != NULL, *((T *)NULL));
945 return m.raw[aIdx];
946#endif
947 }
948
949 /**
950 * Const version of #operator[] that returns an array element by value.
951 */
952 const T operator[] (size_t aIdx) const
953 {
954 AssertReturn(m.arr != NULL, *((T *)NULL));
955 AssertReturn(aIdx < size(), *((T *)NULL));
956#ifdef VBOX_WITH_XPCOM
957 return m.arr[aIdx];
958#else
959 AssertReturn(m.raw != NULL, *((T *)NULL));
960 return m.raw[aIdx];
961#endif
962 }
963
964 /**
965 * Creates a copy of this array and stores it in a method parameter declared
966 * using the ComSafeArrayOut macro. When using this call, always wrap the
967 * parameter name in the ComSafeArrayOutArg macro call like this:
968 * <pre>
969 * safeArray.cloneTo(ComSafeArrayOutArg(aArg));
970 * </pre>
971 *
972 * @note It is assumed that the ownership of the returned copy is
973 * transferred to the caller of the method and he is responsible to free the
974 * array data when it is no longer needed.
975 *
976 * @param aArg Output method parameter to clone to.
977 */
978 virtual const SafeArray &cloneTo(ComSafeArrayOut(T, aArg)) const
979 {
980 /// @todo Implement me!
981#ifdef VBOX_WITH_XPCOM
982 NOREF(aArgSize);
983 NOREF(aArg);
984#else
985 NOREF(aArg);
986#endif
987 AssertFailedReturn(*this);
988 }
989
990 void cloneTo(SafeArray<T>& aOther) const
991 {
992 aOther.reset(size());
993 aOther.initFrom(*this);
994 }
995
996
997 /**
998 * Transfers the ownership of this array's data to the specified location
999 * declared using the ComSafeArrayOut macro and makes this array a null
1000 * array. When using this call, always wrap the parameter name in the
1001 * ComSafeArrayOutArg macro call like this:
1002 * <pre>
1003 * safeArray.detachTo(ComSafeArrayOutArg(aArg));
1004 * </pre>
1005 *
1006 * Detaching the null array is also possible in which case the location will
1007 * receive NULL.
1008 *
1009 * @note Since the ownership of the array data is transferred to the
1010 * caller of the method, he is responsible to free the array data when it is
1011 * no longer needed.
1012 *
1013 * @param aArg Location to detach to.
1014 */
1015 virtual SafeArray &detachTo(ComSafeArrayOut(T, aArg))
1016 {
1017 AssertReturn(!m.isWeak, *this);
1018
1019#ifdef VBOX_WITH_XPCOM
1020
1021 AssertReturn(aArgSize != NULL, *this);
1022 AssertReturn(aArg != NULL, *this);
1023
1024 *aArgSize = m.size;
1025 *aArg = m.arr;
1026
1027 m.isWeak = false;
1028 m.size = 0;
1029 m.arr = NULL;
1030
1031#else /* !VBOX_WITH_XPCOM */
1032
1033 AssertReturn(aArg != NULL, *this);
1034 *aArg = m.arr;
1035
1036 if (m.raw)
1037 {
1038 HRESULT rc = SafeArrayUnaccessData(m.arr);
1039 AssertComRCReturn(rc, *this);
1040 m.raw = NULL;
1041 }
1042
1043 m.isWeak = false;
1044 m.arr = NULL;
1045
1046#endif /* !VBOX_WITH_XPCOM */
1047
1048 return *this;
1049 }
1050
1051 /**
1052 * Returns a copy of this SafeArray as RTCList<T>.
1053 */
1054 RTCList<T> toList()
1055 {
1056 RTCList<T> list(size());
1057 for (size_t i = 0; i < size(); ++i)
1058#ifdef VBOX_WITH_XPCOM
1059 list.append(m.arr[i]);
1060#else
1061 list.append(m.raw[i]);
1062#endif
1063 return list;
1064 }
1065
1066 inline void initFrom(const com::SafeArray<T> & aRef);
1067 inline void initFrom(const T* aPtr, size_t aSize);
1068
1069 // Public methods for internal purposes only.
1070
1071#ifdef VBOX_WITH_XPCOM
1072
1073 /** Internal function. Never call it directly. */
1074 PRUint32 *__asOutParam_Size() { setNull(); return &m.size; }
1075
1076 /** Internal function Never call it directly. */
1077 T **__asOutParam_Arr() { Assert(isNull()); return &m.arr; }
1078
1079#else /* !VBOX_WITH_XPCOM */
1080
1081 /** Internal function Never call it directly. */
1082 SAFEARRAY * __asInParam() { return m.arr; }
1083
1084 /** Internal function Never call it directly. */
1085 OutSafeArrayDipper __asOutParam()
1086 { setNull(); return OutSafeArrayDipper(&m.arr, (void **)&m.raw); }
1087
1088#endif /* !VBOX_WITH_XPCOM */
1089
1090 static const SafeArray Null;
1091
1092protected:
1093
1094 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(SafeArray)
1095
1096 /**
1097 * Ensures that the array is big enough to contain aNewSize elements.
1098 *
1099 * If the new size is greater than the current capacity, a new array is
1100 * allocated and elements from the old array are copied over. The size of
1101 * the array doesn't change, only the capacity increases (which is always
1102 * greater than the size). Note that the additionally allocated elements are
1103 * left uninitialized by this method.
1104 *
1105 * If the new size is less than the current size, the existing array is
1106 * truncated to the specified size and the elements outside the new array
1107 * boundary are freed.
1108 *
1109 * If the new size is the same as the current size, nothing happens.
1110 *
1111 * @param aNewSize New size of the array.
1112 *
1113 * @return @c true on success and @c false if not enough memory.
1114 */
1115 bool ensureCapacity(size_t aNewSize)
1116 {
1117 AssertReturn(!m.isWeak, false);
1118
1119#ifdef VBOX_WITH_XPCOM
1120
1121 /* Note: we distinguish between a null array and an empty (zero
1122 * elements) array. Therefore we never use zero in malloc (even if
1123 * aNewSize is zero) to make sure we get a non-null pointer. */
1124
1125 if (m.size == aNewSize && m.arr != NULL)
1126 return true;
1127
1128 /* Allocate in 16-byte pieces. */
1129 size_t newCapacity = RT_MAX((aNewSize + 15) / 16 * 16, 16);
1130
1131 if (m.capacity != newCapacity)
1132 {
1133 T *newArr = (T *)nsMemory::Alloc(RT_MAX(newCapacity, 1) * sizeof(T));
1134 AssertReturn(newArr != NULL, false);
1135
1136 if (m.arr != NULL)
1137 {
1138 if (m.size > aNewSize)
1139 {
1140 /* Truncation takes place, uninit exceeding elements and
1141 * shrink the size. */
1142 for (size_t i = aNewSize; i < m.size; ++ i)
1143 SafeArray::Uninit(m.arr[i]);
1144
1145 m.size = aNewSize;
1146 }
1147
1148 /* Copy the old contents. */
1149 memcpy(newArr, m.arr, m.size * sizeof(T));
1150 nsMemory::Free((void *)m.arr);
1151 }
1152
1153 m.arr = newArr;
1154 }
1155 else
1156 {
1157 if (m.size > aNewSize)
1158 {
1159 /* Truncation takes place, uninit exceeding elements and
1160 * shrink the size. */
1161 for (size_t i = aNewSize; i < m.size; ++ i)
1162 SafeArray::Uninit(m.arr[i]);
1163
1164 m.size = aNewSize;
1165 }
1166 }
1167
1168 m.capacity = newCapacity;
1169
1170#else
1171
1172 SAFEARRAYBOUND bound = { VarCount(aNewSize), 0 };
1173 HRESULT rc;
1174
1175 if (m.arr == NULL)
1176 {
1177 m.arr = CreateSafeArray(VarType(), &bound);
1178 AssertReturn(m.arr != NULL, false);
1179 }
1180 else
1181 {
1182 SafeArrayUnaccessData(m.arr);
1183
1184 rc = SafeArrayRedim(m.arr, &bound);
1185 AssertComRCReturn(rc == S_OK, false);
1186 }
1187
1188 rc = SafeArrayAccessData(m.arr, (void HUGEP **)&m.raw);
1189 AssertComRCReturn(rc, false);
1190
1191#endif
1192 return true;
1193 }
1194
1195 struct Data
1196 {
1197 Data()
1198 : isWeak(false)
1199#ifdef VBOX_WITH_XPCOM
1200 , capacity(0), size(0), arr(NULL)
1201#else
1202 , arr(NULL), raw(NULL)
1203#endif
1204 {}
1205
1206 ~Data() { uninit(); }
1207
1208 void uninit()
1209 {
1210#ifdef VBOX_WITH_XPCOM
1211
1212 if (arr)
1213 {
1214 if (!isWeak)
1215 {
1216 for (size_t i = 0; i < size; ++ i)
1217 SafeArray::Uninit(arr[i]);
1218
1219 nsMemory::Free((void *)arr);
1220 }
1221 else
1222 isWeak = false;
1223
1224 arr = NULL;
1225 }
1226
1227 size = capacity = 0;
1228
1229#else /* !VBOX_WITH_XPCOM */
1230
1231 if (arr)
1232 {
1233 if (raw)
1234 {
1235 SafeArrayUnaccessData(arr);
1236 raw = NULL;
1237 }
1238
1239 if (!isWeak)
1240 {
1241 HRESULT rc = SafeArrayDestroy(arr);
1242 AssertComRCReturnVoid(rc);
1243 }
1244 else
1245 isWeak = false;
1246
1247 arr = NULL;
1248 }
1249
1250#endif /* !VBOX_WITH_XPCOM */
1251 }
1252
1253 bool isWeak : 1;
1254
1255#ifdef VBOX_WITH_XPCOM
1256 PRUint32 capacity;
1257 PRUint32 size;
1258 T *arr;
1259#else
1260 SAFEARRAY *arr;
1261 T *raw;
1262#endif
1263 };
1264
1265 Data m;
1266};
1267
1268/* Few fast specializations for primitive array types */
1269template<>
1270inline void com::SafeArray<BYTE>::initFrom(const com::SafeArray<BYTE> & aRef)
1271{
1272 size_t sSize = aRef.size();
1273 resize(sSize);
1274 ::memcpy(raw(), aRef.raw(), sSize);
1275}
1276template<>
1277inline void com::SafeArray<BYTE>::initFrom(const BYTE* aPtr, size_t aSize)
1278{
1279 resize(aSize);
1280 ::memcpy(raw(), aPtr, aSize);
1281}
1282
1283
1284template<>
1285inline void com::SafeArray<SHORT>::initFrom(const com::SafeArray<SHORT> & aRef)
1286{
1287 size_t sSize = aRef.size();
1288 resize(sSize);
1289 ::memcpy(raw(), aRef.raw(), sSize * sizeof(SHORT));
1290}
1291template<>
1292inline void com::SafeArray<SHORT>::initFrom(const SHORT* aPtr, size_t aSize)
1293{
1294 resize(aSize);
1295 ::memcpy(raw(), aPtr, aSize * sizeof(SHORT));
1296}
1297
1298template<>
1299inline void com::SafeArray<USHORT>::initFrom(const com::SafeArray<USHORT> & aRef)
1300{
1301 size_t sSize = aRef.size();
1302 resize(sSize);
1303 ::memcpy(raw(), aRef.raw(), sSize * sizeof(USHORT));
1304}
1305template<>
1306inline void com::SafeArray<USHORT>::initFrom(const USHORT* aPtr, size_t aSize)
1307{
1308 resize(aSize);
1309 ::memcpy(raw(), aPtr, aSize * sizeof(USHORT));
1310}
1311
1312template<>
1313inline void com::SafeArray<LONG>::initFrom(const com::SafeArray<LONG> & aRef)
1314{
1315 size_t sSize = aRef.size();
1316 resize(sSize);
1317 ::memcpy(raw(), aRef.raw(), sSize * sizeof(LONG));
1318}
1319template<>
1320inline void com::SafeArray<LONG>::initFrom(const LONG* aPtr, size_t aSize)
1321{
1322 resize(aSize);
1323 ::memcpy(raw(), aPtr, aSize * sizeof(LONG));
1324}
1325
1326
1327////////////////////////////////////////////////////////////////////////////////
1328
1329#ifdef VBOX_WITH_XPCOM
1330
1331/**
1332 * Version of com::SafeArray for arrays of GUID.
1333 *
1334 * In MS COM, GUID arrays store GUIDs by value and therefore input arrays are
1335 * represented using |GUID *| and out arrays -- using |GUID **|. In XPCOM,
1336 * GUID arrays store pointers to nsID so that input arrays are |const nsID **|
1337 * and out arrays are |nsID ***|. Due to this difference, it is impossible to
1338 * work with arrays of GUID on both platforms by simply using com::SafeArray
1339 * <GUID>. This class is intended to provide some level of cross-platform
1340 * behavior.
1341 *
1342 * The basic usage pattern is basically similar to com::SafeArray<> except that
1343 * you use ComSafeGUIDArrayIn* and ComSafeGUIDArrayOut* macros instead of
1344 * ComSafeArrayIn* and ComSafeArrayOut*. Another important nuance is that the
1345 * raw() array type is different (nsID **, or GUID ** on XPCOM and GUID * on MS
1346 * COM) so it is recommended to use operator[] instead which always returns a
1347 * GUID by value.
1348 *
1349 * Note that due to const modifiers, you cannot use SafeGUIDArray for input GUID
1350 * arrays. Please use SafeConstGUIDArray for this instead.
1351 *
1352 * Other than mentioned above, the functionality of this class is equivalent to
1353 * com::SafeArray<>. See the description of that template and its methods for
1354 * more information.
1355 *
1356 * Output GUID arrays are handled by a separate class, SafeGUIDArrayOut, since
1357 * this class cannot handle them because of const modifiers.
1358 */
1359class SafeGUIDArray : public SafeArray<nsID *>
1360{
1361public:
1362
1363 typedef SafeArray<nsID *> Base;
1364
1365 class nsIDRef
1366 {
1367 public:
1368
1369 nsIDRef(nsID * &aVal) : mVal(aVal) {}
1370
1371 operator const nsID &() const { return mVal ? *mVal : *Empty; }
1372 operator nsID() const { return mVal ? *mVal : *Empty; }
1373
1374 const nsID *operator&() const { return mVal ? mVal : Empty; }
1375
1376 nsIDRef &operator= (const nsID &aThat)
1377 {
1378 if (mVal == NULL)
1379 Copy(&aThat, mVal);
1380 else
1381 *mVal = aThat;
1382 return *this;
1383 }
1384
1385 private:
1386
1387 nsID * &mVal;
1388
1389 static const nsID *Empty;
1390
1391 friend class SafeGUIDArray;
1392 };
1393
1394 /** See SafeArray<>::SafeArray(). */
1395 SafeGUIDArray() {}
1396
1397 /** See SafeArray<>::SafeArray(size_t). */
1398 SafeGUIDArray(size_t aSize) : Base(aSize) {}
1399
1400 /**
1401 * Array access operator that returns an array element by reference. As a
1402 * special case, the return value of this operator on XPCOM is an nsID (GUID)
1403 * reference, instead of an nsID pointer (the actual SafeArray template
1404 * argument), for compatibility with the MS COM version.
1405 *
1406 * The rest is equivalent to SafeArray<>::operator[].
1407 */
1408 nsIDRef operator[] (size_t aIdx)
1409 {
1410 Assert(m.arr != NULL);
1411 Assert(aIdx < size());
1412 return nsIDRef(m.arr[aIdx]);
1413 }
1414
1415 /**
1416 * Const version of #operator[] that returns an array element by value.
1417 */
1418 const nsID &operator[] (size_t aIdx) const
1419 {
1420 Assert(m.arr != NULL);
1421 Assert(aIdx < size());
1422 return m.arr[aIdx] ? *m.arr[aIdx] : *nsIDRef::Empty;
1423 }
1424};
1425
1426/**
1427 * Version of com::SafeArray for const arrays of GUID.
1428 *
1429 * This class is used to work with input GUID array parameters in method
1430 * implementations. See SafeGUIDArray for more details.
1431 */
1432class SafeConstGUIDArray : public SafeArray<const nsID *,
1433 SafeArrayTraits<nsID *> >
1434{
1435public:
1436
1437 typedef SafeArray<const nsID *, SafeArrayTraits<nsID *> > Base;
1438
1439 /** See SafeArray<>::SafeArray(). */
1440 SafeConstGUIDArray() {}
1441
1442 /* See SafeArray<>::SafeArray(ComSafeArrayIn(T, aArg)). */
1443 SafeConstGUIDArray(ComSafeGUIDArrayIn(aArg))
1444 : Base(ComSafeGUIDArrayInArg(aArg)) {}
1445
1446 /**
1447 * Array access operator that returns an array element by reference. As a
1448 * special case, the return value of this operator on XPCOM is nsID (GUID)
1449 * instead of nsID *, for compatibility with the MS COM version.
1450 *
1451 * The rest is equivalent to SafeArray<>::operator[].
1452 */
1453 const nsID &operator[] (size_t aIdx) const
1454 {
1455 AssertReturn(m.arr != NULL, **((const nsID * *)NULL));
1456 AssertReturn(aIdx < size(), **((const nsID * *)NULL));
1457 return *m.arr[aIdx];
1458 }
1459
1460private:
1461
1462 /* These are disabled because of const. */
1463 bool reset(size_t aNewSize) { NOREF(aNewSize); return false; }
1464};
1465
1466#else /* !VBOX_WITH_XPCOM */
1467
1468typedef SafeArray<GUID> SafeGUIDArray;
1469typedef SafeArray<const GUID, SafeArrayTraits<GUID> > SafeConstGUIDArray;
1470
1471#endif /* !VBOX_WITH_XPCOM */
1472
1473////////////////////////////////////////////////////////////////////////////////
1474
1475#ifdef VBOX_WITH_XPCOM
1476
1477template<class I>
1478struct SafeIfaceArrayTraits
1479{
1480protected:
1481
1482 static void Init(I * &aElem) { aElem = NULL; }
1483 static void Uninit(I * &aElem)
1484 {
1485 if (aElem)
1486 {
1487 aElem->Release();
1488 aElem = NULL;
1489 }
1490 }
1491
1492 static void Copy(I * aFrom, I * &aTo)
1493 {
1494 if (aFrom != NULL)
1495 {
1496 aTo = aFrom;
1497 aTo->AddRef();
1498 }
1499 else
1500 aTo = NULL;
1501 }
1502
1503public:
1504
1505 /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard. */
1506 static I **__asInParam_Arr(I **aArr) { return aArr; }
1507 static I **__asInParam_Arr(const I **aArr) { return const_cast<I **>(aArr); }
1508};
1509
1510#else /* !VBOX_WITH_XPCOM */
1511
1512template<class I>
1513struct SafeIfaceArrayTraits
1514{
1515protected:
1516
1517 static VARTYPE VarType() { return VT_DISPATCH; }
1518 static ULONG VarCount(size_t aSize) { return (ULONG)aSize; }
1519 static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; }
1520
1521 static void Copy(I * aFrom, I * &aTo)
1522 {
1523 if (aFrom != NULL)
1524 {
1525 aTo = aFrom;
1526 aTo->AddRef();
1527 }
1528 else
1529 aTo = NULL;
1530 }
1531
1532 static SAFEARRAY *CreateSafeArray(VARTYPE aVarType, SAFEARRAYBOUND *aBound)
1533 {
1534 NOREF(aVarType);
1535 return SafeArrayCreateEx(VT_DISPATCH, 1, aBound, (PVOID)&_ATL_IIDOF(I));
1536 }
1537};
1538
1539#endif /* !VBOX_WITH_XPCOM */
1540
1541////////////////////////////////////////////////////////////////////////////////
1542
1543/**
1544 * Version of com::SafeArray for arrays of interface pointers.
1545 *
1546 * Except that it manages arrays of interface pointers, the usage of this class
1547 * is identical to com::SafeArray.
1548 *
1549 * @param I Interface class (no asterisk).
1550 */
1551template<class I>
1552class SafeIfaceArray : public SafeArray<I *, SafeIfaceArrayTraits<I> >
1553{
1554public:
1555
1556 typedef SafeArray<I *, SafeIfaceArrayTraits<I> > Base;
1557
1558 /**
1559 * Creates a null array.
1560 */
1561 SafeIfaceArray() {}
1562
1563 /**
1564 * Creates a new array of the given size. All elements of the newly created
1565 * array initialized with null values.
1566 *
1567 * @param aSize Initial number of elements in the array. Must be greater
1568 * than 0.
1569 *
1570 * @note If this object remains null after construction it means that there
1571 * was not enough memory for creating an array of the requested size.
1572 * The constructor will also assert in this case.
1573 */
1574 SafeIfaceArray(size_t aSize) { Base::resize(aSize); }
1575
1576 /**
1577 * Weakly attaches this instance to the existing array passed in a method
1578 * parameter declared using the ComSafeArrayIn macro. When using this call,
1579 * always wrap the parameter name in the ComSafeArrayOutArg macro call like
1580 * this:
1581 * <pre>
1582 * SafeArray safeArray(ComSafeArrayInArg(aArg));
1583 * </pre>
1584 *
1585 * Note that this constructor doesn't take the ownership of the array. In
1586 * particular, this means that operations that operate on the ownership
1587 * (e.g. #detachTo()) are forbidden and will assert.
1588 *
1589 * @param aArg Input method parameter to attach to.
1590 */
1591 SafeIfaceArray(ComSafeArrayIn(I *, aArg))
1592 {
1593 if (aArg)
1594 {
1595#ifdef VBOX_WITH_XPCOM
1596
1597 Base::m.size = aArgSize;
1598 Base::m.arr = aArg;
1599 Base::m.isWeak = true;
1600
1601#else /* !VBOX_WITH_XPCOM */
1602
1603 SAFEARRAY *arg = aArg;
1604
1605 AssertReturnVoid(arg->cDims == 1);
1606
1607 VARTYPE vt;
1608 HRESULT rc = SafeArrayGetVartype(arg, &vt);
1609 AssertComRCReturnVoid(rc);
1610 AssertMsgReturnVoid(vt == VT_UNKNOWN || vt == VT_DISPATCH,
1611 ("Expected vartype VT_UNKNOWN or VT_DISPATCH, got %d.\n",
1612 vt));
1613 GUID guid;
1614 rc = SafeArrayGetIID(arg, &guid);
1615 AssertComRCReturnVoid(rc);
1616 AssertMsgReturnVoid(InlineIsEqualGUID(_ATL_IIDOF(I), guid),
1617 ("Expected IID {%RTuuid}, got {%RTuuid}.\n",
1618 &_ATL_IIDOF(I), &guid));
1619
1620 rc = SafeArrayAccessData(arg, (void HUGEP **)&m.raw);
1621 AssertComRCReturnVoid(rc);
1622
1623 m.arr = arg;
1624 m.isWeak = true;
1625
1626#endif /* !VBOX_WITH_XPCOM */
1627 }
1628 }
1629
1630 /**
1631 * Creates a deep copy of the given standard C++ container that stores
1632 * interface pointers as objects of the ComPtr\<I\> class.
1633 *
1634 * @param aCntr Container object to copy.
1635 *
1636 * @tparam C Standard C++ container template class (normally deduced from
1637 * @c aCntr).
1638 * @tparam A Standard C++ allocator class (deduced from @c aCntr).
1639 * @tparam OI Argument to the ComPtr template (deduced from @c aCntr).
1640 */
1641 template<template<typename, typename> class C, class A, class OI>
1642 SafeIfaceArray(const C<ComPtr<OI>, A> & aCntr)
1643 {
1644 typedef C<ComPtr<OI>, A> List;
1645
1646 Base::resize(aCntr.size());
1647 AssertReturnVoid(!Base::isNull());
1648
1649 int i = 0;
1650 for (typename List::const_iterator it = aCntr.begin();
1651 it != aCntr.end(); ++ it, ++ i)
1652#ifdef VBOX_WITH_XPCOM
1653 this->Copy(*it, Base::m.arr[i]);
1654#else
1655 Copy(*it, Base::m.raw[i]);
1656#endif
1657 }
1658
1659 /**
1660 * Creates a deep copy of the given standard C++ container that stores
1661 * interface pointers as objects of the ComObjPtr\<I\> class.
1662 *
1663 * @param aCntr Container object to copy.
1664 *
1665 * @tparam C Standard C++ container template class (normally deduced from
1666 * @c aCntr).
1667 * @tparam A Standard C++ allocator class (deduced from @c aCntr).
1668 * @tparam OI Argument to the ComObjPtr template (deduced from @c aCntr).
1669 */
1670 template<template<typename, typename> class C, class A, class OI>
1671 SafeIfaceArray(const C<ComObjPtr<OI>, A> & aCntr)
1672 {
1673 typedef C<ComObjPtr<OI>, A> List;
1674
1675 Base::resize(aCntr.size());
1676 AssertReturnVoid(!Base::isNull());
1677
1678 int i = 0;
1679 for (typename List::const_iterator it = aCntr.begin();
1680 it != aCntr.end(); ++ it, ++ i)
1681#ifdef VBOX_WITH_XPCOM
1682 SafeIfaceArray::Copy(*it, Base::m.arr[i]);
1683#else
1684 Copy(*it, Base::m.raw[i]);
1685#endif
1686 }
1687
1688 /**
1689 * Creates a deep copy of the given standard C++ map whose values are
1690 * interface pointers stored as objects of the ComPtr\<I\> class.
1691 *
1692 * @param aMap Map object to copy.
1693 *
1694 * @tparam C Standard C++ map template class (normally deduced from
1695 * @c aCntr).
1696 * @tparam L Standard C++ compare class (deduced from @c aCntr).
1697 * @tparam A Standard C++ allocator class (deduced from @c aCntr).
1698 * @tparam K Map key class (deduced from @c aCntr).
1699 * @tparam OI Argument to the ComPtr template (deduced from @c aCntr).
1700 */
1701 template<template<typename, typename, typename, typename>
1702 class C, class L, class A, class K, class OI>
1703 SafeIfaceArray(const C<K, ComPtr<OI>, L, A> & aMap)
1704 {
1705 typedef C<K, ComPtr<OI>, L, A> Map;
1706
1707 Base::resize(aMap.size());
1708 AssertReturnVoid(!Base::isNull());
1709
1710 int i = 0;
1711 for (typename Map::const_iterator it = aMap.begin();
1712 it != aMap.end(); ++ it, ++ i)
1713#ifdef VBOX_WITH_XPCOM
1714 SafeIfaceArray::Copy(it->second, Base::m.arr[i]);
1715#else
1716 Copy(it->second, Base::m.raw[i]);
1717#endif
1718 }
1719
1720 /**
1721 * Creates a deep copy of the given standard C++ map whose values are
1722 * interface pointers stored as objects of the ComObjPtr\<I\> class.
1723 *
1724 * @param aMap Map object to copy.
1725 *
1726 * @tparam C Standard C++ map template class (normally deduced from
1727 * @c aCntr).
1728 * @tparam L Standard C++ compare class (deduced from @c aCntr).
1729 * @tparam A Standard C++ allocator class (deduced from @c aCntr).
1730 * @tparam K Map key class (deduced from @c aCntr).
1731 * @tparam OI Argument to the ComObjPtr template (deduced from @c aCntr).
1732 */
1733 template<template<typename, typename, typename, typename>
1734 class C, class L, class A, class K, class OI>
1735 SafeIfaceArray(const C<K, ComObjPtr<OI>, L, A> & aMap)
1736 {
1737 typedef C<K, ComObjPtr<OI>, L, A> Map;
1738
1739 Base::resize(aMap.size());
1740 AssertReturnVoid(!Base::isNull());
1741
1742 int i = 0;
1743 for (typename Map::const_iterator it = aMap.begin();
1744 it != aMap.end(); ++ it, ++ i)
1745#ifdef VBOX_WITH_XPCOM
1746 SafeIfaceArray::Copy(it->second, Base::m.arr[i]);
1747#else
1748 Copy(it->second, Base::m.raw[i]);
1749#endif
1750 }
1751
1752 void setElement(size_t iIdx, I* obj)
1753 {
1754#ifdef VBOX_WITH_XPCOM
1755 SafeIfaceArray::Copy(obj, Base::m.arr[iIdx]);
1756#else
1757 Copy(obj, Base::m.raw[iIdx]);
1758#endif
1759 }
1760};
1761
1762} /* namespace com */
1763
1764/** @} */
1765
1766#endif /* !___VBox_com_array_h */
1767
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette