VirtualBox

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

Last change on this file since 8155 was 8155, checked in by vboxsync, 16 years ago

The Big Sun Rebranding Header Change

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 29.4 KB
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#include <VBox/com/ptr.h>
35
36/** @defgroup grp_COM_arrays COM/XPCOM Arrays
37 * @{
38 *
39 * The COM/XPCOM array support layer provides a cross-platform way to pass
40 * arrays to and from COM interface methods and consists of the com::SafeArray
41 * template and a set of ComSafeArray* macros part of which is defined in
42 * VBox/com/defs.h.
43 *
44 * This layer works with interface attributes and method parameters that have
45 * the 'safearray="yes"' attribute in the XIDL definition:
46 * @code
47
48 <interface name="ISomething" ...>
49
50 <method name="testArrays">
51 <param name="inArr" type="long" dir="in" safearray="yes"/>
52 <param name="outArr" type="long" dir="out" safearray="yes"/>
53 <param name="retArr" type="long" dir="return" safearray="yes"/>
54 </method>
55
56 </interface>
57
58 * @endcode
59 *
60 * Methods generated from this and similar definitions are implemented in
61 * component classes using the following declarations:
62 * @code
63
64 STDMETHOD(TestArrays) (ComSafeArrayIn (LONG, aIn),
65 ComSafeArrayOut (LONG, aOut),
66 ComSafeArrayOut (LONG, aRet));
67
68 * @endcode
69 *
70 * And the following function bodies:
71 * @code
72
73 STDMETHODIMP Component::TestArrays (ComSafeArrayIn (LONG, aIn),
74 ComSafeArrayOut (LONG, aOut),
75 ComSafeArrayOut (LONG, aRet))
76 {
77 if (ComSafeArrayInIsNull (aIn))
78 return E_INVALIDARG;
79 if (ComSafeArrayOutIsNull (aOut))
80 return E_POINTER;
81 if (ComSafeArrayOutIsNull (aRet))
82 return E_POINTER;
83
84 // Use SafeArray to access the input array parameter
85
86 com::SafeArray <LONG> in (ComSafeArrayInArg (aIn));
87
88 for (size_t i = 0; i < in.size(); ++ i)
89 LogFlow (("*** in[%u]=%d\n", i, in [i]));
90
91 // Use SafeArray to create the return array (the same technique is used
92 // for output array paramters)
93
94 SafeArray <LONG> ret (in.size() * 2);
95 for (size_t i = 0; i < in.size(); ++ i)
96 {
97 ret [i] = in [i];
98 ret [i + in.size()] = in [i] * 10;
99 }
100
101 ret.detachTo (ComSafeArrayOutArg (aRet));
102
103 return S_OK;
104 }
105
106 * @endcode
107 *
108 * Such methods can be called from the client code using the following pattern:
109 * @code
110
111 ComPtr <ISomething> component;
112
113 // ...
114
115 com::SafeArray <LONG> in (3);
116 in [0] = -1;
117 in [1] = -2;
118 in [2] = -3;
119
120 com::SafeArray <LONG> out;
121 com::SafeArray <LONG> ret;
122
123 HRESULT rc = component->TestArrays (ComSafeArrayAsInParam (in),
124 ComSafeArrayAsOutParam (out),
125 ComSafeArrayAsOutParam (ret));
126
127 if (SUCCEEDED (rc))
128 for (size_t i = 0; i < ret.size(); ++ i)
129 printf ("*** ret[%u]=%d\n", i, ret [i]);
130
131 * @endcode
132 *
133 * For interoperability with standard C++ containers, there is a template
134 * constructor that takes such a container as argument and performs a deep copy
135 * of its contents. This can be used in method implementations like this:
136 * @code
137
138 STDMETHODIMP Component::COMGETTER(Values) (ComSafeArrayOut (int, aValues))
139 {
140 // ... assume there is a |std::list <int> mValues| data member
141
142 com::SafeArray <int> values (mValues);
143 values.detachTo (ComSafeArrayOutArg (aValues));
144
145 return S_OK;
146 }
147
148 * @endcode
149 *
150 * The current implementation of the SafeArray layer supports all types normally
151 * allowed in XIDL as array element types (including 'wstring' and 'uuid').
152 * However, 'pointer-to-...' types (e.g. 'long *', 'wstring *') are not
153 * supported and therefore cannot be used as element types.
154 *
155 * Arrays of interface pointers are also supported but they require to use a
156 * special SafeArray implementation, com::SafeIfacePointer, which takes the
157 * interface class name as a template argument (e.g. com::SafeIfacePointer
158 * <IUnknown>). This implementation functions identically to com::SafeArray.
159 */
160
161#if defined (VBOX_WITH_XPCOM)
162#include <nsMemory.h>
163#endif
164
165#include "VBox/com/defs.h"
166#include "VBox/com/assert.h"
167
168#include "iprt/cpputils.h"
169
170#if defined (VBOX_WITH_XPCOM)
171
172/**
173 * Wraps the given com::SafeArray instance to generate an expression that is
174 * suitable for passing it to functions that take input safearray parameters
175 * declared using the ComSafeArrayIn marco.
176 *
177 * @param aArray com::SafeArray instance to pass as an input parameter.
178 */
179#define ComSafeArrayAsInParam(aArray) \
180 (aArray).size(), (aArray).__asInParam_Arr (aArray.raw())
181
182/**
183 * Wraps the given com::SafeArray instance to generate an expression that is
184 * suitable for passing it to functions that take output safearray parameters
185 * declared using the ComSafeArrayOut marco.
186 *
187 * @param aArray com::SafeArray instance to pass as an output parameter.
188 */
189#define ComSafeArrayAsOutParam(aArray) \
190 (aArray).__asOutParam_Size(), (aArray).__asOutParam_Arr()
191
192#else /* defined (VBOX_WITH_XPCOM) */
193
194#define ComSafeArrayAsInParam(aArray) (aArray).__asInParam()
195
196#define ComSafeArrayAsOutParam(aArray) (aArray).__asOutParam()
197
198#endif /* defined (VBOX_WITH_XPCOM) */
199
200/**
201 *
202 */
203namespace com
204{
205
206#if defined (VBOX_WITH_XPCOM)
207
208////////////////////////////////////////////////////////////////////////////////
209
210/**
211 * Contains various helper constants for SafeArray.
212 */
213template <typename T>
214struct SafeArrayTraits
215{
216 static void Init (T &aElem) { aElem = 0; }
217 static void Uninit (T &aElem) { aElem = 0; }
218 static void Copy (const T &aFrom, T &aTo) { aTo = aFrom; }
219
220 /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard (that
221 * in particular forbid casts of 'char **' to 'const char **'). Then initial
222 * reason for this magic is that XPIDL declares input strings
223 * (char/PRUnichar pointers) as const but doesn't do so for pointers to
224 * arrays. */
225 static T *__asInParam_Arr (T *aArr) { return aArr; }
226 static T *__asInParam_Arr (const T *aArr) { return const_cast <T *> (aArr); }
227};
228
229template <typename T>
230struct SafeArrayTraits <T *>
231{
232 // Arbitrary pointers are not supported
233};
234
235template<>
236struct SafeArrayTraits <PRUnichar *>
237{
238 static void Init (PRUnichar * &aElem) { aElem = NULL; }
239 static void Uninit (PRUnichar * &aElem)
240 {
241 if (aElem)
242 {
243 ::SysFreeString (aElem);
244 aElem = NULL;
245 }
246 }
247
248 static void Copy (const PRUnichar * aFrom, PRUnichar * &aTo)
249 {
250 AssertCompile (sizeof (PRUnichar) == sizeof (OLECHAR));
251 aTo = aFrom ? ::SysAllocString ((const OLECHAR *) aFrom) : NULL;
252 }
253
254 /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard */
255 static const PRUnichar **__asInParam_Arr (PRUnichar **aArr)
256 {
257 return const_cast <const PRUnichar **> (aArr);
258 }
259 static const PRUnichar **__asInParam_Arr (const PRUnichar **aArr) { return aArr; }
260};
261
262#else /* defined (VBOX_WITH_XPCOM) */
263
264////////////////////////////////////////////////////////////////////////////////
265
266/**
267 * Contains various helper constants for SafeArray.
268 */
269template <typename T>
270struct SafeArrayTraits
271{
272 // Arbitrary types are not supported
273};
274
275template<>
276struct SafeArrayTraits <LONG>
277{
278 static VARTYPE VarType() { return VT_I4; }
279 static void Copy (LONG aFrom, LONG &aTo) { aTo = aFrom; }
280};
281
282template<>
283struct SafeArrayTraits <ULONG>
284{
285 static VARTYPE VarType() { return VT_UI4; }
286 static void Copy (ULONG aFrom, ULONG &aTo) { aTo = aFrom; }
287};
288
289template<>
290struct SafeArrayTraits <BSTR>
291{
292 static VARTYPE VarType() { return VT_BSTR; }
293
294 static void Copy (BSTR aFrom, BSTR &aTo)
295 {
296 aTo = aFrom ? ::SysAllocString ((const OLECHAR *) aFrom) : NULL;
297 }
298};
299
300#endif /* defined (VBOX_WITH_XPCOM) */
301
302////////////////////////////////////////////////////////////////////////////////
303
304/**
305 * The SafeArray class represents the safe array type used in COM to pass arrays
306 * to/from interface methods.
307 *
308 * This helper class hides all MSCOM/XPCOM specific implementation details and,
309 * together with ComSafeArrayIn, ComSafeArrayOut and ComSafeArrayRet macros,
310 * provides a platform-neutral way to handle safe arrays in the method
311 * implementation.
312 *
313 * When an instance of this class is destroyed, it automatically frees all
314 * resources occupied by individual elements of the array as well as by the
315 * array itself. However, when the value of an element is manually changed
316 * using #operator[] or by acessing array data through the #raw() pointer, it is
317 * the caller's responsibility to free resources occupied by the previous
318 * element's value.
319 *
320 * Also, objects of this class do not support copy and assignment operations and
321 * therefore cannot be returned from functions by value. In other words, this
322 * class is just a temporary storage for handling interface method calls and not
323 * intended to be used to store arrays as data members and such -- you should
324 * use normal list/vector classes for that.
325 *
326 * @note The current implementation supports only one-dimentional arrays.
327 *
328 * @note This class is not thread-safe.
329 */
330template <typename T, class Traits = SafeArrayTraits <T> >
331class SafeArray : protected Traits
332{
333public:
334
335 /**
336 * Creates a null array.
337 */
338 SafeArray() {}
339
340 /**
341 * Creates a new array of the given size. All elements of the newly created
342 * array initialized with null values.
343 *
344 * @param aSize Initial number of elements in the array. Must be greater
345 * than 0.
346 *
347 * @note If this object remains null after construction it means that there
348 * was not enough memory for creating an array of the requested size.
349 * The constructor will also assert in this case.
350 */
351 SafeArray (size_t aSize) { reset (aSize); }
352
353 /**
354 * Weakly attaches this instance to the existing array passed in a method
355 * parameter declared using the ComSafeArrayIn macro. When using this call,
356 * always wrap the parameter name in the ComSafeArrayOutArg macro call like
357 * this:
358 * <pre>
359 * SafeArray safeArray (ComSafeArrayInArg (aArg));
360 * </pre>
361 *
362 * Note that this constructor doesn't take the ownership of the array. In
363 * particular, it means that operations that operate on the ownership (e.g.
364 * #detachTo()) are forbidden and will assert.
365 *
366 * @param aArg Input method parameter to attach to.
367 */
368 SafeArray (ComSafeArrayIn (T, aArg))
369 {
370#if defined (VBOX_WITH_XPCOM)
371
372 AssertReturnVoid (aArg != NULL);
373
374 m.size = aArgSize;
375 m.arr = aArg;
376 m.isWeak = true;
377
378#else /* defined (VBOX_WITH_XPCOM) */
379
380 AssertReturnVoid (aArg != NULL);
381 SAFEARRAY *arg = *aArg;
382
383 if (arg)
384 {
385 AssertReturnVoid (arg->cDims == 1);
386
387 VARTYPE vt;
388 HRESULT rc = SafeArrayGetVartype (arg, &vt);
389 AssertComRCReturnVoid (rc);
390 AssertMsgReturnVoid (vt == VarType(),
391 ("Expected vartype %d, got %d.\n",
392 VarType(), vt));
393 }
394
395 m.arr = arg;
396 m.isWeak = true;
397
398 AssertReturnVoid (accessRaw() != NULL);
399
400#endif /* defined (VBOX_WITH_XPCOM) */
401 }
402
403 /**
404 * Creates a deep copy of the goven standard C++ container.
405 *
406 * @param aCntr Container object to copy.
407 *
408 * @param C Standard C++ container template class (normally deduced from
409 * @c aCntr).
410 */
411 template <template <class> class C>
412 SafeArray (const C <T> & aCntr)
413 {
414 reset (aCntr.size());
415 AssertReturnVoid (!isNull());
416
417 int i = 0;
418 for (typename C <T>::const_iterator it = aCntr.begin();
419 it != aCntr.end(); ++ it, ++ i)
420#if defined (VBOX_WITH_XPCOM)
421 Copy (*it, m.arr [i]);
422#else
423 Copy (*it, m.raw [i]);
424#endif
425 }
426
427 /**
428 * Destroys this instance after calling #setNull() to release allocated
429 * resources. See #setNull() for more details.
430 */
431 virtual ~SafeArray() { setNull(); }
432
433 /**
434 * Returns @c true if this instance represents a null array.
435 */
436 bool isNull() const { return m.arr == NULL; }
437
438 /**
439 * Resets this instance to null and, if this instance is not a weak one,
440 * releases any resources ocuppied by the array data.
441 *
442 * @note This method destroys (cleans up) all elements of the array using
443 * the corresponding cleanup routine for the element type before the
444 * array itself is destroyed.
445 */
446 virtual void setNull() { m.uninit(); }
447
448 /**
449 * Returns @c true if this instance is weak. A weak instance doesn't own the
450 * array data and therefore operations manipulating the ownership (e.g.
451 * #detachTo()) are forbidden and will assert.
452 */
453 bool isWeak() const { return m.isWeak; }
454
455 /** Number of elements in the array. */
456 size_t size() const
457 {
458#if defined (VBOX_WITH_XPCOM)
459 if (m.arr)
460 return m.size;
461 return 0;
462#else
463 if (m.arr)
464 return m.arr->rgsabound [0].cElements;
465 return 0;
466#endif
467 }
468
469 /**
470 * Resizes the array preserving its contents when possible. If the new size
471 * is bigger than the old size, new elements are initialized with null
472 * values. If the new size is smaller than the old size, the contents of the
473 * array above the new size is lost.
474 *
475 * @param aNewSize New number of elements in the array.
476 * @return @c true on success and false if there is not enough
477 * memory for resizing.
478 */
479 virtual bool resize (size_t aNewSize)
480 {
481 /// @todo Implement me!
482 NOREF (aNewSize);
483 AssertFailedReturn (false);
484 }
485
486 /**
487 * Reinitializes this instance by preallocating space for the given number
488 * of elements. The previous array contents is lost.
489 *
490 * @param aNewSize New number of elements in the array.
491 * @return @c true on success and false if there is not enough
492 * memory for resizing.
493 */
494 virtual bool reset (size_t aNewSize)
495 {
496 m.uninit();
497
498#if defined (VBOX_WITH_XPCOM)
499
500 /* Note: for zero-sized arrays, we use the size of 1 because whether
501 * malloc(0) returns a null pointer or not (which is used in isNull())
502 * is implementation-dependent according to the C standard. */
503
504 m.arr = (T *) nsMemory::Alloc (RT_MAX (aNewSize, 1) * sizeof (T));
505 AssertReturn (m.arr != NULL, false);
506
507 m.size = aNewSize;
508
509 for (size_t i = 0; i < m.size; ++ i)
510 Init (m.arr [i]);
511
512#else
513
514 SAFEARRAYBOUND bound = { (ULONG)aNewSize, 0 };
515 m.arr = SafeArrayCreate (VarType(), 1, &bound);
516 AssertReturn (m.arr != NULL, false);
517
518 AssertReturn (accessRaw() != NULL, false);
519
520#endif
521 return true;
522 }
523
524 /**
525 * Returns a pointer to the raw array data. Use this raw pointer with care
526 * as no type or bound checking is done for you in this case.
527 *
528 * @note This method returns @c NULL when this instance is null.
529 * @see #operator[]
530 */
531 T *raw()
532 {
533#if defined (VBOX_WITH_XPCOM)
534 return m.arr;
535#else
536 return accessRaw();
537#endif
538 }
539
540 /**
541 * Const version of #raw().
542 */
543 const T *raw() const
544 {
545#if defined (VBOX_WITH_XPCOM)
546 return m.arr;
547#else
548 return accessRaw();
549#endif
550 }
551
552 /**
553 * Array access operator that returns an array element by reference. A bit
554 * safer than #raw(): asserts and returns an invalid reference if this
555 * instance is null or if the index is out of bounds.
556 *
557 * @note For weak instances, this call will succeed but the beiavior of
558 * changing the contents of an element of the weak array instance is
559 * undefined and may lead to a program crash on some platforms.
560 */
561 T &operator[] (size_t aIdx)
562 {
563 AssertReturn (m.arr != NULL, *((T *) NULL));
564 AssertReturn (aIdx < size(), *((T *) NULL));
565#if defined (VBOX_WITH_XPCOM)
566 return m.arr [aIdx];
567#else
568
569 AssertReturn (accessRaw() != NULL, *((T *) NULL));
570 return m.raw [aIdx];
571#endif
572 }
573
574 /**
575 * Const version of #operator[] that returns an array element by value.
576 */
577 const T operator[] (size_t aIdx) const
578 {
579 AssertReturn (m.arr != NULL, *((T *) NULL));
580 AssertReturn (aIdx < size(), *((T *) NULL));
581#if defined (VBOX_WITH_XPCOM)
582 return m.arr [aIdx];
583#else
584 AssertReturn (unconst (this)->accessRaw() != NULL, *((T *) NULL));
585 return m.raw [aIdx];
586#endif
587 }
588
589 /**
590 * Creates a copy of this array and stores it in a method parameter declared
591 * using the ComSafeArrayOut macro. When using this call, always wrap the
592 * parameter name in the ComSafeArrayOutArg macro call like this:
593 * <pre>
594 * safeArray.cloneTo (ComSafeArrayOutArg (aArg));
595 * </pre>
596 *
597 * @note It is assumed that the ownership of the returned copy is
598 * transferred to the caller of the method and he is responsible to free the
599 * array data when it is no more necessary.
600 *
601 * @param aArg Output method parameter to clone to.
602 */
603 virtual const SafeArray &cloneTo (ComSafeArrayOut (T, aArg)) const
604 {
605 /// @todo Implement me!
606#if defined (VBOX_WITH_XPCOM)
607 NOREF (aArgSize);
608 NOREF (aArg);
609#else
610 NOREF (aArg);
611#endif
612 AssertFailedReturn (*this);
613 }
614
615 /**
616 * Transfers the ownership of this array's data to a method parameter
617 * declared using the ComSafeArrayOut macro and makes this array a null
618 * array. When using this call, always wrap the parameter name in the
619 * ComSafeArrayOutArg macro call like this:
620 * <pre>
621 * safeArray.detachTo (ComSafeArrayOutArg (aArg));
622 * </pre>
623 *
624 * @note Since the ownership of the array data is transferred to the
625 * caller of the method, he is responsible to free the array data when it is
626 * no more necessary.
627 *
628 * @param aArg Output method parameter to detach to.
629 */
630 virtual SafeArray &detachTo (ComSafeArrayOut (T, aArg))
631 {
632 AssertReturn (m.isWeak == false, *this);
633
634#if defined (VBOX_WITH_XPCOM)
635
636 AssertReturn (aArgSize != NULL, *this);
637 AssertReturn (aArg != NULL, *this);
638
639 *aArgSize = m.size;
640 *aArg = m.arr;
641
642 m.isWeak = false;
643 m.size = 0;
644 m.arr = NULL;
645
646#else /* defined (VBOX_WITH_XPCOM) */
647
648 AssertReturn (aArg != NULL, *this);
649 *aArg = m.arr;
650
651 if (m.raw)
652 {
653 HRESULT rc = SafeArrayUnaccessData (m.arr);
654 AssertComRCReturn (rc, *this);
655 m.raw = NULL;
656 }
657
658 m.isWeak = false;
659 m.arr = NULL;
660
661#endif /* defined (VBOX_WITH_XPCOM) */
662
663 return *this;
664 }
665
666 // public methods for internal purposes only
667
668#if defined (VBOX_WITH_XPCOM)
669
670 /** Internal funciton. Never call it directly. */
671 PRUint32 *__asOutParam_Size() { setNull(); return &m.size; }
672
673 /** Internal funciton. Never call it directly. */
674 T **__asOutParam_Arr() { Assert (isNull()); return &m.arr; }
675
676#else /* defined (VBOX_WITH_XPCOM) */
677
678 /** Internal funciton. Never call it directly. */
679 SAFEARRAY ** __asInParam() { return &m.arr; }
680
681 /** Internal funciton. Never call it directly. */
682 SAFEARRAY ** __asOutParam() { setNull(); return &m.arr; }
683
684#endif /* defined (VBOX_WITH_XPCOM) */
685
686 static const SafeArray Null;
687
688protected:
689
690 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(SafeArray)
691
692#if defined (VBOX_WITH_XPCOM)
693#else /* defined (VBOX_WITH_XPCOM) */
694
695 /** Requests access to the raw data pointer. */
696 T *accessRaw()
697 {
698 if (m.arr && m.raw == NULL)
699 {
700 HRESULT rc = SafeArrayAccessData (m.arr, (void HUGEP **) &m.raw);
701 AssertComRCReturn (rc, NULL);
702 }
703 return m.raw;
704 }
705
706#endif /* defined (VBOX_WITH_XPCOM) */
707
708 struct Data
709 {
710 Data()
711 : isWeak (false)
712#if defined (VBOX_WITH_XPCOM)
713 , size (0), arr (NULL)
714#else
715 , arr (NULL), raw (NULL)
716#endif
717 {}
718
719 ~Data() { uninit(); }
720
721 void uninit()
722 {
723#if defined (VBOX_WITH_XPCOM)
724
725 if (arr)
726 {
727 if (!isWeak)
728 {
729 for (size_t i = 0; i < size; ++ i)
730 Uninit (arr [i]);
731
732 nsMemory::Free ((void *) arr);
733
734 isWeak = false;
735 }
736 arr = NULL;
737 }
738
739#else /* defined (VBOX_WITH_XPCOM) */
740
741 if (arr)
742 {
743 if (raw)
744 {
745 SafeArrayUnaccessData (arr);
746 raw = NULL;
747 }
748
749 if (!isWeak)
750 {
751 HRESULT rc = SafeArrayDestroy (arr);
752 AssertComRCReturnVoid (rc);
753
754 isWeak = false;
755 }
756 arr = NULL;
757 }
758
759#endif /* defined (VBOX_WITH_XPCOM) */
760 }
761
762 bool isWeak : 1;
763
764#if defined (VBOX_WITH_XPCOM)
765 PRUint32 size;
766 T *arr;
767#else
768 SAFEARRAY *arr;
769 T *raw;
770#endif
771 };
772
773 Data m;
774};
775
776////////////////////////////////////////////////////////////////////////////////
777
778#if defined (VBOX_WITH_XPCOM)
779
780template <class I>
781struct SafeIfaceArrayTraits
782{
783 static void Init (I * &aElem) { aElem = NULL; }
784 static void Uninit (I * &aElem)
785 {
786 if (aElem)
787 {
788 aElem->Release();
789 aElem = NULL;
790 }
791 }
792
793 static void Copy (I * aFrom, I * &aTo)
794 {
795 if (aFrom != NULL)
796 {
797 aTo = aFrom;
798 aTo->AddRef();
799 }
800 else
801 aTo = NULL;
802 }
803
804 /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard. */
805 static I **__asInParam_Arr (I **aArr) { return aArr; }
806 static I **__asInParam_Arr (const I **aArr) { return const_cast <I **> (aArr); }
807};
808
809#else /* defined (VBOX_WITH_XPCOM) */
810
811template <class I>
812struct SafeIfaceArrayTraits
813{
814 static VARTYPE VarType() { return VT_UNKNOWN; }
815
816 static void Copy (I * aFrom, I * &aTo)
817 {
818 if (aFrom != NULL)
819 {
820 aTo = aFrom;
821 aTo->AddRef();
822 }
823 else
824 aTo = NULL;
825 }
826};
827
828#endif /* defined (VBOX_WITH_XPCOM) */
829
830////////////////////////////////////////////////////////////////////////////////
831
832/**
833 * Version of com::SafeArray for arrays of interface pointers.
834 *
835 * Except that it manages arrays of interface pointers, the usage of this class
836 * is identical to com::SafeArray.
837 *
838 * @param I Interface class (no asterisk).
839 */
840template <class I>
841class SafeIfaceArray : public SafeArray <I *, SafeIfaceArrayTraits <I> >
842{
843public:
844
845 typedef SafeArray <I *, SafeIfaceArrayTraits <I> > Base;
846
847 /**
848 * Creates a null array.
849 */
850 SafeIfaceArray() {}
851
852 /**
853 * Creates a new array of the given size. All elements of the newly created
854 * array initialized with null values.
855 *
856 * @param aSize Initial number of elements in the array. Must be greater
857 * than 0.
858 *
859 * @note If this object remains null after construction it means that there
860 * was not enough memory for creating an array of the requested size.
861 * The constructor will also assert in this case.
862 */
863 SafeIfaceArray (size_t aSize) { reset (aSize); }
864
865 /**
866 * Weakly attaches this instance to the existing array passed in a method
867 * parameter declared using the ComSafeArrayIn macro. When using this call,
868 * always wrap the parameter name in the ComSafeArrayOutArg macro call like
869 * this:
870 * <pre>
871 * SafeArray safeArray (ComSafeArrayInArg (aArg));
872 * </pre>
873 *
874 * Note that this constructor doesn't take the ownership of the array. In
875 * particular, it means that operations that operate on the ownership (e.g.
876 * #detachTo()) are forbidden and will assert.
877 *
878 * @param aArg Input method parameter to attach to.
879 */
880 SafeIfaceArray (ComSafeArrayIn (I *, aArg))
881 {
882#if defined (VBOX_WITH_XPCOM)
883
884 AssertReturnVoid (aArg != NULL);
885
886 Base::m.size = aArgSize;
887 Base::m.arr = aArg;
888 Base::m.isWeak = true;
889
890#else /* defined (VBOX_WITH_XPCOM) */
891
892 AssertReturnVoid (aArg != NULL);
893 SAFEARRAY *arg = *aArg;
894
895 if (arg)
896 {
897 AssertReturnVoid (arg->cDims == 1);
898
899 VARTYPE vt;
900 HRESULT rc = SafeArrayGetVartype (arg, &vt);
901 AssertComRCReturnVoid (rc);
902 AssertMsgReturnVoid (vt == VT_UNKNOWN,
903 ("Expected vartype VT_UNKNOWN, got %d.\n",
904 VarType(), vt));
905 GUID guid;
906 rc = SafeArrayGetIID (arg, &guid);
907 AssertComRCReturnVoid (rc);
908 AssertMsgReturnVoid (InlineIsEqualGUID (_ATL_IIDOF (I), guid),
909 ("Expected IID {%Vuuid}, got {%Vuuid}.\n",
910 &_ATL_IIDOF (I), &guid));
911 }
912
913 m.arr = arg;
914 m.isWeak = true;
915
916 AssertReturnVoid (accessRaw() != NULL);
917
918#endif /* defined (VBOX_WITH_XPCOM) */
919 }
920
921 /**
922 * Creates a deep copy of the given standard C++ container that stores
923 * interface pointers as objects of the ComPtr <I> class.
924 *
925 * @param aCntr Container object to copy.
926 *
927 * @param C Standard C++ container template class (normally deduced from
928 * @c aCntr).
929 * @param A Standard C++ allocator class (deduced from @c aCntr).
930 * @param OI Argument to the ComPtr template (deduced from @c aCntr).
931 */
932 template <template <typename, typename> class C, class A, class OI>
933 SafeIfaceArray (const C <ComPtr <OI>, A> & aCntr)
934 {
935 typedef C <ComPtr <OI>, A> List;
936
937 reset (aCntr.size());
938 AssertReturnVoid (!Base::isNull());
939
940 int i = 0;
941 for (typename List::const_iterator it = aCntr.begin();
942 it != aCntr.end(); ++ it, ++ i)
943#if defined (VBOX_WITH_XPCOM)
944 Copy (*it, Base::m.arr [i]);
945#else
946 Copy (*it, Base::m.raw [i]);
947#endif
948 }
949
950 /**
951 * Creates a deep copy of the given standard C++ container that stores
952 * interface pointers as objects of the ComObjPtr <I> class.
953 *
954 * @param aCntr Container object to copy.
955 *
956 * @param C Standard C++ container template class (normally deduced from
957 * @c aCntr).
958 * @param A Standard C++ allocator class (deduced from @c aCntr).
959 * @param OI Argument to the ComObjPtr template (deduced from @c aCntr).
960 */
961 template <template <typename, typename> class C, class A, class OI>
962 SafeIfaceArray (const C <ComObjPtr <OI>, A> & aCntr)
963 {
964 typedef C <ComObjPtr <OI>, A> List;
965
966 reset (aCntr.size());
967 AssertReturnVoid (!Base::isNull());
968
969 int i = 0;
970 for (typename List::const_iterator it = aCntr.begin();
971 it != aCntr.end(); ++ it, ++ i)
972#if defined (VBOX_WITH_XPCOM)
973 Copy (*it, Base::m.arr [i]);
974#else
975 Copy (*it, Base::m.raw [i]);
976#endif
977 }
978
979 /**
980 * Reinitializes this instance by preallocating space for the given number
981 * of elements. The previous array contents is lost.
982 *
983 * @param aNewSize New number of elements in the array.
984 * @return @c true on success and false if there is not enough
985 * memory for resizing.
986 */
987 virtual bool reset (size_t aNewSize)
988 {
989 Base::m.uninit();
990
991#if defined (VBOX_WITH_XPCOM)
992
993 /* Note: for zero-sized arrays, we use the size of 1 because whether
994 * malloc(0) returns a null pointer or not (which is used in isNull())
995 * is implementation-dependent according to the C standard. */
996
997 Base::m.arr = (I **) nsMemory::Alloc (RT_MAX (aNewSize, 1) * sizeof (I *));
998 AssertReturn (Base::m.arr != NULL, false);
999
1000 Base::m.size = aNewSize;
1001
1002 for (size_t i = 0; i < Base::m.size; ++ i)
1003 Init (Base::m.arr [i]);
1004
1005#else
1006
1007 SAFEARRAYBOUND bound = { (ULONG)aNewSize, 0 };
1008 m.arr = SafeArrayCreateEx (VT_UNKNOWN, 1, &bound,
1009 (PVOID) &_ATL_IIDOF (I));
1010 AssertReturn (m.arr != NULL, false);
1011
1012 AssertReturn (accessRaw() != NULL, false);
1013
1014#endif
1015 return true;
1016 }
1017};
1018
1019} /* namespace com */
1020
1021/** @} */
1022
1023#endif /* ___VBox_com_array_h */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use