VirtualBox

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

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

Got rid of annoying warnings during win64 build

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

© 2023 Oracle
ContactPrivacy policyTerms of Use