VirtualBox

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

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

Main: SafeArray: Fixed: SafeArrayTraits::asInParam_Arr() was protected on XPCOM which prevented from using input safe arrays in methods.

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