VirtualBox

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

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

Rolled back r34628 changes.

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