VirtualBox

root/trunk/include/VBox/com/array.h

Revision 15051, 45.1 kB (checked in by vboxsync, 1 month ago)

Main: Cleaned up the long standing const BSTR = const (OLECHAR *) on WIn32 vs (const PRunichar) * on XPCOM clash. Cleaned up BSTR/GUID macros (IN_BSTR replaces INPTR BSTR, IN_GUID replaces INPTR GUIDPARAM, OUT_GUID replaces GUIDPARAMOUT).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
Line 
1 /** @file
2  * MS COM / XPCOM Abstraction Layer:
3  * Safe array helper class declaration
4  */
5
6 /*
7  * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8  *
9  * This file is part of VirtualBox Open Source Edition (OSE), as
10  * available from http://www.virtualbox.org. This file is free software;
11  * you can redistribute it and/or modify it under the terms of the GNU
12  * General Public License (GPL) as published by the Free Software
13  * Foundation, in version 2 as it comes in the "COPYING" file of the
14  * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15  * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16  *
17  * The contents of this file may alternatively be used under the terms
18  * of the Common Development and Distribution License Version 1.0
19  * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20  * VirtualBox OSE distribution, in which case the provisions of the
21  * CDDL are applicable instead of those of the GPL.
22  *
23  * You may elect to license modified versions of this file under the
24  * terms and conditions of either the GPL or the CDDL or both.
25  *
26  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27  * Clara, CA 95054 USA or visit http://www.sun.com if you need
28  * additional information or have any questions.
29  */
30
31 #ifndef ___VBox_com_array_h
32 #define ___VBox_com_array_h
33
34 /** @defgroup   grp_COM_arrays    COM/XPCOM Arrays
35  * @{
36  *
37  * The COM/XPCOM array support layer provides a cross-platform way to pass
38  * arrays to and from COM interface methods and consists of the com::SafeArray
39  * template and a set of ComSafeArray* macros part of which is defined in
40  * VBox/com/defs.h.
41  *
42  * This layer works with interface attributes and method parameters that have
43  * the 'safearray="yes"' attribute in the XIDL definition:
44  * @code
45
46     <interface name="ISomething" ...>
47
48       <method name="testArrays">
49         <param name="inArr" type="long" dir="in" safearray="yes"/>
50         <param name="outArr" type="long" dir="out" safearray="yes"/>
51         <param name="retArr" type="long" dir="return" safearray="yes"/>
52       </method>
53
54     </interface>
55
56  * @endcode
57  *
58  * Methods generated from this and similar definitions are implemented in
59  * component classes using the following declarations:
60  * @code
61
62     STDMETHOD(TestArrays) (ComSafeArrayIn (LONG, aIn),
63                            ComSafeArrayOut (LONG, aOut),
64                            ComSafeArrayOut (LONG, aRet));
65
66  * @endcode
67  *
68  * And the following function bodies:
69  * @code
70
71     STDMETHODIMP Component::TestArrays (ComSafeArrayIn (LONG, aIn),
72                                         ComSafeArrayOut (LONG, aOut),
73                                         ComSafeArrayOut (LONG, aRet))
74     {
75         if (ComSafeArrayInIsNull (aIn))
76             return E_INVALIDARG;
77         if (ComSafeArrayOutIsNull (aOut))
78             return E_POINTER;
79         if (ComSafeArrayOutIsNull (aRet))
80             return E_POINTER;
81
82         // Use SafeArray to access the input array parameter
83
84         com::SafeArray <LONG> in (ComSafeArrayInArg (aIn));
85
86         for (size_t i = 0; i < in.size(); ++ i)
87             LogFlow (("*** in[%u]=%d\n", i, in [i]));
88
89         // Use SafeArray to create the return array (the same technique is used
90         // for output array paramters)
91
92         SafeArray <LONG> ret (in.size() * 2);
93         for (size_t i = 0; i < in.size(); ++ i)
94         {
95             ret [i] = in [i];
96             ret [i + in.size()] = in [i] * 10;
97         }
98
99         ret.detachTo (ComSafeArrayOutArg (aRet));
100
101         return S_OK;
102     }
103
104  * @endcode
105  *
106  * Such methods can be called from the client code using the following pattern:
107  * @code
108
109     ComPtr <ISomething> component;
110
111     // ...
112
113     com::SafeArray <LONG> in (3);
114     in [0] = -1;
115     in [1] = -2;
116     in [2] = -3;
117
118     com::SafeArray <LONG> out;
119     com::SafeArray <LONG> ret;
120
121     HRESULT rc = component->TestArrays (ComSafeArrayAsInParam (in),
122                                         ComSafeArrayAsOutParam (out),
123                                         ComSafeArrayAsOutParam (ret));
124
125     if (SUCCEEDED (rc))
126         for (size_t i = 0; i < ret.size(); ++ i)
127             printf ("*** ret[%u]=%d\n", i, ret [i]);
128
129  * @endcode
130  *
131  * For interoperability with standard C++ containers, there is a template
132  * constructor that takes such a container as argument and performs a deep copy
133  * of its contents. This can be used in method implementations like this:
134  * @code
135
136     STDMETHODIMP Component::COMGETTER(Values) (ComSafeArrayOut (int, aValues))
137     {
138         // ... assume there is a |std::list <int> mValues| data member
139
140         com::SafeArray <int> values (mValues);
141         values.detachTo (ComSafeArrayOutArg (aValues));
142
143         return S_OK;
144     }
145
146  * @endcode
147  *
148  * The current implementation of the SafeArray layer supports all types normally
149  * allowed in XIDL as array element types (including 'wstring' and 'uuid').
150  * However, 'pointer-to-...' types (e.g. 'long *', 'wstring *') are not
151  * supported and therefore cannot be used as element types.
152  *
153  * Note that for GUID arrays you should use SafeGUIDArray and
154  * SafeConstGUIDArray, customized SafeArray<> specializations.
155  *
156  * Also note that in order to pass input BSTR array parameters declared
157  * using the ComSafeArrayIn (IN_BSTR, aParam) macro to the SafeArray<>
158  * constructor using the ComSafeArrayInArg() macro, you should use IN_BSTR
159  * as the SafeArray<> template argument, not just BSTR.
160  *
161  * Arrays of interface pointers are also supported but they require to use a
162  * special SafeArray implementation, com::SafeIfacePointer, which takes the
163  * interface class name as a template argument (e.g. com::SafeIfacePointer
164  * <IUnknown>). This implementation functions identically to com::SafeArray.
165  */
166
167 #if defined (VBOX_WITH_XPCOM)
168 # include <nsMemory.h>
169 #endif
170
171 #include "VBox/com/defs.h"
172 #include "VBox/com/ptr.h"
173 #include "VBox/com/assert.h"
174
175 #include "iprt/cpputils.h"
176
177 #if defined (VBOX_WITH_XPCOM)
178
179 /**
180  * Wraps the given com::SafeArray instance to generate an expression that is
181  * suitable for passing it to functions that take input safearray parameters
182  * declared using the ComSafeArrayIn macro.
183  *
184  * @param aArray    com::SafeArray instance to pass as an input parameter.
185  */
186 #define ComSafeArrayAsInParam(aArray)   \
187     (aArray).size(), (aArray).__asInParam_Arr ((aArray).raw())
188
189 /**
190  * Wraps the given com::SafeArray instance to generate an expression that is
191  * suitable for passing it to functions that take output safearray parameters
192  * declared using the ComSafeArrayOut macro.
193  *
194  * @param aArray    com::SafeArray instance to pass as an output parameter.
195  */
196 #define ComSafeArrayAsOutParam(aArray)  \
197     (aArray).__asOutParam_Size(), (aArray).__asOutParam_Arr()
198
199 #else /* defined (VBOX_WITH_XPCOM) */
200
201 #define ComSafeArrayAsInParam(aArray)   (aArray).__asInParam()
202
203 #define ComSafeArrayAsOutParam(aArray)  (aArray).__asOutParam()
204
205 #endif /* defined (VBOX_WITH_XPCOM) */
206
207 /**
208  *
209  */
210 namespace com
211 {
212
213 #if defined (VBOX_WITH_XPCOM)
214
215 ////////////////////////////////////////////////////////////////////////////////
216
217 /**
218  * Provides various helpers for SafeArray.
219  *
220  * @param T Type of array elements.
221  */
222 template <typename T>
223 struct SafeArrayTraits
224 {
225 protected:
226
227     /** Initializes memory for aElem. */
228     static void Init (T &aElem) { aElem = 0; }
229
230     /** Initializes memory occupied by aElem. */
231     static void Uninit (T &aElem) { aElem = 0; }
232
233     /** Creates a deep copy of aFrom and stores it in aTo. */
234     static void Copy (const T &aFrom, T &aTo) { aTo = aFrom; }
235
236 public:
237
238     /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard (that
239      * in particular forbid casts of 'char **' to 'const char **'). Then initial
240      * reason for this magic is that XPIDL declares input strings
241      * (char/PRUnichar pointers) as const but doesn't do so for pointers to
242      * arrays. */
243     static T *__asInParam_Arr (T *aArr) { return aArr; }
244     static T *__asInParam_Arr (const T *aArr) { return const_cast <T *> (aArr); }
245 };
246
247 template <typename T>
248 struct SafeArrayTraits <T *>
249 {
250     // Arbitrary pointers are not supported
251 };
252
253 template<>
254 struct SafeArrayTraits <PRUnichar *>
255 {
256 protected:
257
258     static void Init (PRUnichar * &aElem) { aElem = NULL; }
259
260     static void Uninit (PRUnichar * &aElem)
261     {
262         if (aElem)
263         {
264             ::SysFreeString (aElem);
265             aElem = NULL;
266         }
267     }
268
269     static void Copy (const PRUnichar * aFrom, PRUnichar * &aTo)
270     {
271         AssertCompile (sizeof (PRUnichar) == sizeof (OLECHAR));
272         aTo = aFrom ? ::SysAllocString ((const OLECHAR *) aFrom) : NULL;
273     }
274
275 public:
276
277     /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard */
278     static const PRUnichar **__asInParam_Arr (PRUnichar **aArr)
279     {
280         return const_cast <const PRUnichar **> (aArr);
281     }
282     static const PRUnichar **__asInParam_Arr (const PRUnichar **aArr) { return aArr; }
283 };
284
285 template<>
286 struct SafeArrayTraits <const PRUnichar *>
287 {
288 protected:
289
290     static void Init (const PRUnichar * &aElem) { aElem = NULL; }
291     static void Uninit (const PRUnichar * &aElem)
292     {
293         if (aElem)
294         {
295             ::SysFreeString (const_cast <PRUnichar *> (aElem));
296             aElem = NULL;
297         }
298     }
299
300     static void Copy (const PRUnichar * aFrom, const PRUnichar * &aTo)
301     {
302         AssertCompile (sizeof (PRUnichar) == sizeof (OLECHAR));
303         aTo = aFrom ? ::SysAllocString ((const OLECHAR *) aFrom) : NULL;
304     }
305
306 public:
307
308     /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard */
309     static const PRUnichar **__asInParam_Arr (const PRUnichar **aArr) { return aArr; }
310 };
311
312 template<>
313 struct SafeArrayTraits <nsID *>
314 {
315 protected:
316
317     static void Init (nsID * &aElem) { aElem = NULL; }
318
319     static void Uninit (nsID * &aElem)
320     {
321         if (aElem)
322         {
323             ::nsMemory::Free (aElem);
324             aElem = NULL;
325         }
326     }
327
328     static void Copy (const nsID * aFrom, nsID * &aTo)
329     {
330         if (aFrom)
331         {
332             aTo = (nsID *) ::nsMemory::Alloc (sizeof (nsID));
333             if (aTo)
334                 *aTo = *aFrom;
335         }
336         else
337             aTo = NULL;
338     }
339
340     /* This specification is also reused for SafeConstGUIDArray, so provide a
341      * no-op Init() and Uninit() which are necessary for SafeArray<> but should
342      * be never called in context of SafeConstGUIDArray. */
343
344     static void Init (const nsID * &aElem) { NOREF (aElem); AssertFailed(); }
345     static void Uninit (const nsID * &aElem) { NOREF (aElem); AssertFailed(); }
346
347 public:
348
349     /** Magic to workaround strict rules of par. 4.4.4 of the C++ standard. */
350     static const nsID **__asInParam_Arr (nsID **aArr)
351     {
352         return const_cast <const nsID **> (aArr);
353     }
354     static const nsID **__asInParam_Arr (const nsID **aArr) { return aArr; }
355 };
356
357 #else /* defined (VBOX_WITH_XPCOM) */
358
359 ////////////////////////////////////////////////////////////////////////////////
360
361 struct SafeArrayTraitsBase
362 {
363 protected:
364
365     static SAFEARRAY *CreateSafeArray (VARTYPE aVarType, SAFEARRAYBOUND *aBound)
366     { return SafeArrayCreate (aVarType, 1, aBound); }
367 };
368
369 /**
370  * Provides various helpers for SafeArray.
371  *
372  * @param T Type of array elements.
373  *
374  * Specializations of this template must provide the following methods:
375  *
376     // Returns the VARTYPE of COM SafeArray elements to be used for T
377     static VARTYPE VarType();
378
379     // Returns the number of VarType() elements necessary for aSize
380     // elements of T
381     static ULONG VarCount (size_t aSize);
382
383     // Returns the number of elements of T that fit into the given number of
384     // VarType() elements (opposite to VarCount (size_t aSize)).
385     static size_t Size (ULONG aVarCount);
386
387     // Creates a deep copy of aFrom and stores it in aTo
388     static void Copy (ULONG aFrom, ULONG &aTo);
389  */
390 template <typename T>
391 struct SafeArrayTraits : public SafeArrayTraitsBase
392 {
393 protected:
394
395     // Arbitrary types are treated as passed by value and each value is
396     // represented by a number of VT_Ix type elements where VT_Ix has the
397     // biggest possible bitness necessary to represent T w/o a gap. COM enums
398     // fall into this category.
399
400     static VARTYPE VarType()
401     {
402         if (sizeof (T) % 8 == 0) return VT_I8;
403         if (sizeof (T) % 4 == 0) return VT_I4;
404         if (sizeof (T) % 2 == 0) return VT_I2;
405         return VT_I1;
406     }
407
408     static ULONG VarCount (size_t aSize)
409     {
410         if (sizeof (T) % 8 == 0) return (ULONG) ((sizeof (T) / 8) * aSize);
411         if (sizeof (T) % 4 == 0) return (ULONG) ((sizeof (T) / 4) * aSize);
412         if (sizeof (T) % 2 == 0) return (ULONG) ((sizeof (T) / 2) * aSize);
413         return (ULONG) (sizeof (T) * aSize);
414     }
415
416     static size_t Size (ULONG aVarCount)
417     {
418         if (sizeof (T) % 8 == 0) return (size_t) (aVarCount * 8) / sizeof (T);
419         if (sizeof (T) % 4 == 0) return (size_t) (aVarCount * 4) / sizeof (T);
420         if (sizeof (T) % 2 == 0) return (size_t) (aVarCount * 2) / sizeof (T);
421         return (size_t) aVarCount / sizeof (T);
422     }
423
424     static void Copy (T aFrom, T &aTo) { aTo = aFrom; }
425 };
426
427 template <typename T>
428 struct SafeArrayTraits <T *>
429 {
430     // Arbitrary pointer types are not supported
431 };
432
433 /* Although the generic SafeArrayTraits template would work for all integers,
434  * we specialize it for some of them in order to use the correct VT_ type */
435
436 template<>
437 struct SafeArrayTraits <LONG> : public SafeArrayTraitsBase
438 {
439 protected:
440
441     static VARTYPE VarType() { return VT_I4; }
442     static ULONG VarCount (size_t aSize) { return (ULONG) aSize; }
443     static size_t Size (ULONG aVarCount) { return (size_t) aVarCount; }
444
445     static void Copy (LONG aFrom, LONG &aTo) { aTo = aFrom; }
446 };
447
448 template<>
449 struct SafeArrayTraits <ULONG> : public SafeArrayTraitsBase
450 {
451 protected:
452
453     static VARTYPE VarType() { return VT_UI4; }
454     static ULONG VarCount (size_t aSize) { return (ULONG) aSize; }
455     static size_t Size (ULONG aVarCount) { return (size_t) aVarCount; }
456
457     static void Copy (ULONG aFrom, ULONG &aTo) { aTo = aFrom; }
458 };
459
460 template<>
461 struct SafeArrayTraits <LONG64> : public SafeArrayTraitsBase
462 {
463 protected:
464
465     static VARTYPE VarType() { return VT_I8; }
466     static ULONG VarCount (size_t aSize) { return (ULONG) aSize; }
467     static size_t Size (ULONG aVarCount) { return (size_t) aVarCount; }
468
469     static void Copy (LONG64 aFrom, LONG64 &aTo) { aTo = aFrom; }
470 };
471
472 template<>
473 struct SafeArrayTraits <ULONG64> : public SafeArrayTraitsBase
474 {
475 protected:
476
477     static VARTYPE VarType() { return VT_UI8; }
478     static ULONG VarCount (size_t aSize) { return (ULONG) aSize; }
479     static size_t Size (ULONG aVarCount) { return (size_t) aVarCount; }
480
481     static void Copy (ULONG64 aFrom, ULONG64 &aTo) { aTo = aFrom; }
482 };
483
484 template<>
485 struct SafeArrayTraits <BSTR> : public SafeArrayTraitsBase
486 {
487 protected:
488
489     static VARTYPE VarType() { return VT_BSTR; }
490     static ULONG VarCount (size_t aSize) { return (ULONG) aSize; }
491     static size_t Size (ULONG aVarCount) { return (size_t) aVarCount; }
492
493     static void Copy (BSTR aFrom, BSTR &aTo)
494     {
495         aTo = aFrom ? ::SysAllocString ((const OLECHAR *) aFrom) : NULL;
496     }
497 };
498
499 template<>
500 struct SafeArrayTraits <GUID> : public SafeArrayTraitsBase
501 {
502 protected:
503
504     /* Use the 64-bit unsigned integer type for GUID */
505     static VARTYPE VarType() { return VT_UI8; }
506
507     /* GUID is 128 bit, so we need two VT_UI8 */
508     static ULONG VarCount (size_t aSize)
509     {
510         AssertCompileSize (GUID, 16);
511         return (ULONG) (aSize * 2);
512     }
513
514     static size_t Size (ULONG aVarCount) { return (size_t) aVarCount / 2; }
515
516     static void Copy (GUID aFrom, GUID &aTo) { aTo = aFrom; }
517 };
518
519 /**
520  * Helper for SafeArray::__asOutParam() that automatically updates m.raw after a
521  * non-NULL m.arr assignment.
522  */
523 class OutSafeArrayDipper
524 {
525     OutSafeArrayDipper (SAFEARRAY **aArr, void **aRaw)
526         : arr (aArr), raw (aRaw) { Assert (*aArr == NULL && *aRaw == NULL); }
527
528     SAFEARRAY **arr;
529     void **raw;
530
531     template <class, class> friend class SafeArray;
532
533 public:
534
535     ~OutSafeArrayDipper()
536     {
537         if (*arr != NULL)
538         {
539             HRESULT rc = SafeArrayAccessData (*arr, raw);
540             AssertComRC (rc);
541         }
542     }
543
544     operator SAFEARRAY **() { return arr; }
545 };
546
547 #endif /* defined (VBOX_WITH_XPCOM) */
548
549 ////////////////////////////////////////////////////////////////////////////////
550
551 /**
552  * The SafeArray class represents the safe array type used in COM to pass arrays
553  * to/from interface methods.
554  *
555  * This helper class hides all MSCOM/XPCOM specific implementation details and,
556  * together with ComSafeArrayIn, ComSafeArrayOut and ComSafeArrayRet macros,
557  * provides a platform-neutral way to handle safe arrays in the method
558  * implementation.
559  *
560  * When an instance of this class is destroyed, it automatically frees all
561  * resources occupied by individual elements of the array as well as by the
562  * array itself. However, when the value of an element is manually changed
563  * using #operator[] or by accessing array data through the #raw() pointer, it is
564  * the caller's responsibility to free resources occupied by the previous
565  * element's value.
566  *
567  * Also, objects of this class do not support copy and assignment operations and
568  * therefore cannot be returned from functions by value. In other words, this
569  * class is just a temporary storage for handling interface method calls and not
570  * intended to be used to store arrays as data members and such -- you should
571  * use normal list/vector classes for that.
572  *
573  * @note The current implementation supports only one-dimensional arrays.
574  *
575  * @note This class is not thread-safe.
576  */
577 template  <typename T, class Traits = SafeArrayTraits <T> >
578 class SafeArray : public Traits
579 {
580 public:
581
582     /**
583      * Creates a null array.
584      */
585     SafeArray() {}
586
587     /**
588      * Creates a new array of the given size. All elements of the newly created
589      * array initialized with null values.
590      *
591      * @param aSize     Initial number of elements in the array.
592      *
593      * @note If this object remains null after construction it means that there
594      *       was not enough memory for creating an array of the requested size.
595      *       The constructor will also assert in this case.
596      */
597     SafeArray (size_t aSize) { resize (aSize); }
598
599     /**
600      * Weakly attaches this instance to the existing array passed in a method
601      * parameter declared using the ComSafeArrayIn macro. When using this call,
602      * always wrap the parameter name in the ComSafeArrayInArg macro call like
603      * this:
604      * <pre>
605      *  SafeArray safeArray (ComSafeArrayInArg (aArg));
606      * </pre>
607      *
608      * Note that this constructor doesn't take the ownership of the array. In
609      * particular, it means that operations that operate on the ownership (e.g.
610      * #detachTo()) are forbidden and will assert.
611      *
612      * @param aArg  Input method parameter to attach to.
613      */
614     SafeArray (ComSafeArrayIn (T, aArg))
615     {
616 #if defined (VBOX_WITH_XPCOM)
617
618         AssertReturnVoid (aArg != NULL);
619
620         m.size = aArgSize;
621         m.arr = aArg;
622         m.isWeak = true;
623
624 #else /* defined (VBOX_WITH_XPCOM) */
625
626         AssertReturnVoid (aArg != NULL);
627         SAFEARRAY *arg = *aArg;
628
629         if (arg)
630         {
631             AssertReturnVoid (arg->cDims == 1);
632
633             VARTYPE vt;
634             HRESULT rc = SafeArrayGetVartype (arg, &vt);
635             AssertComRCReturnVoid (rc);
636             AssertMsgReturnVoid (vt == VarType(),
637                                  ("Expected vartype %d, got %d.\n",
638                                   VarType(), vt));
639
640             rc = SafeArrayAccessData (arg, (void HUGEP **) &m.raw);
641             AssertComRCReturnVoid (rc);
642         }
643
644         m.arr = arg;
645         m.isWeak = true;
646
647 #endif /* defined (VBOX_WITH_XPCOM) */
648     }
649
650     /**
651      * Creates a deep copy of the given standard C++ container.
652      *
653      * @param aCntr Container object to copy.
654      *
655      * @param C     Standard C++ container template class (normally deduced from
656      *              @c aCntr).
657      */
658     template <template <typename, typename> class C, class A>
659     SafeArray (const C <T, A> & aCntr)
660     {
661         resize (aCntr.size());
662         AssertReturnVoid (!isNull());
663
664         size_t i = 0;
665         for (typename C <T, A>::const_iterator it = aCntr.begin();
666              it != aCntr.end(); ++ it, ++ i)
667 #if defined (VBOX_WITH_XPCOM)
668             Copy (*it, m.arr [i]);
669 #else
670             Copy (*it, m.raw [i]);
671 #endif
672     }
673
674     /**
675      * Destroys this instance after calling #setNull() to release allocated
676      * resources. See #setNull() for more details.
677      */
678     virtual ~SafeArray() { setNull(); }
679
680     /**
681      * Returns @c true if this instance represents a null array.
682      */
683     bool isNull() const { return m.arr == NULL; }
684
685     /**
686      * Resets this instance to null and, if this instance is not a weak one,
687      * releases any resources occupied by the array data.
688      *
689      * @note This method destroys (cleans up) all elements of the array using
690      *       the corresponding cleanup routine for the element type before the
691      *       array itself is destroyed.
692      */
693     virtual void setNull() { m.uninit(); }
694
695     /**
696      * Returns @c true if this instance is weak. A weak instance doesn't own the
697      * array data and therefore operations manipulating the ownership (e.g.
698      * #detachTo()) are forbidden and will assert.
699      */
700     bool isWeak() const { return m.isWeak; }
701
702     /** Number of elements in the array. */
703     size_t size() const
704     {
705 #if defined (VBOX_WITH_XPCOM)
706         if (m.arr)
707             return m.size;
708         return 0;
709 #else
710         if (m.arr)
711             return Size (m.arr->rgsabound [0].cElements);
712         return 0;
713 #endif
714     }
715
716     /**
717      * Appends a copy of the given element at the end of the array.
718      *
719      * The array size is increased by one by this method and the additional
720      * space is allocated as needed.
721      *
722      * This method is handy in cases where you want to assign a copy of the
723      * existing value to the array element, for example:
724      * <tt>Bstr string; array.push_back (string);</tt>. If you create a string
725      * just to put it to the array, you may find #appendedRaw() more useful.
726      *
727      * @param aElement Element to append.
728      *
729      * @return          @c true on success and false if there is not enough
730      *                  memory for resizing.
731      */
732     bool push_back (const T &aElement)
733     {
734         if (!ensureCapacity (size() + 1))
735             return false;
736
737 #if defined (VBOX_WITH_XPCOM)
738         Copy (aElement, m.arr [m.size]);
739         ++ m.size;
740 #else
741         Copy (aElement, m.raw [size() - 1]);
742 #endif
743         return true;
744     }
745
746     /**
747      * Appends an empty element at the end of the array and returns a raw
748      * pointer to it suitable for assigning a raw value (w/o constructing a
749      * copy).
750      *
751      * The array size is increased by one by this method and the additional
752      * space is allocated as needed.
753      *
754      * Note that in case of raw assignment, value ownership (for types with
755      * dynamically allocated data and for interface pointers) is transferred to
756      * the safe array object.
757      *
758      * This method is handy for operations like
759      * <tt>Bstr ("foo").detacTo (array.appendedRaw());</tt>. Don't use it as
760      * l-value (<tt>array.appendedRaw() = SysAllocString (L"tralala");</tt>)
761      * since this doesn't check for a NULL condition; use #resize() and
762      * #setRawAt() instead. If you need to assign a copy of the existing value
763      * instead of transferring the ownership, look at #push_back().
764      *
765      * @return          Raw pointer to the added element or NULL if no memory.
766      */
767     T *appendedRaw()
768     {
769         if (!ensureCapacity (size() + 1))
770             return NULL;
771
772 #if defined (VBOX_WITH_XPCOM)
773         Init (m.arr [m.size]);
774         ++ m.size;
775         return &m.arr [m.size - 1];
776 #else
777         /* nothing to do here, SafeArrayCreate() has performed element
778          * initialization */
779         return &m.raw [size() - 1];
780 #endif
781     }
782
783     /**
784      * Resizes the array preserving its contents when possible. If the new size
785      * is larget than the old size, new elements are initialized with null
786      * values. If the new size is less than the old size, the contents of the
787      * array beyond the new size is lost.
788      *
789      * @param aNewSize  New number of elements in the array.
790      * @return          @c true on success and false if there is not enough
791      *                  memory for resizing.
792      */
793     bool resize (size_t aNewSize)
794     {
795         if (!ensureCapacity (aNewSize))
796             return false;
797
798 #if defined (VBOX_WITH_XPCOM)
799
800         if (m.size < aNewSize)
801         {
802             /* initialize the new elements */
803             for (size_t i = m.size; i < aNewSize; ++ i)
804                 Init (m.arr [i]);
805         }
806
807         m.size = aNewSize;
808 #else
809         /* nothing to do here, SafeArrayCreate() has performed element
810          * initialization */
811 #endif
812         return true;
813     }
814
815     /**
816      * Reinitializes this instance by preallocating space for the given number
817      * of elements. The previous array contents is lost.
818      *
819      * @param aNewSize  New number of elements in the array.
820      * @return          @c true on success and false if there is not enough
821      *                  memory for resizing.
822      */
823     bool reset (size_t aNewSize)
824     {
825         m.uninit();
826         return resize (aNewSize);
827     }
828
829     /**
830      * Returns a pointer to the raw array data. Use this raw pointer with care
831      * as no type or bound checking is done for you in this case.
832      *
833      * @note This method returns @c NULL when this instance is null.
834      * @see #operator[]
835      */
836     T *raw()
837     {
838 #if defined (VBOX_WITH_XPCOM)
839         return m.arr;
840 #else
841         return m.raw;
842 #endif
843     }
844
845     /**
846      * Const version of #raw().
847      */
848     const T *raw() const
849     {
850 #if defined (VBOX_WITH_XPCOM)
851         return m.arr;
852 #else
853         return m.raw;
854 #endif
855     }
856
857     /**
858      * Array access operator that returns an array element by reference. A bit
859      * safer than #raw(): asserts and returns an invalid reference if this
860      * instance is null or if the index is out of bounds.
861      *
862      * @note For weak instances, this call will succeed but the behavior of
863      *       changing the contents of an element of the weak array instance is
864      *       undefined and may lead to a program crash on some platforms.
865      */
866     T &operator[] (size_t aIdx)
867     {
868         AssertReturn (m.arr != NULL,  *((T *) NULL));
869         AssertReturn (aIdx < size(), *((T *) NULL));
870 #if defined (VBOX_WITH_XPCOM)
871         return m.arr [aIdx];
872 #else
873         AssertReturn (m.raw != NULL,  *((T *) NULL));
874         return m.raw [aIdx];
875 #endif
876     }
877
878     /**
879      * Const version of #operator[] that returns an array element by value.
880      */
881     const T operator[] (size_t aIdx) const
882     {
883         AssertReturn (m.arr != NULL,  *((T *) NULL));
884         AssertReturn (aIdx < size(), *((T *) NULL));
885 #if defined (VBOX_WITH_XPCOM)
886         return m.arr [aIdx];
887 #else
888         AssertReturn (m.raw != NULL,  *((T *) NULL));
889         return m.raw [aIdx];
890 #endif
891     }
892
893     /**
894      * Creates a copy of this array and stores it in a method parameter declared
895      * using the ComSafeArrayOut macro. When using this call, always wrap the
896      * parameter name in the ComSafeArrayOutArg macro call like this:
897      * <pre>
898      *  safeArray.cloneTo (ComSafeArrayOutArg (aArg));
899      * </pre>
900      *
901      * @note It is assumed that the ownership of the returned copy is
902      * transferred to the caller of the method and he is responsible to free the
903      * array data when it is no more necessary.
904      *
905      * @param aArg  Output method parameter to clone to.
906      */
907     virtual const SafeArray &cloneTo (ComSafeArrayOut (T, aArg)) const
908     {
909         /// @todo Implement me!
910 #if defined (VBOX_WITH_XPCOM)
911         NOREF (aArgSize);
912         NOREF (aArg);
913 #else
914         NOREF (aArg);
915 #