ProteoWizard
automation_vector.h
Go to the documentation of this file.
1 //
2 // $Id: automation_vector.h 2056 2010-06-17 16:17:29Z chambm $
3 //
4 //
5 // Original author: Andrei Alexandrescu
6 //
7 // Copyright 1999 Micro Modeling Associates, Inc.
8 //
9 // This code was downloaded from:
10 // http://erdani.org/publications/adapting_automation_arrays.html
11 //
12 // No license was specified in the article or in the download... permission pending?
13 //
14 
15 
16 #ifndef __AUTOMATION_VECTOR_H__
17 #define __AUTOMATION_VECTOR_H__
18 
19 #ifndef _MSC_VER
20 // Because automation_vector provides std::vector semantics, non-MSVC compilers
21 // can parse it equivalently.
22 #include <vector>
23 #define automation_vector std::vector
24 #else // _MSC_VER
25 
26 /******************************************************************************
27 Template class automation_vector<T>
28 Purpose: to wrap the VB safe one-dimensional arrays while having the following
29 properties:
30 1. The same memory layout as VB's safe arrays, in order to freely pass data
31 back and forth without adapting/copying
32 2. Provide fully std::vector semantics
33 3. Hide all the details of locking/unlocking an such to the user.
34 ******************************************************************************/
35 
36 // identifier was truncated to 'number' characters in the debug information
37 #pragma warning(disable : 4786)
38 
39 #define NOMINMAX
40 #include <oaidl.h>
41 #include <algorithm>
42 #include <stdexcept>
43 
44 #include "Export.hpp"
45 
46 template <bool> struct static_checker;
47 template <> struct static_checker<true> {};
48 
49 class PWIZ_API_DECL automation_vector_base;
50 
51 template <VARENUM varenum>
52 struct static_variant_info
53 {
54  enum { vt = varenum };
55  enum { size =
56  vt == VT_I1 ? 1
57  : vt == VT_I2 ? 2
58  : vt == VT_I4 ? 4
59  : vt == VT_R4 ? 4
60  : vt == VT_R8 ? 8
61  : vt == VT_CY ? 8
62 #ifdef _WIN64
63  : vt == VT_BSTR ? 8
64  : vt == VT_DISPATCH ? 8
65  : vt == VT_UNKNOWN ? 8
66 #else
67  : vt == VT_BSTR ? 4
68  : vt == VT_DISPATCH ? 4
69  : vt == VT_UNKNOWN ? 4
70 #endif
71  : vt == VT_VARIANT ? 16
72  : 0
73  };
74  static char size_checker[
75  vt == VT_I1 ? 1
76  : vt == VT_I2 ? 2
77  : vt == VT_I4 ? 4
78  : vt == VT_R4 ? 4
79  : vt == VT_R8 ? 8
80  : vt == VT_CY ? 8
81 #ifdef _WIN64
82  : vt == VT_BSTR ? 8
83  : vt == VT_DISPATCH ? 8
84  : vt == VT_UNKNOWN ? 8
85 #else
86  : vt == VT_BSTR ? 4
87  : vt == VT_DISPATCH ? 4
88  : vt == VT_UNKNOWN ? 4
89 #endif
90  : vt == VT_VARIANT ? 16
91  : 0];
92 };
93 
94 namespace Configure
95 {
96  static_variant_info<VT_I1> deduceVARENUM(char);
97  static_variant_info<VT_I1> deduceVARENUM(signed char);
98  static_variant_info<VT_I1> deduceVARENUM(unsigned char);
99  static_variant_info<VT_I2> deduceVARENUM(short);
100  static_variant_info<VT_I2> deduceVARENUM(unsigned short);
101  static_variant_info<VT_I4> deduceVARENUM(int);
102  static_variant_info<VT_I4> deduceVARENUM(unsigned int);
103  static_variant_info<VT_I4> deduceVARENUM(long);
104  static_variant_info<VT_I4> deduceVARENUM(unsigned long);
105  static_variant_info<VT_R4> deduceVARENUM(float);
106  static_variant_info<VT_R8> deduceVARENUM(double);
107  static_variant_info<VT_CY> deduceVARENUM(CURRENCY);
108  static_variant_info<VT_BSTR> deduceVARENUM(BSTR);
109  static_variant_info<VT_DISPATCH> deduceVARENUM(IDispatch *);
110  static_variant_info<VT_UNKNOWN> deduceVARENUM(IUnknown *);
111  static_variant_info<VT_VARIANT> deduceVARENUM(VARIANT);
112  static_variant_info<VT_VARIANT> deduceVARENUM(automation_vector_base);
113 }
114 
115 template <class> class automation_vector;
116 
117 class PWIZ_API_DECL automation_vector_base
118 {
119  friend void trace(VARIANT &v);
120  typedef automation_vector_base self;
121 protected:
122  // Swap contents efficiently with another vector.
123  void swap(self &that) /*throw()*/
124  {
125  _ASSERT(valid());
126  _ASSERT(that.valid());
127  std::swap(static_cast<VARIANT &>(m_Value),
128  static_cast<VARIANT &>(that.m_Value));
129  }
130  // Attach to a VARIANT.
131  // No checking made!
132  void attach(VARIANT &v) /*throw()*/;
133  // Pours the contents in a VARIANT.
134  // Assume the dest was cleared previously
135  void detach(VARIANT &v) /*throw()*/;
136 public:
137  // SAFEARRAY lock class wrapper
138  // for exception safety
139  class array_lock
140  {
141  SAFEARRAY *pArray;
142  public:
143  array_lock(SAFEARRAY &a) /*throw(std::runtime_error)*/ : pArray(&a)
144  { self::com_enforce(::SafeArrayLock(pArray)); }
145  void leave_ownership()
146  { pArray = 0; }
147  ~array_lock() /*throw()*/
148  { if (pArray && FAILED(::SafeArrayUnlock(pArray))) _ASSERT(false); }
149  };
150  typedef size_t size_type;
151  typedef ptrdiff_t difference_type;
152 #ifdef _DEBUG
153  // Check if the vector is okay
154  bool valid() const /*throw()*/;
155 #endif
156  // The index of the first element
157  long low_bound() const /*throw()*/
158  {
159  _ASSERT(valid());
160  return empty() ? 0 : bounds().lLbound;
161  }
162  void low_bound(long NewValue) /*throw(std::runtime_error)*/
163  {
164  _ASSERT(valid());
165  if (empty())
166  throw std::runtime_error("Cannot set lower bound on an empty array");
167  bounds().lLbound = NewValue;
168  }
169  // The index of the last element
170  long up_bound() const /*throw()*/
171  {
172  _ASSERT(valid());
173  if (empty())
174  return -1;
175  const SAFEARRAYBOUND &Bounds = bounds();
176  return Bounds.lLbound + Bounds.cElements - 1;
177  }
178  VARTYPE plain_vartype() const
179  {
180  return m_Value.vt;
181  }
182  static void com_enforce(HRESULT hr) /*throw(std::runtime_error)*/;
183  // The size of the vector
184  size_t size() const /*throw()*/
185  {
186  _ASSERT(valid());
187  return m_Value.vt == VT_EMPTY ? 0 : bounds().cElements;
188  }
189  size_t capacity() const /*throw()*/
190  {
191  return size();
192  }
193  // checks whether the vector is empty
194  bool empty() const /*throw()*/
195  {
196  return size() == 0;
197  }
198  ~automation_vector_base() /*throw()*/;
199  // Creation mode
200  enum TCreateMode { MOVE, COPY };
201 protected:
202  // Constructors/destructors are protected to prevent direct instantiation
203  self(unsigned Elements, VARENUM VarType)
204  /*throw(std::invalid_argument, std::runtime_error)*/;
205  SAFEARRAY &array() /*throw()*/
206  {
207  return array(m_Value);
208  }
209  const SAFEARRAY &array() const /*throw()*/
210  {
211  return array(m_Value);
212  }
213  SAFEARRAYBOUND &bounds() /*throw()*/
214  {
215  return array().rgsabound[0];
216  }
217  const SAFEARRAYBOUND &bounds() const /*throw()*/
218  {
219  return array().rgsabound[0];
220  }
221  void resize(size_type NewSize, VARENUM Type);
222  void clear()
223  {
224  _ASSERT(!V_ISBYREF(&m_Value));
225  _ASSERT(empty() || array().cLocks == 0);
226  com_enforce(::VariantClear(&m_Value));
227  }
228  static void get_element(const VARIANT &Array, long Index, VARIANT &v)
229  /*throw(std::runtime_error)*/;
230  static void put_element(VARIANT &Array, long Index, const VARIANT &v)
231  /*throw(std::runtime_error)*/;
232 private:
233  static SAFEARRAY &array(const VARIANT &v) /*throw()*/
234  {
235  _ASSERT(V_ISARRAY(&v));
236  _ASSERT(!V_ISBYREF(&v));
237  return *v.parray;
238  }
239  // The actual holder of the array
240  VARIANT m_Value;
241 };
242 
243 // Dummy implementations for deduceVARENUM functions
244 namespace Configure
245 {
246  inline static_variant_info<VT_I1> deduceVARENUM(char)
247  { return static_variant_info<VT_I1>(); }
248  inline static_variant_info<VT_I1> deduceVARENUM(signed char)
249  { return static_variant_info<VT_I1>(); }
250  inline static_variant_info<VT_I1> deduceVARENUM(unsigned char)
251  { return static_variant_info<VT_I1>(); }
252  inline static_variant_info<VT_I2> deduceVARENUM(short)
253  { return static_variant_info<VT_I2>(); }
254  inline static_variant_info<VT_I2> deduceVARENUM(unsigned short)
255  { return static_variant_info<VT_I2>(); }
256  inline static_variant_info<VT_I4> deduceVARENUM(int)
257  { return static_variant_info<VT_I4>(); }
258  inline static_variant_info<VT_I4> deduceVARENUM(unsigned int)
259  { return static_variant_info<VT_I4>(); }
260  inline static_variant_info<VT_I4> deduceVARENUM(long)
261  { return static_variant_info<VT_I4>(); }
262  inline static_variant_info<VT_I4> deduceVARENUM(unsigned long)
263  { return static_variant_info<VT_I4>(); }
264  inline static_variant_info<VT_R4> deduceVARENUM(float)
265  { return static_variant_info<VT_R4>(); }
266  inline static_variant_info<VT_R8> deduceVARENUM(double)
267  { return static_variant_info<VT_R8>(); }
268  inline static_variant_info<VT_CY> deduceVARENUM(CURRENCY)
269  { return static_variant_info<VT_CY>(); }
270  inline static_variant_info<VT_BSTR> deduceVARENUM(BSTR)
271  { return static_variant_info<VT_BSTR>(); }
272  inline static_variant_info<VT_DISPATCH> deduceVARENUM(IDispatch *)
273  { return static_variant_info<VT_DISPATCH>(); }
274  inline static_variant_info<VT_UNKNOWN> deduceVARENUM(IUnknown *)
275  { return static_variant_info<VT_UNKNOWN>(); }
276  inline static_variant_info<VT_VARIANT> deduceVARENUM(VARIANT)
277  { return static_variant_info<VT_VARIANT>(); }
278  inline static_variant_info<VT_VARIANT>
279  deduceVARENUM(automation_vector_base)
280  { return static_variant_info<VT_VARIANT>(); }
281 }
282 
283 inline void from_automation(SAFEARRAY &, void *)
284 {
285 }
286 
287 inline void to_automation(SAFEARRAY &, void *)
288 {
289 }
290 
291 template <class T>
292 void from_automation(SAFEARRAY &Array, automation_vector<T> *pDummy);
293 
294 template <class T>
295 void to_automation(SAFEARRAY &Array, automation_vector<T> *pDummy);
296 
297 template <class T> class automation_vector : public automation_vector_base
298 {
299  typedef automation_vector_base base;
300  typedef automation_vector self;
301  // Makes unnecessary const_cast in some cases
302  const self &const_this()
303  {
304  return *this;
305  }
306 public:
307  // *** vector compatibilty typedefs
308  typedef T value_type;
309  typedef T &reference;
310  typedef const T &const_reference;
311  // iterators
312  typedef T *iterator;
313  typedef const T *const_iterator;
314  typedef std::reverse_iterator<iterator> reverse_iterator;
315  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
316  // *** Static VARIANT type mapped from the C++ type
317  static VARENUM myVARENUM()
318  {
319  // If you have an error on the line below, you've instantiated
320  // automation_vector with the wrong type
321  static_checker<sizeof(T) ==
322  sizeof(Configure::deduceVARENUM(T()).size_checker)>();
323  return static_cast<VARENUM>(Configure::deduceVARENUM(T()).vt);
324  }
325  // *** Constructors
326  // Construction options (mutual exclusive).
327  // 1. MOVE: the data is moved from the source and the source is cleared.
328  // Use it when you're sure you don't need the source anymore.
329  // 2. COPY: make a full copy of the array. Use it cautiously.
330  automation_vector(VARIANT &vSource, TCreateMode Mode)
331  /*throw(std::invalid_argument, std::runtime_error)*/
332  : base(0, myVARENUM())
333  {
334  if (Mode == COPY)
335  {
336  // Make a copy and attach to it
337  VARIANT v;
338  ::VariantInit(&v);
339  ::VariantCopy(&v, &vSource);
340  attach(v);
341  }
342  else
343  // Attach directly to the source
344  attach(vSource);
345  }
346 
347  // *** Constructors
348  // Construction options (mutual exclusive).
349  // 1. MOVE: the data is moved from the source and the source is cleared.
350  // Use it when you're sure you don't need the source anymore.
351  // 2. COPY: make a full copy of the array. Use it cautiously.
352  automation_vector(SAFEARRAY &Array, TCreateMode Mode)
353  /*throw(std::invalid_argument, std::runtime_error)*/
354  : base(0, myVARENUM())
355  {
356  if (Mode == COPY)
357  {
358  // Make a copy and attach to it
359  VARIANT vSource, vCopy;
360  ::VariantInit(&vSource);
361  if (Array.rgsabound->cElements == 0)
362  vSource.vt = VT_EMPTY;
363  else
364  {
365  ::SafeArrayGetVartype(&Array, &vSource.vt);
366  vSource.vt |= VT_ARRAY;
367  vSource.parray = &Array;
368  ::VariantInit(&vCopy);
369  ::VariantCopy(&vCopy, &vSource);
370  attach(vCopy);
371  }
372  }
373  else
374  // Attach directly to the source
375  attach(Array);
376  }
377 
378  // Takes the # of elements, the lower bound, and the VType of the elements.
379  // The VType is deducted from the C++ type.
380  explicit automation_vector(unsigned uElements = 0, T t = T())
381  /*throw(std::invalid_argument, std::runtime_error)*/
382  : base(uElements, myVARENUM())
383  {
384  if (empty())
385  return;
386  _ASSERT(sizeof(T) == array().cbElements);
387  _ASSERT(array().cLocks == 0);
388  com_enforce(::SafeArrayLock(&array()));
389  std::uninitialized_fill(begin(), end(), t);
390  }
391  // Copy constructor. Warning! It copies data, so it may be inefficient.
392  // You may want to use attach() instead.
393  automation_vector(const automation_vector &vSource)
394  /*throw(std::runtime_error)*/ : base(vSource.size(), myVARENUM())
395  {
396  if (empty())
397  return;
398  com_enforce(::SafeArrayLock(&array()));
399  std::uninitialized_copy(vSource.begin(), vSource.end(), begin());
400  }
401  automation_vector(const_iterator first, const_iterator last)
402  : base(last - first, myVARENUM())
403  {
404  std::uninitialized_copy(first, last, begin());
405  }
406  // *** ~
408  // *** Assignment operator. Warning! It copies data, so it may be
409  // inefficient. You may want to use swap() instead.
410  automation_vector &operator=(const automation_vector &that)
411  {
412  resize(that.size());
413  std::copy(that.begin(), that.end(), begin());
414  return *this;
415  }
416  // *** Assignment operator. Warning! It copies data, so it may be
417  // inefficient. You may want to use attach() instead
418  automation_vector &operator=(const VARIANT &that)
419  {
420  VARIANT v;
421  ::VariantInit(&v);
422  ::VariantCopy(&v, &that);
423  attach(v);
424  return *this;
425  }
426  // *** Takes the contents of the source and empty it.
427  // Requirement: vSource must be either a safe array or empty
428  // All existing iterators to 'this' will be invalidated.
429  void attach(VARIANT &vSource)
430  /*throw(std::invalid_argument, std::runtime_error)*/;
431 
432  // *** Takes the contents of the source and empty it.
433  // Requirement: vSource must be either a safe array or empty
434  // All existing iterators to 'this' will be invalidated.
435  void attach(SAFEARRAY &vSource)
436  /*throw(std::invalid_argument, std::runtime_error)*/;
437 
438  // *** Moves the vector to Var.
439  // Requirement: Var must be valid
440  // After the move, size() will return zero.
441  // All existing iterators to 'this' will be invalidated.
442  void detach(VARIANT &Var)
443  {
444  _ASSERT(_CrtIsValidPointer(&Var, sizeof(VARIANT), true));
445  com_enforce(::VariantClear(&Var));
446  unlock();
447  base::detach(Var);
448  }
449  VARIANT* detach()
450  {
451  VARIANT* v = new VARIANT;
452  detach(*v);
453  return v;
454  }
455  // *** vector compatibility methods
456  void assign(const_iterator first, const_iterator last)
457  {
458  clear();
459  insert(begin(), first, last);
460  }
461  void assign(size_type n, const T &x)
462  {
463  clear();
464  insert(begin(), n, x);
465  }
466  // The start of the vector
467  const_iterator begin() const /*throw(std::runtime_error)*/
468  {
469  _ASSERT(valid());
470  _ASSERT(empty() || array().cLocks == 1);
471  return empty() ? 0 : static_cast<T *>(array().pvData);
472  }
473  iterator begin() /*throw(std::runtime_error)*/
474  {
475  return const_cast<iterator>(const_this().begin());
476  }
477  // One past the last element of the vector
478  const_iterator end() const /*throw(std::runtime_error)*/
479  {
480  _ASSERT(valid());
481  if (empty())
482  return 0;
483  _ASSERT(array().cLocks == 1);
484  const SAFEARRAY &a = array();
485  return static_cast<T *>(a.pvData) + a.rgsabound[0].cElements;
486  }
487  iterator end() /*throw(std::runtime_error)*/
488  {
489  return const_cast<iterator>(const_this().end());
490  }
491  // The reversed begin of the vector
492  reverse_iterator rbegin() /*throw(std::runtime_error)*/
493  {
494  return reverse_iterator(end());
495  }
496  const_reverse_iterator rbegin() const /*throw(std::runtime_error)*/
497  {
498  return const_reverse_iterator(end());
499  }
500  // The reversed end of the vector
501  reverse_iterator rend() /*throw(std::runtime_error)*/
502  {
503  return reverse_iterator(begin());
504  }
505  const_reverse_iterator rend() const /*throw(std::runtime_error)*/
506  {
507  return const_reverse_iterator(begin());
508  }
509  // Reference to the first element of the vector
510  // Requirement: the vector must not be empty
511  const_reference front() const /*throw(std::runtime_error)*/
512  {
513  _ASSERT(!empty());
514  return *begin();
515  }
516  reference front() /*throw(std::runtime_error)*/
517  {
518  return const_cast<reference>(const_this().front());
519  }
520  // Reference to the last element of the vector
521  // Requirement: the vector must not be empty
522  const_reference back() const /*throw(std::runtime_error)*/
523  {
524  _ASSERT(!empty());
525  return end()[-1];
526  }
527  reference back() /*throw(std::runtime_error)*/
528  {
529  return const_cast<reference>(const_this().back());
530  }
531  size_t max_size() const /*throw()*/
532  {
533  return size_type(-1) / sizeof(T);
534  }
535  // C-like random access
536  // Requirements: the index must fall within the bounds
537  const_reference operator[] (long lIndex) const /*throw(std::runtime_error)*/
538  {
539  _ASSERT(valid());
540  _ASSERT(!empty());
541  const SAFEARRAYBOUND &Bounds = bounds();
542  lIndex -= Bounds.lLbound;
543  _ASSERT(lIndex >= 0 && (unsigned long)lIndex < Bounds.cElements);
544  return begin()[lIndex];
545  }
546  reference operator[](long lIndex)
547  {
548  return const_cast<reference>(const_this()[lIndex]);
549  }
550  const_reference at(long lIndex) const /*throw(std::runtime_error)*/
551  {
552  _ASSERT(valid());
553  if (empty())
554  throw std::out_of_range("out of range");
555  const SAFEARRAYBOUND &Bounds = bounds();
556  lIndex -= Bounds.lLbound;
557  if (lIndex < 0 || (unsigned long)lIndex >= Bounds.cElements)
558  throw std::out_of_range("out of range");
559  return begin()[lIndex];
560  }
561  reference at(long lIndex) /*throw(std::runtime_error)*/
562  {
563  return const_cast<reference>(const_this().at(lIndex));
564  }
565  void swap(self &that) /*throw()*/
566  {
567  base::swap(that);
568  }
569  // Insert an element BEFORE i within the vector.
570  // Call insert(end(), x) or push_back(x) to append.
571  iterator insert(iterator i, const T& x = T()) /*throw(std::runtime_error)*/
572  {
573  _ASSERT(i >= begin() && i <= end());
574  size_t Offset = i - begin();
575  insert(i, (T *)&x, (T *)&x + 1);
576  return begin() + Offset;
577  }
578  // Insert a repetition of x BEFORE i within the vector.
579  void insert(iterator i, size_t n, const T &x) /*throw(std::runtime_error)*/
580  {
581  size_t OldSize = size();
582  resize(size() + n);
583  std::copy_backward(begin(), begin() + OldSize, end());
584  std::fill(begin(), begin() + n, x);
585  }
586  // Insert a sequence of elements BEFORE i within the vector.
587  void insert(iterator i, const_iterator first, const_iterator last)
588  /*throw(std::runtime_error)*/
589  {
590  _ASSERT(valid());
591  _ASSERT(last >= first);
592  _ASSERT(i >= begin() && i <= end());
593  size_t count = last - first;
594  if (count == 0)
595  return;
596  size_t offset = i - begin(), old_size = size();
597  resize(old_size + count);
598  for (iterator j = begin() + old_size, k = end(); j != begin() + offset; )
599  std::iter_swap(--j, --k);
600  std::copy(first, last, begin() + offset);
601  _ASSERT(valid());
602  }
603  iterator erase(iterator i)
604  {
605  unsigned Offset = i - begin();
606  std::copy(i + 1, end(), i);
607  pop_back();
608  return begin() + Offset;
609  }
610  iterator erase(iterator From, iterator To)
611  {
612  unsigned Offset = From - begin();
613  iterator i = std::copy(To, end(), From);
614  resize(i - begin());
615  return begin() + Offset;
616  }
617  // Change the size of the vector. NewDim may be 0 or whatever.
618  void resize(size_t NewDim, const T &FillWith);
619  void resize(size_t NewDim)
620  {
621  resize(NewDim, T());
622  }
623  // Append an element to the vector.
624  void push_back(const T &ToAdd) /*throw(std::runtime_error)*/
625  {
626  _ASSERT(valid());
627  insert(end(), ToAdd);
628  }
629  // Nuke the last element of the vector.
630  void pop_back() /*throw(std::runtime_error)*/
631  {
632  _ASSERT(valid());
633  _ASSERT(!empty());
634  resize(size() - 1);
635  }
636  // Clear the entire vector
637  void clear();
638 #ifdef _DEBUG
639  // Check if the vector is okay
640  bool valid() const /*throw()*/
641  {
642  if (!base::valid())
643  return false;
644  if (empty())
645  return true;
646  std::string ErrorMessage;
647  if (array().cbElements != sizeof(T))
648  ErrorMessage += "Element size (cbElements) is incorrect.\n";
649  VARENUM ElementType = VARENUM(plain_vartype() & VT_TYPEMASK);
650  if (ElementType != myVARENUM() &&
651  !(ElementType == VT_DATE && myVARENUM() == VT_R4) &&
652  !(ElementType == VT_ERROR && myVARENUM() == VT_I4))
653  ErrorMessage += "Element type is incorrect.\n";
654  if (ErrorMessage.empty())
655  return true;
656  throw std::runtime_error("The automation_vector is invalid due to the following problem(s):\n" + ErrorMessage);
657  }
658 #endif
659 protected:
660  void lock();
661  void unlock();
662 };
663 
664 template <class T>
665 automation_vector<T>::~automation_vector()
666 {
667  _ASSERT(valid());
668  try
669  {
670  unlock();
671  _ASSERT(plain_vartype() == VT_EMPTY || array().cLocks == 0);
672  }
673  catch (...)
674  {
675  // Don't throw anything - just assert
676  _ASSERT(false);
677  }
678 }
679 
680 template <class T>
681 void automation_vector<T>::clear()
682 {
683  _ASSERT(valid());
684  unlock();
685  base::clear();
686 }
687 
688 template <class T>
689 void automation_vector<T>::resize(size_t NewSize, const T &t)
690 {
691  _ASSERT(valid());
692  size_type OldSize = size();
693  unlock();
694  base::resize(NewSize, myVARENUM());
695  lock();
696  _ASSERT(valid());
697  if (OldSize < size())
698  std::uninitialized_fill(begin() + OldSize, end(), t);
699 }
700 
701 template <class T>
702 void automation_vector<T>::lock()
703 {
704  _ASSERT(valid());
705  if (empty())
706  // nothing to do -- all ok
707  return;
708  _ASSERT(array().cLocks == 0);
709  // Lock self
710  array_lock MyLock(array());
711  _ASSERT(valid());
712  // Convert contents
713  from_automation(array(), static_cast<T *>(0));
714  // Commit the lock
715  MyLock.leave_ownership();
716 }
717 
718 template <class T>
719 void automation_vector<T>::unlock()
720 {
721  _ASSERT(valid());
722  if (empty())
723  // nothing to do -- all ok
724  return;
725  to_automation(array(), static_cast<T *>(0));
726  // Unlock self
727  com_enforce(::SafeArrayUnlock(&array()));
728 }
729 
730 /*template <class T>
731 void from_automation(SAFEARRAY &Array, automation_vector<T> *)
732 {
733  _ASSERT(Array.cbElements == sizeof(automation_vector<T>));
734  automation_vector<T>::array_lock MyLock(Array);
735  VARIANT *f = static_cast<VARIANT *>(Array.pvData),
736  *t = f + Array.rgsabound[0].cElements;
737  for (; f != t; ++f)
738  {
739  VARIANT ShallowCopy = *f;
740  new (f) automation_vector<T>(ShallowCopy, automation_vector<T>::MOVE);
741  }
742 }
743 
744 template <class T>
745 void to_automation(SAFEARRAY &Array, automation_vector<T> *)
746 {
747  _ASSERT(Array.cLocks == 1 && Array.cbElements == sizeof(automation_vector<T>));
748  automation_vector<T> *f = static_cast<automation_vector<T> *>(Array.pvData),
749  *t = f + Array.rgsabound[0].cElements;
750  VARIANT *iOut = static_cast<VARIANT *>(Array.pvData);
751  for (; f != t; ++f, ++iOut)
752  {
753  VARIANT Copy;
754  ::VariantInit(&Copy);
755  f->detach(Copy);
756  automation_vector<T>::com_enforce(Copy.Detach(iOut));
757  }
758 }*/
759 
760 template <class T>
761 void automation_vector<T>::attach(VARIANT &vSource)
762 /*throw(std::invalid_argument, std::runtime_error)*/
763 {
764  if (V_VT(&vSource) == VT_EMPTY)
765  {
766  clear();
767  return;
768  }
769  if (!V_ISARRAY(&vSource))
770  throw std::invalid_argument("Invalid argument passed to attach()");
771  SAFEARRAY &Array = V_ISBYREF(&vSource) ? **vSource.pparray : *vSource.parray;
772  if (Array.cDims != 1)
773  throw std::invalid_argument("Only one-dimensional arrays are supported");
774  const VARENUM vt = VARENUM(vSource.vt & VT_TYPEMASK);
775  automation_vector Temp;
776  if (vt == myVARENUM())
777  {
778  // Great, types match
779  com_enforce(::SafeArrayLock(&Array));
780  from_automation(Array, static_cast<T *>(0));
781  Temp.base::attach(vSource);
782  }
783  else
784  {
785  // Types don't match, we'll have to do a conversion
786  Temp.resize(Array.rgsabound[0].cElements);
787  VARIANT* Converted = Temp.detach();
788  long f = Array.rgsabound[0].lLbound,
789  t = f + Array.rgsabound[0].cElements;
790  VARIANT Buffer;
791  ::VariantInit(&Buffer);
792  for (; f != t; ++f)
793  {
794  get_element(vSource, f, Buffer);
795  if (myVARENUM() != VT_VARIANT)
796  com_enforce(::VariantChangeType(&Buffer, &Buffer, 0, myVARENUM()));
797  put_element(*Converted, f, Buffer);
798  }
799  _ASSERT(Converted->vt == (myVARENUM() | VT_ARRAY));
800  Temp.attach(*Converted);
801  delete Converted;
802  }
803  swap(Temp);
804  _ASSERT(valid());
805 }
806 
807 template <class T>
808 void automation_vector<T>::attach(SAFEARRAY &Array)
809 /*throw(std::invalid_argument, std::runtime_error)*/
810 {
811  VARIANT v;
812  ::VariantInit(&v);
813  if (Array.rgsabound->cElements == 0)
814  v.vt = VT_EMPTY;
815  else
816  {
817  ::SafeArrayGetVartype(&Array, &v.vt);
818  v.vt |= VT_ARRAY;
819  v.parray = &Array;
820  }
821  attach(v);
822 }
823 
824 #endif // _MSC_VER
825 
826 #endif //__AUTOMATION_VECTOR_H__