xref: /reactos/dll/win32/oleaut32/safearray.c (revision 5bfe6a53)
1 /*************************************************************************
2  * OLE Automation - SafeArray
3  *
4  * This file contains the implementation of the SafeArray functions.
5  *
6  * Copyright 1999 Sylvain St-Germain
7  * Copyright 2002-2003 Marcus Meissner
8  * Copyright 2003 Jon Griffiths
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 /* Memory Layout of a SafeArray:
25  *
26  * -0x10: start of memory.
27  * -0x10: GUID for VT_DISPATCH and VT_UNKNOWN safearrays (if FADF_HAVEIID)
28  * -0x04: DWORD varianttype; (for all others, except VT_RECORD) (if FADF_HAVEVARTYPE)
29  *  -0x4: IRecordInfo* iface;  (if FADF_RECORD, for VT_RECORD (can be NULL))
30  *  0x00: SAFEARRAY,
31  *  0x10: SAFEARRAYBOUNDS[0...]
32  */
33 
34 #include "config.h"
35 
36 #include <string.h>
37 #include <stdarg.h>
38 #include <stdio.h>
39 
40 #define COBJMACROS
41 
42 #include "windef.h"
43 #include "winerror.h"
44 #include "winbase.h"
45 #include "variant.h"
46 #include "wine/debug.h"
47 
48 WINE_DEFAULT_DEBUG_CHANNEL(variant);
49 
50 /************************************************************************
51  * SafeArray {OLEAUT32}
52  *
53  * NOTES
54  * The SafeArray data type provides the underlying interface for Ole
55  * Automations arrays, used for example to represent array types in
56  * Visual Basic(tm) and to gather user defined parameters for invocation through
57  * an IDispatch interface.
58  *
59  * Safe arrays provide bounds checking and automatically manage the data
60  * types they contain, for example handing reference counting and copying
61  * of interface pointers. User defined types can be stored in arrays
62  * using the IRecordInfo interface.
63  *
64  * There are two types of SafeArray, normal and vectors. Normal arrays can have
65  * multiple dimensions and the data for the array is allocated separately from
66  * the array header. This is the most flexible type of array. Vectors, on the
67  * other hand, are fixed in size and consist of a single allocated block, and a
68  * single dimension.
69  *
70  * DATATYPES
71  * The following types of data can be stored within a SafeArray.
72  * Numeric:
73  *|  VT_I1, VT_UI1, VT_I2, VT_UI2, VT_I4, VT_UI4, VT_I8, VT_UI8, VT_INT, VT_UINT,
74  *|  VT_R4, VT_R8, VT_CY, VT_DECIMAL
75  * Interfaces:
76  *|  VT_DISPATCH, VT_UNKNOWN, VT_RECORD
77  * Other:
78  *|  VT_VARIANT, VT_INT_PTR, VT_UINT_PTR, VT_BOOL, VT_ERROR, VT_DATE, VT_BSTR
79  *
80  * FUNCTIONS
81  *  BstrFromVector()
82  *  VectorFromBstr()
83  */
84 
85 /* Undocumented hidden space before the start of a SafeArray descriptor */
86 #define SAFEARRAY_HIDDEN_SIZE sizeof(GUID)
87 
88 /* features listed here are not propagated to newly created array or data copy
89    created with SafeArrayCopy()/SafeArrayCopyData() */
90 static const USHORT ignored_copy_features =
91         FADF_AUTO |
92         FADF_STATIC |
93         FADF_EMBEDDED |
94         FADF_FIXEDSIZE |
95         FADF_CREATEVECTOR;
96 
97 /* Allocate memory */
98 static inline void* SAFEARRAY_Malloc(ULONG size)
99 {
100   void *ret = CoTaskMemAlloc(size);
101   if (ret)
102     memset(ret, 0, size);
103   return ret;
104 }
105 
106 /* Free memory */
107 static inline void SAFEARRAY_Free(void *ptr)
108 {
109   CoTaskMemFree(ptr);
110 }
111 
112 /* Get the size of a supported VT type (0 means unsupported) */
113 static DWORD SAFEARRAY_GetVTSize(VARTYPE vt)
114 {
115   switch (vt)
116   {
117     case VT_I1:
118     case VT_UI1:      return sizeof(BYTE);
119     case VT_BOOL:
120     case VT_I2:
121     case VT_UI2:      return sizeof(SHORT);
122     case VT_I4:
123     case VT_UI4:
124     case VT_R4:
125     case VT_ERROR:    return sizeof(LONG);
126     case VT_R8:
127     case VT_I8:
128     case VT_UI8:      return sizeof(LONG64);
129     case VT_INT:
130     case VT_UINT:     return sizeof(INT);
131     case VT_INT_PTR:
132     case VT_UINT_PTR: return sizeof(UINT_PTR);
133     case VT_CY:       return sizeof(CY);
134     case VT_DATE:     return sizeof(DATE);
135     case VT_BSTR:     return sizeof(BSTR);
136     case VT_DISPATCH: return sizeof(LPDISPATCH);
137     case VT_VARIANT:  return sizeof(VARIANT);
138     case VT_UNKNOWN:  return sizeof(LPUNKNOWN);
139     case VT_DECIMAL:  return sizeof(DECIMAL);
140     /* Note: Return a non-zero size to indicate vt is valid. The actual size
141      * of a UDT is taken from the result of IRecordInfo_GetSize().
142      */
143     case VT_RECORD:   return 32;
144   }
145   return 0;
146 }
147 
148 /* Set the hidden data for an array */
149 static inline void SAFEARRAY_SetHiddenDWORD(SAFEARRAY* psa, DWORD dw)
150 {
151   /* Implementation data is stored in the 4 bytes before the header */
152   LPDWORD lpDw = (LPDWORD)psa;
153   lpDw[-1] = dw;
154 }
155 
156 /* Get the hidden data from an array */
157 static inline DWORD SAFEARRAY_GetHiddenDWORD(SAFEARRAY* psa)
158 {
159   LPDWORD lpDw = (LPDWORD)psa;
160   return lpDw[-1];
161 }
162 
163 /* Get the number of cells in a SafeArray */
164 static ULONG SAFEARRAY_GetCellCount(const SAFEARRAY *psa)
165 {
166   const SAFEARRAYBOUND* psab = psa->rgsabound;
167   USHORT cCount = psa->cDims;
168   ULONG ulNumCells = 1;
169 
170   while (cCount--)
171   {
172     /* This is a valid bordercase. See testcases. -Marcus */
173     if (!psab->cElements)
174       return 0;
175     ulNumCells *= psab->cElements;
176     psab++;
177   }
178   return ulNumCells;
179 }
180 
181 /* Allocate a descriptor for an array */
182 static HRESULT SAFEARRAY_AllocDescriptor(ULONG ulSize, SAFEARRAY **ppsaOut)
183 {
184   char *ptr = SAFEARRAY_Malloc(ulSize + SAFEARRAY_HIDDEN_SIZE);
185 
186   if (!ptr)
187   {
188       *ppsaOut = NULL;
189       return E_OUTOFMEMORY;
190   }
191 
192   *ppsaOut = (SAFEARRAY*)(ptr + SAFEARRAY_HIDDEN_SIZE);
193   return S_OK;
194 }
195 
196 /* Set the features of an array */
197 static void SAFEARRAY_SetFeatures(VARTYPE vt, SAFEARRAY *psa)
198 {
199   /* Set the IID if we have one, otherwise set the type */
200   if (vt == VT_DISPATCH)
201   {
202     psa->fFeatures = FADF_HAVEIID;
203     SafeArraySetIID(psa, &IID_IDispatch);
204   }
205   else if (vt == VT_UNKNOWN)
206   {
207     psa->fFeatures = FADF_HAVEIID;
208     SafeArraySetIID(psa, &IID_IUnknown);
209   }
210   else if (vt == VT_RECORD)
211     psa->fFeatures = FADF_RECORD;
212   else
213   {
214     psa->fFeatures = FADF_HAVEVARTYPE;
215     SAFEARRAY_SetHiddenDWORD(psa, vt);
216   }
217 }
218 
219 /* Create an array */
220 static SAFEARRAY* SAFEARRAY_Create(VARTYPE vt, UINT cDims, const SAFEARRAYBOUND *rgsabound, ULONG ulSize)
221 {
222   SAFEARRAY *psa = NULL;
223   unsigned int i;
224 
225   if (!rgsabound)
226     return NULL;
227 
228   if (SUCCEEDED(SafeArrayAllocDescriptorEx(vt, cDims, &psa)))
229   {
230     switch (vt)
231     {
232       case VT_BSTR:     psa->fFeatures |= FADF_BSTR; break;
233       case VT_UNKNOWN:  psa->fFeatures |= FADF_UNKNOWN; break;
234       case VT_DISPATCH: psa->fFeatures |= FADF_DISPATCH; break;
235       case VT_VARIANT:  psa->fFeatures |= FADF_VARIANT; break;
236     }
237 
238     for (i = 0; i < cDims; i++)
239       memcpy(psa->rgsabound + i, rgsabound + cDims - 1 - i, sizeof(SAFEARRAYBOUND));
240 
241     if (ulSize)
242       psa->cbElements = ulSize;
243 
244     if (!psa->cbElements || FAILED(SafeArrayAllocData(psa)))
245     {
246       SafeArrayDestroyDescriptor(psa);
247       psa = NULL;
248     }
249   }
250   return psa;
251 }
252 
253 /* Create an array as a vector */
254 static SAFEARRAY* SAFEARRAY_CreateVector(VARTYPE vt, LONG lLbound, ULONG cElements, ULONG ulSize)
255 {
256   SAFEARRAY *psa = NULL;
257 
258   if (ulSize || (vt == VT_RECORD))
259   {
260     /* Allocate the header and data together */
261     if (SUCCEEDED(SAFEARRAY_AllocDescriptor(sizeof(SAFEARRAY) + ulSize * cElements, &psa)))
262     {
263       SAFEARRAY_SetFeatures(vt, psa);
264 
265       psa->cDims = 1;
266       psa->fFeatures |= FADF_CREATEVECTOR;
267       psa->pvData = &psa[1]; /* Data follows the header */
268       psa->cbElements = ulSize;
269       psa->rgsabound[0].cElements = cElements;
270       psa->rgsabound[0].lLbound = lLbound;
271 
272       switch (vt)
273       {
274         case VT_BSTR:     psa->fFeatures |= FADF_BSTR; break;
275         case VT_UNKNOWN:  psa->fFeatures |= FADF_UNKNOWN; break;
276         case VT_DISPATCH: psa->fFeatures |= FADF_DISPATCH; break;
277         case VT_VARIANT:  psa->fFeatures |= FADF_VARIANT; break;
278       }
279     }
280   }
281   return psa;
282 }
283 
284 /* Free data items in an array */
285 static HRESULT SAFEARRAY_DestroyData(SAFEARRAY *psa, ULONG ulStartCell)
286 {
287   if (psa->pvData && !(psa->fFeatures & FADF_DATADELETED))
288   {
289     ULONG ulCellCount = SAFEARRAY_GetCellCount(psa);
290 
291     if (ulStartCell > ulCellCount) {
292       FIXME("unexpected ulCellCount %d, start %d\n",ulCellCount,ulStartCell);
293       return E_UNEXPECTED;
294     }
295 
296     ulCellCount -= ulStartCell;
297 
298     if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
299     {
300       LPUNKNOWN *lpUnknown = (LPUNKNOWN *)psa->pvData + ulStartCell;
301 
302       while(ulCellCount--)
303       {
304         if (*lpUnknown)
305           IUnknown_Release(*lpUnknown);
306         lpUnknown++;
307       }
308     }
309     else if (psa->fFeatures & FADF_RECORD)
310     {
311       IRecordInfo *lpRecInfo;
312 
313       if (SUCCEEDED(SafeArrayGetRecordInfo(psa, &lpRecInfo)))
314       {
315         PBYTE pRecordData = psa->pvData;
316         while(ulCellCount--)
317         {
318           IRecordInfo_RecordClear(lpRecInfo, pRecordData);
319           pRecordData += psa->cbElements;
320         }
321         IRecordInfo_Release(lpRecInfo);
322       }
323     }
324     else if (psa->fFeatures & FADF_BSTR)
325     {
326       BSTR* lpBstr = (BSTR*)psa->pvData + ulStartCell;
327 
328       while(ulCellCount--)
329       {
330         SysFreeString(*lpBstr);
331         lpBstr++;
332       }
333     }
334     else if (psa->fFeatures & FADF_VARIANT)
335     {
336       VARIANT* lpVariant = (VARIANT*)psa->pvData + ulStartCell;
337 
338       while(ulCellCount--)
339       {
340         HRESULT hRet = VariantClear(lpVariant);
341 
342         if (FAILED(hRet)) FIXME("VariantClear of element failed!\n");
343         lpVariant++;
344       }
345     }
346   }
347   return S_OK;
348 }
349 
350 /* Copy data items from one array to another. Destination data is freed before copy. */
351 static HRESULT SAFEARRAY_CopyData(SAFEARRAY *psa, SAFEARRAY *dest)
352 {
353   HRESULT hr = S_OK;
354 
355   if (!psa->pvData)
356     return S_OK;
357 
358   if (!dest->pvData || psa->fFeatures & FADF_DATADELETED)
359     return E_INVALIDARG;
360   else
361   {
362     ULONG ulCellCount = SAFEARRAY_GetCellCount(psa);
363 
364     dest->fFeatures = (dest->fFeatures & FADF_CREATEVECTOR) | (psa->fFeatures & ~ignored_copy_features);
365 
366     if (psa->fFeatures & FADF_VARIANT)
367     {
368       VARIANT *src_var = psa->pvData;
369       VARIANT *dest_var = dest->pvData;
370 
371       while(ulCellCount--)
372       {
373         HRESULT hRet;
374 
375         /* destination is cleared automatically */
376         hRet = VariantCopy(dest_var, src_var);
377         if (FAILED(hRet)) FIXME("VariantCopy failed with 0x%08x, element %u\n", hRet, ulCellCount);
378         src_var++;
379         dest_var++;
380       }
381     }
382     else if (psa->fFeatures & FADF_BSTR)
383     {
384       BSTR *src_bstr = psa->pvData;
385       BSTR *dest_bstr = dest->pvData;
386 
387       while(ulCellCount--)
388       {
389         SysFreeString(*dest_bstr);
390         if (*src_bstr)
391         {
392           *dest_bstr = SysAllocStringByteLen((char*)*src_bstr, SysStringByteLen(*src_bstr));
393           if (!*dest_bstr)
394             return E_OUTOFMEMORY;
395         }
396         else
397           *dest_bstr = NULL;
398         src_bstr++;
399         dest_bstr++;
400       }
401     }
402     else if (psa->fFeatures & FADF_RECORD)
403     {
404       BYTE *dest_data = dest->pvData;
405       BYTE *src_data = psa->pvData;
406       IRecordInfo *record;
407 
408       SafeArrayGetRecordInfo(psa, &record);
409       while (ulCellCount--)
410       {
411           /* RecordCopy() clears destination record */
412           hr = IRecordInfo_RecordCopy(record, src_data, dest_data);
413           if (FAILED(hr)) break;
414           src_data += psa->cbElements;
415           dest_data += psa->cbElements;
416       }
417 
418       SafeArraySetRecordInfo(dest, record);
419       /* This value is set to 32 bytes by default on descriptor creation,
420          update with actual structure size. */
421       dest->cbElements = psa->cbElements;
422       IRecordInfo_Release(record);
423     }
424     else if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
425     {
426       IUnknown **dest_unk = dest->pvData;
427       IUnknown **src_unk = psa->pvData;
428 
429       /* release old iface, addref new one */
430       while (ulCellCount--)
431       {
432           if (*dest_unk)
433               IUnknown_Release(*dest_unk);
434           *dest_unk = *src_unk;
435           if (*dest_unk)
436               IUnknown_AddRef(*dest_unk);
437           src_unk++;
438           dest_unk++;
439       }
440     }
441     else
442     {
443       /* Copy the data over */
444       memcpy(dest->pvData, psa->pvData, ulCellCount * psa->cbElements);
445     }
446 
447     if (psa->fFeatures & FADF_HAVEIID)
448     {
449       GUID guid;
450       SafeArrayGetIID(psa, &guid);
451       SafeArraySetIID(dest, &guid);
452     }
453     else if (psa->fFeatures & FADF_HAVEVARTYPE)
454     {
455       SAFEARRAY_SetHiddenDWORD(dest, SAFEARRAY_GetHiddenDWORD(psa));
456     }
457   }
458 
459   return hr;
460 }
461 
462 /*************************************************************************
463  *		SafeArrayAllocDescriptor (OLEAUT32.36)
464  *
465  * Allocate and initialise a descriptor for a SafeArray.
466  *
467  * PARAMS
468  *  cDims   [I] Number of dimensions of the array
469  *  ppsaOut [O] Destination for new descriptor
470  *
471  * RETURNS
472  * Success: S_OK. ppsaOut is filled with a newly allocated descriptor.
473  * Failure: An HRESULT error code indicating the error.
474  *
475  * NOTES
476  * See SafeArray.
477  */
478 HRESULT WINAPI SafeArrayAllocDescriptor(UINT cDims, SAFEARRAY **ppsaOut)
479 {
480   LONG allocSize;
481   HRESULT hr;
482 
483   TRACE("(%d,%p)\n", cDims, ppsaOut);
484 
485   if (!cDims || cDims >= 0x10000) /* Maximum 65535 dimensions */
486     return E_INVALIDARG;
487 
488   if (!ppsaOut)
489     return E_POINTER;
490 
491   /* We need enough space for the header and its bounds */
492   allocSize = sizeof(SAFEARRAY) + sizeof(SAFEARRAYBOUND) * (cDims - 1);
493 
494   hr = SAFEARRAY_AllocDescriptor(allocSize, ppsaOut);
495   if (FAILED(hr))
496     return hr;
497 
498   (*ppsaOut)->cDims = cDims;
499 
500   TRACE("(%d): %u bytes allocated for descriptor.\n", cDims, allocSize);
501   return S_OK;
502 }
503 
504 /*************************************************************************
505  *		SafeArrayAllocDescriptorEx (OLEAUT32.41)
506  *
507  * Allocate and initialise a descriptor for a SafeArray of a given type.
508  *
509  * PARAMS
510  *  vt      [I] The type of items to store in the array
511  *  cDims   [I] Number of dimensions of the array
512  *  ppsaOut [O] Destination for new descriptor
513  *
514  * RETURNS
515  *  Success: S_OK. ppsaOut is filled with a newly allocated descriptor.
516  *  Failure: An HRESULT error code indicating the error.
517  *
518  * NOTES
519  *  - This function does not check that vt is an allowed VARTYPE.
520  *  - Unlike SafeArrayAllocDescriptor(), vt is associated with the array.
521  *  See SafeArray.
522  */
523 HRESULT WINAPI SafeArrayAllocDescriptorEx(VARTYPE vt, UINT cDims, SAFEARRAY **ppsaOut)
524 {
525   ULONG cbElements;
526   HRESULT hRet;
527 
528   TRACE("(%d->%s,%d,%p)\n", vt, debugstr_vt(vt), cDims, ppsaOut);
529 
530   cbElements = SAFEARRAY_GetVTSize(vt);
531   if (!cbElements)
532     WARN("Creating a descriptor with an invalid VARTYPE!\n");
533 
534   hRet = SafeArrayAllocDescriptor(cDims, ppsaOut);
535 
536   if (SUCCEEDED(hRet))
537   {
538     SAFEARRAY_SetFeatures(vt, *ppsaOut);
539     (*ppsaOut)->cbElements = cbElements;
540   }
541   return hRet;
542 }
543 
544 /*************************************************************************
545  *		SafeArrayAllocData (OLEAUT32.37)
546  *
547  * Allocate the data area of a SafeArray.
548  *
549  * PARAMS
550  *  psa [I] SafeArray to allocate the data area of.
551  *
552  * RETURNS
553  *  Success: S_OK. The data area is allocated and initialised.
554  *  Failure: An HRESULT error code indicating the error.
555  *
556  * NOTES
557  *  See SafeArray.
558  */
559 HRESULT WINAPI SafeArrayAllocData(SAFEARRAY *psa)
560 {
561   HRESULT hRet = E_INVALIDARG;
562 
563   TRACE("(%p)\n", psa);
564 
565   if (psa)
566   {
567     ULONG ulSize = SAFEARRAY_GetCellCount(psa);
568 
569     psa->pvData = SAFEARRAY_Malloc(ulSize * psa->cbElements);
570 
571     if (psa->pvData)
572     {
573       hRet = S_OK;
574       TRACE("%u bytes allocated for data at %p (%u objects).\n",
575             ulSize * psa->cbElements, psa->pvData, ulSize);
576     }
577     else
578       hRet = E_OUTOFMEMORY;
579   }
580   return hRet;
581 }
582 
583 /*************************************************************************
584  *		SafeArrayCreate (OLEAUT32.15)
585  *
586  * Create a new SafeArray.
587  *
588  * PARAMS
589  *  vt        [I] Type to store in the safe array
590  *  cDims     [I] Number of array dimensions
591  *  rgsabound [I] Bounds of the array dimensions
592  *
593  * RETURNS
594  *  Success: A pointer to a new array object.
595  *  Failure: NULL, if any parameter is invalid or memory allocation fails.
596  *
597  * NOTES
598  *  Win32 allows arrays with 0 sized dimensions. This bug is not reproduced
599  *  in the Wine implementation.
600  *  See SafeArray.
601  */
602 SAFEARRAY* WINAPI SafeArrayCreate(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound)
603 {
604   TRACE("(%d->%s,%d,%p)\n", vt, debugstr_vt(vt), cDims, rgsabound);
605 
606   if (vt == VT_RECORD)
607     return NULL;
608 
609   return SAFEARRAY_Create(vt, cDims, rgsabound, 0);
610 }
611 
612 /*************************************************************************
613  *		SafeArrayCreateEx (OLEAUT32.15)
614  *
615  * Create a new SafeArray.
616  *
617  * PARAMS
618  *  vt        [I] Type to store in the safe array
619  *  cDims     [I] Number of array dimensions
620  *  rgsabound [I] Bounds of the array dimensions
621  *  pvExtra   [I] Extra data
622  *
623  * RETURNS
624  *  Success: A pointer to a new array object.
625  *  Failure: NULL, if any parameter is invalid or memory allocation fails.
626  *
627  * NOTES
628  * See SafeArray.
629  */
630 SAFEARRAY* WINAPI SafeArrayCreateEx(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound, LPVOID pvExtra)
631 {
632   ULONG ulSize = 0;
633   IRecordInfo* iRecInfo = pvExtra;
634   SAFEARRAY* psa;
635 
636   TRACE("(%d->%s,%d,%p,%p)\n", vt, debugstr_vt(vt), cDims, rgsabound, pvExtra);
637 
638   if (vt == VT_RECORD)
639   {
640     if  (!iRecInfo)
641       return NULL;
642     IRecordInfo_GetSize(iRecInfo, &ulSize);
643   }
644   psa = SAFEARRAY_Create(vt, cDims, rgsabound, ulSize);
645 
646   if (pvExtra)
647   {
648     switch(vt)
649     {
650       case VT_RECORD:
651         SafeArraySetRecordInfo(psa, pvExtra);
652         break;
653       case VT_UNKNOWN:
654       case VT_DISPATCH:
655         SafeArraySetIID(psa, pvExtra);
656         break;
657     }
658   }
659   return psa;
660 }
661 
662 /************************************************************************
663  *		SafeArrayCreateVector (OLEAUT32.411)
664  *
665  * Create a one dimensional, contiguous SafeArray.
666  *
667  * PARAMS
668  *  vt        [I] Type to store in the safe array
669  *  lLbound   [I] Lower bound of the array
670  *  cElements [I] Number of elements in the array
671  *
672  * RETURNS
673  *  Success: A pointer to a new array object.
674  *  Failure: NULL, if any parameter is invalid or memory allocation fails.
675  *
676  * NOTES
677  * See SafeArray.
678  */
679 SAFEARRAY* WINAPI SafeArrayCreateVector(VARTYPE vt, LONG lLbound, ULONG cElements)
680 {
681   TRACE("(%d->%s,%d,%d\n", vt, debugstr_vt(vt), lLbound, cElements);
682 
683   if (vt == VT_RECORD)
684     return NULL;
685 
686   return SAFEARRAY_CreateVector(vt, lLbound, cElements, SAFEARRAY_GetVTSize(vt));
687 }
688 
689 /************************************************************************
690  *		SafeArrayCreateVectorEx (OLEAUT32.411)
691  *
692  * Create a one dimensional, contiguous SafeArray.
693  *
694  * PARAMS
695  *  vt        [I] Type to store in the safe array
696  *  lLbound   [I] Lower bound of the array
697  *  cElements [I] Number of elements in the array
698  *  pvExtra   [I] Extra data
699  *
700  * RETURNS
701  *  Success: A pointer to a new array object.
702  *  Failure: NULL, if any parameter is invalid or memory allocation fails.
703  *
704  * NOTES
705  * See SafeArray.
706  */
707 SAFEARRAY* WINAPI SafeArrayCreateVectorEx(VARTYPE vt, LONG lLbound, ULONG cElements, LPVOID pvExtra)
708 {
709   ULONG ulSize;
710   IRecordInfo* iRecInfo = pvExtra;
711   SAFEARRAY* psa;
712 
713  TRACE("(%d->%s,%d,%d,%p\n", vt, debugstr_vt(vt), lLbound, cElements, pvExtra);
714 
715   if (vt == VT_RECORD)
716   {
717     if  (!iRecInfo)
718       return NULL;
719     IRecordInfo_GetSize(iRecInfo, &ulSize);
720   }
721   else
722     ulSize = SAFEARRAY_GetVTSize(vt);
723 
724   psa = SAFEARRAY_CreateVector(vt, lLbound, cElements, ulSize);
725 
726   if (pvExtra)
727   {
728     switch(vt)
729     {
730       case VT_RECORD:
731         SafeArraySetRecordInfo(psa, iRecInfo);
732         break;
733       case VT_UNKNOWN:
734       case VT_DISPATCH:
735         SafeArraySetIID(psa, pvExtra);
736         break;
737     }
738   }
739   return psa;
740 }
741 
742 /*************************************************************************
743  *		SafeArrayDestroyDescriptor (OLEAUT32.38)
744  *
745  * Destroy a SafeArray.
746  *
747  * PARAMS
748  *  psa [I] SafeArray to destroy.
749  *
750  * RETURNS
751  *  Success: S_OK. The resources used by the array are freed.
752  *  Failure: An HRESULT error code indicating the error.
753  *
754  * NOTES
755  * See SafeArray.
756  */
757 HRESULT WINAPI SafeArrayDestroyDescriptor(SAFEARRAY *psa)
758 {
759   TRACE("(%p)\n", psa);
760 
761   if (psa)
762   {
763     LPVOID lpv = (char*)psa - SAFEARRAY_HIDDEN_SIZE;
764 
765     if (psa->cLocks)
766       return DISP_E_ARRAYISLOCKED; /* Can't destroy a locked array */
767 
768     if (psa->fFeatures & FADF_RECORD)
769       SafeArraySetRecordInfo(psa, NULL);
770 
771     if (psa->fFeatures & FADF_CREATEVECTOR &&
772         !(psa->fFeatures & FADF_DATADELETED))
773         SAFEARRAY_DestroyData(psa, 0); /* Data not previously deleted */
774 
775     SAFEARRAY_Free(lpv);
776   }
777   return S_OK;
778 }
779 
780 /*************************************************************************
781  *		SafeArrayLock (OLEAUT32.21)
782  *
783  * Increment the lock counter of a SafeArray.
784  *
785  * PARAMS
786  *  psa [O] SafeArray to lock
787  *
788  * RETURNS
789  *  Success: S_OK. The array lock is incremented.
790  *  Failure: E_INVALIDARG if psa is NULL, or E_UNEXPECTED if too many locks
791  *           are held on the array at once.
792  *
793  * NOTES
794  *  In Win32 these locks are not thread safe.
795  *  See SafeArray.
796  */
797 HRESULT WINAPI SafeArrayLock(SAFEARRAY *psa)
798 {
799   ULONG ulLocks;
800 
801   TRACE("(%p)\n", psa);
802 
803   if (!psa)
804     return E_INVALIDARG;
805 
806   ulLocks = InterlockedIncrement( (LONG*) &psa->cLocks);
807 
808   if (ulLocks > 0xffff) /* Maximum of 16384 locks at a time */
809   {
810     WARN("Out of locks!\n");
811     InterlockedDecrement( (LONG*) &psa->cLocks);
812     return E_UNEXPECTED;
813   }
814   return S_OK;
815 }
816 
817 /*************************************************************************
818  *		SafeArrayUnlock (OLEAUT32.22)
819  *
820  * Decrement the lock counter of a SafeArray.
821  *
822  * PARAMS
823  *  psa [O] SafeArray to unlock
824  *
825  * RETURNS
826  *  Success: S_OK. The array lock is decremented.
827  *  Failure: E_INVALIDARG if psa is NULL, or E_UNEXPECTED if no locks are
828  *           held on the array.
829  *
830  * NOTES
831  * See SafeArray.
832  */
833 HRESULT WINAPI SafeArrayUnlock(SAFEARRAY *psa)
834 {
835   TRACE("(%p)\n", psa);
836 
837   if (!psa)
838     return E_INVALIDARG;
839 
840   if (InterlockedDecrement( (LONG*) &psa->cLocks) < 0)
841   {
842     WARN("Unlocked but no lock held!\n");
843     InterlockedIncrement( (LONG*) &psa->cLocks);
844     return E_UNEXPECTED;
845   }
846   return S_OK;
847 }
848 
849 /*************************************************************************
850  *		SafeArrayPutElement (OLEAUT32.26)
851  *
852  * Put an item into a SafeArray.
853  *
854  * PARAMS
855  *  psa       [I] SafeArray to insert into
856  *  rgIndices [I] Indices to insert at
857  *  pvData    [I] Data to insert
858  *
859  * RETURNS
860  *  Success: S_OK. The item is inserted
861  *  Failure: An HRESULT error code indicating the error.
862  *
863  * NOTES
864  * See SafeArray.
865  */
866 HRESULT WINAPI SafeArrayPutElement(SAFEARRAY *psa, LONG *rgIndices, void *pvData)
867 {
868   HRESULT hRet;
869 
870   TRACE("(%p,%p,%p)\n", psa, rgIndices, pvData);
871 
872   if (!psa || !rgIndices)
873     return E_INVALIDARG;
874 
875   hRet = SafeArrayLock(psa);
876 
877   if (SUCCEEDED(hRet))
878   {
879     PVOID lpvDest;
880 
881     hRet = SafeArrayPtrOfIndex(psa, rgIndices, &lpvDest);
882 
883     if (SUCCEEDED(hRet))
884     {
885       if (psa->fFeatures & FADF_VARIANT)
886       {
887         VARIANT* lpVariant = pvData;
888         VARIANT* lpDest = lpvDest;
889 
890         hRet = VariantCopy(lpDest, lpVariant);
891         if (FAILED(hRet)) FIXME("VariantCopy failed with 0x%x\n", hRet);
892       }
893       else if (psa->fFeatures & FADF_BSTR)
894       {
895         BSTR  lpBstr = (BSTR)pvData;
896         BSTR* lpDest = lpvDest;
897 
898         SysFreeString(*lpDest);
899 
900         *lpDest = SysAllocStringByteLen((char*)lpBstr, SysStringByteLen(lpBstr));
901         if (!*lpDest)
902           hRet = E_OUTOFMEMORY;
903       }
904       else if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
905       {
906         IUnknown  *lpUnknown = pvData;
907         IUnknown **lpDest = lpvDest;
908 
909         if (lpUnknown)
910           IUnknown_AddRef(lpUnknown);
911         if (*lpDest)
912           IUnknown_Release(*lpDest);
913         *lpDest = lpUnknown;
914       }
915       else if (psa->fFeatures & FADF_RECORD)
916       {
917         IRecordInfo *record;
918 
919         SafeArrayGetRecordInfo(psa, &record);
920         hRet = IRecordInfo_RecordCopy(record, pvData, lpvDest);
921         IRecordInfo_Release(record);
922       } else
923         /* Copy the data over */
924         memcpy(lpvDest, pvData, psa->cbElements);
925     }
926     SafeArrayUnlock(psa);
927   }
928   return hRet;
929 }
930 
931 
932 /*************************************************************************
933  *		SafeArrayGetElement (OLEAUT32.25)
934  *
935  * Get an item from a SafeArray.
936  *
937  * PARAMS
938  *  psa       [I] SafeArray to get from
939  *  rgIndices [I] Indices to get from
940  *  pvData    [O] Destination for data
941  *
942  * RETURNS
943  *  Success: S_OK. The item data is returned in pvData.
944  *  Failure: An HRESULT error code indicating the error.
945  *
946  * NOTES
947  * See SafeArray.
948  */
949 HRESULT WINAPI SafeArrayGetElement(SAFEARRAY *psa, LONG *rgIndices, void *pvData)
950 {
951   HRESULT hRet;
952 
953   TRACE("(%p,%p,%p)\n", psa, rgIndices, pvData);
954 
955   if (!psa || !rgIndices || !pvData)
956     return E_INVALIDARG;
957 
958   hRet = SafeArrayLock(psa);
959 
960   if (SUCCEEDED(hRet))
961   {
962     PVOID lpvSrc;
963 
964     hRet = SafeArrayPtrOfIndex(psa, rgIndices, &lpvSrc);
965 
966     if (SUCCEEDED(hRet))
967     {
968       if (psa->fFeatures & FADF_VARIANT)
969       {
970         VARIANT* lpVariant = lpvSrc;
971         VARIANT* lpDest = pvData;
972 
973         /* The original content of pvData is ignored. */
974         V_VT(lpDest) = VT_EMPTY;
975         hRet = VariantCopy(lpDest, lpVariant);
976 	if (FAILED(hRet)) FIXME("VariantCopy failed with 0x%x\n", hRet);
977       }
978       else if (psa->fFeatures & FADF_BSTR)
979       {
980         BSTR* lpBstr = lpvSrc;
981         BSTR* lpDest = pvData;
982 
983         if (*lpBstr)
984         {
985           *lpDest = SysAllocStringByteLen((char*)*lpBstr, SysStringByteLen(*lpBstr));
986           if (!*lpBstr)
987             hRet = E_OUTOFMEMORY;
988         }
989         else
990           *lpDest = NULL;
991       }
992       else if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
993       {
994         IUnknown **src_unk = lpvSrc;
995         IUnknown **dest_unk = pvData;
996 
997         if (*src_unk)
998           IUnknown_AddRef(*src_unk);
999         *dest_unk = *src_unk;
1000       }
1001       else if (psa->fFeatures & FADF_RECORD)
1002       {
1003         IRecordInfo *record;
1004 
1005         SafeArrayGetRecordInfo(psa, &record);
1006         hRet = IRecordInfo_RecordCopy(record, lpvSrc, pvData);
1007         IRecordInfo_Release(record);
1008       }
1009       else
1010         /* Copy the data over */
1011         memcpy(pvData, lpvSrc, psa->cbElements);
1012     }
1013     SafeArrayUnlock(psa);
1014   }
1015   return hRet;
1016 }
1017 
1018 /*************************************************************************
1019  *		SafeArrayGetUBound (OLEAUT32.19)
1020  *
1021  * Get the upper bound for a given SafeArray dimension
1022  *
1023  * PARAMS
1024  *  psa      [I] Array to get dimension upper bound from
1025  *  nDim     [I] The dimension number to get the upper bound of
1026  *  plUbound [O] Destination for the upper bound
1027  *
1028  * RETURNS
1029  *  Success: S_OK. plUbound contains the dimensions upper bound.
1030  *  Failure: An HRESULT error code indicating the error.
1031  *
1032  * NOTES
1033  * See SafeArray.
1034  */
1035 HRESULT WINAPI SafeArrayGetUBound(SAFEARRAY *psa, UINT nDim, LONG *plUbound)
1036 {
1037   TRACE("(%p,%d,%p)\n", psa, nDim, plUbound);
1038 
1039   if (!psa || !plUbound)
1040     return E_INVALIDARG;
1041 
1042   if(!nDim || nDim > psa->cDims)
1043     return DISP_E_BADINDEX;
1044 
1045   *plUbound = psa->rgsabound[psa->cDims - nDim].lLbound +
1046               psa->rgsabound[psa->cDims - nDim].cElements - 1;
1047 
1048   return S_OK;
1049 }
1050 
1051 /*************************************************************************
1052  *		SafeArrayGetLBound (OLEAUT32.20)
1053  *
1054  * Get the lower bound for a given SafeArray dimension
1055  *
1056  * PARAMS
1057  *  psa      [I] Array to get dimension lower bound from
1058  *  nDim     [I] The dimension number to get the lower bound of
1059  *  plLbound [O] Destination for the lower bound
1060  *
1061  * RETURNS
1062  *  Success: S_OK. plUbound contains the dimensions lower bound.
1063  *  Failure: An HRESULT error code indicating the error.
1064  *
1065  * NOTES
1066  * See SafeArray.
1067  */
1068 HRESULT WINAPI SafeArrayGetLBound(SAFEARRAY *psa, UINT nDim, LONG *plLbound)
1069 {
1070   TRACE("(%p,%d,%p)\n", psa, nDim, plLbound);
1071 
1072   if (!psa || !plLbound)
1073     return E_INVALIDARG;
1074 
1075   if(!nDim || nDim > psa->cDims)
1076     return DISP_E_BADINDEX;
1077 
1078   *plLbound = psa->rgsabound[psa->cDims - nDim].lLbound;
1079   return S_OK;
1080 }
1081 
1082 /*************************************************************************
1083  *		SafeArrayGetDim (OLEAUT32.17)
1084  *
1085  * Get the number of dimensions in a SafeArray.
1086  *
1087  * PARAMS
1088  *  psa [I] Array to get the dimensions of
1089  *
1090  * RETURNS
1091  *  The number of array dimensions in psa, or 0 if psa is NULL.
1092  *
1093  * NOTES
1094  * See SafeArray.
1095  */
1096 UINT WINAPI SafeArrayGetDim(SAFEARRAY *psa)
1097 {
1098   TRACE("(%p) returning %d\n", psa, psa ? psa->cDims : 0u);
1099   return psa ? psa->cDims : 0;
1100 }
1101 
1102 /*************************************************************************
1103  *		SafeArrayGetElemsize (OLEAUT32.18)
1104  *
1105  * Get the size of an element in a SafeArray.
1106  *
1107  * PARAMS
1108  *  psa [I] Array to get the element size from
1109  *
1110  * RETURNS
1111  *  The size of a single element in psa, or 0 if psa is NULL.
1112  *
1113  * NOTES
1114  * See SafeArray.
1115  */
1116 UINT WINAPI SafeArrayGetElemsize(SAFEARRAY *psa)
1117 {
1118   TRACE("(%p) returning %d\n", psa, psa ? psa->cbElements : 0u);
1119   return psa ? psa->cbElements : 0;
1120 }
1121 
1122 /*************************************************************************
1123  *		SafeArrayAccessData (OLEAUT32.23)
1124  *
1125  * Lock a SafeArray and return a pointer to its data.
1126  *
1127  * PARAMS
1128  *  psa     [I] Array to get the data pointer from
1129  *  ppvData [O] Destination for the arrays data pointer
1130  *
1131  * RETURNS
1132  *  Success: S_OK. ppvData contains the arrays data pointer, and the array
1133  *           is locked.
1134  *  Failure: An HRESULT error code indicating the error.
1135  *
1136  * NOTES
1137  * See SafeArray.
1138  */
1139 HRESULT WINAPI SafeArrayAccessData(SAFEARRAY *psa, void **ppvData)
1140 {
1141   HRESULT hr;
1142 
1143   TRACE("(%p,%p)\n", psa, ppvData);
1144 
1145   if(!psa || !ppvData)
1146     return E_INVALIDARG;
1147 
1148   hr = SafeArrayLock(psa);
1149   *ppvData = SUCCEEDED(hr) ? psa->pvData : NULL;
1150 
1151   return hr;
1152 }
1153 
1154 
1155 /*************************************************************************
1156  *		SafeArrayUnaccessData (OLEAUT32.24)
1157  *
1158  * Unlock a SafeArray after accessing its data.
1159  *
1160  * PARAMS
1161  *  psa     [I] Array to unlock
1162  *
1163  * RETURNS
1164  *  Success: S_OK. The array is unlocked.
1165  *  Failure: An HRESULT error code indicating the error.
1166  *
1167  * NOTES
1168  * See SafeArray.
1169  */
1170 HRESULT WINAPI SafeArrayUnaccessData(SAFEARRAY *psa)
1171 {
1172   TRACE("(%p)\n", psa);
1173   return SafeArrayUnlock(psa);
1174 }
1175 
1176 /************************************************************************
1177  *		SafeArrayPtrOfIndex (OLEAUT32.148)
1178  *
1179  * Get the address of an item in a SafeArray.
1180  *
1181  * PARAMS
1182  *  psa       [I] Array to get the items address from
1183  *  rgIndices [I] Index of the item in the array
1184  *  ppvData   [O] Destination for item address
1185  *
1186  * RETURNS
1187  *  Success: S_OK. ppvData contains a pointer to the item.
1188  *  Failure: An HRESULT error code indicating the error.
1189  *
1190  * NOTES
1191  *  This function does not lock the array.
1192  *
1193  * NOTES
1194  * See SafeArray.
1195  */
1196 HRESULT WINAPI SafeArrayPtrOfIndex(SAFEARRAY *psa, LONG *rgIndices, void **ppvData)
1197 {
1198   USHORT dim;
1199   ULONG cell = 0, dimensionSize = 1;
1200   SAFEARRAYBOUND* psab;
1201   LONG c1;
1202 
1203   TRACE("(%p,%p,%p)\n", psa, rgIndices, ppvData);
1204 
1205   /* The general formula for locating the cell number of an entry in an n
1206    * dimensional array (where cn = coordinate in dimension dn) is:
1207    *
1208    * c1 + c2 * sizeof(d1) + c3 * sizeof(d2) ... + cn * sizeof(c(n-1))
1209    *
1210    * We calculate the size of the last dimension at each step through the
1211    * dimensions to avoid recursing to calculate the last dimensions size.
1212    */
1213   if (!psa || !rgIndices || !ppvData)
1214     return E_INVALIDARG;
1215 
1216   psab = psa->rgsabound + psa->cDims - 1;
1217   c1 = *rgIndices++;
1218 
1219   if (c1 < psab->lLbound || c1 >= psab->lLbound + (LONG)psab->cElements)
1220     return DISP_E_BADINDEX; /* Initial index out of bounds */
1221 
1222   for (dim = 1; dim < psa->cDims; dim++)
1223   {
1224     dimensionSize *= psab->cElements;
1225 
1226     psab--;
1227 
1228     if (!psab->cElements ||
1229         *rgIndices < psab->lLbound ||
1230         *rgIndices >= psab->lLbound + (LONG)psab->cElements)
1231     return DISP_E_BADINDEX; /* Index out of bounds */
1232 
1233     cell += (*rgIndices - psab->lLbound) * dimensionSize;
1234     rgIndices++;
1235   }
1236 
1237   cell += (c1 - psa->rgsabound[psa->cDims - 1].lLbound);
1238 
1239   *ppvData = (char*)psa->pvData + cell * psa->cbElements;
1240   return S_OK;
1241 }
1242 
1243 /************************************************************************
1244  *		SafeArrayDestroyData (OLEAUT32.39)
1245  *
1246  * Destroy the data associated with a SafeArray.
1247  *
1248  * PARAMS
1249  *  psa [I] Array to delete the data from
1250  *
1251  * RETURNS
1252  *  Success: S_OK. All items and the item data are freed.
1253  *  Failure: An HRESULT error code indicating the error.
1254  *
1255  * NOTES
1256  * See SafeArray.
1257  */
1258 HRESULT WINAPI SafeArrayDestroyData(SAFEARRAY *psa)
1259 {
1260   HRESULT hr;
1261 
1262   TRACE("(%p)\n", psa);
1263 
1264   if (!psa)
1265     return E_INVALIDARG;
1266 
1267   if (psa->cLocks)
1268     return DISP_E_ARRAYISLOCKED; /* Can't delete a locked array */
1269 
1270   /* Delete the actual item data */
1271   hr = SAFEARRAY_DestroyData(psa, 0);
1272   if (FAILED(hr))
1273     return hr;
1274 
1275   if (psa->pvData)
1276   {
1277     if (psa->fFeatures & FADF_STATIC)
1278     {
1279       ZeroMemory(psa->pvData, SAFEARRAY_GetCellCount(psa) * psa->cbElements);
1280       return S_OK;
1281     }
1282     /* If this is not a vector, free the data memory block */
1283     if (!(psa->fFeatures & FADF_CREATEVECTOR))
1284     {
1285       SAFEARRAY_Free(psa->pvData);
1286       psa->pvData = NULL;
1287     }
1288     else
1289       psa->fFeatures |= FADF_DATADELETED; /* Mark the data deleted */
1290 
1291   }
1292   return S_OK;
1293 }
1294 
1295 /************************************************************************
1296  *		SafeArrayCopyData (OLEAUT32.412)
1297  *
1298  * Copy all data from one SafeArray to another.
1299  *
1300  * PARAMS
1301  *  psaSource [I] Source for copy
1302  *  psaTarget [O] Destination for copy
1303  *
1304  * RETURNS
1305  *  Success: S_OK. psaTarget contains a copy of psaSource.
1306  *  Failure: An HRESULT error code indicating the error.
1307  *
1308  * NOTES
1309  *  The two arrays must have the same number of dimensions and elements.
1310  *
1311  * NOTES
1312  * See SafeArray.
1313  */
1314 HRESULT WINAPI SafeArrayCopyData(SAFEARRAY *psaSource, SAFEARRAY *psaTarget)
1315 {
1316   int dim;
1317 
1318   TRACE("(%p,%p)\n", psaSource, psaTarget);
1319 
1320   if (!psaSource || !psaTarget ||
1321       psaSource->cDims != psaTarget->cDims ||
1322       psaSource->cbElements != psaTarget->cbElements)
1323     return E_INVALIDARG;
1324 
1325   /* Each dimension must be the same size */
1326   for (dim = psaSource->cDims - 1; dim >= 0 ; dim--)
1327     if (psaSource->rgsabound[dim].cElements !=
1328        psaTarget->rgsabound[dim].cElements)
1329       return E_INVALIDARG;
1330 
1331   return SAFEARRAY_CopyData(psaSource, psaTarget);
1332 }
1333 
1334 /************************************************************************
1335  *		SafeArrayDestroy (OLEAUT32.16)
1336  *
1337  * Destroy a SafeArray.
1338  *
1339  * PARAMS
1340  *  psa [I] Array to destroy
1341  *
1342  * RETURNS
1343  *  Success: S_OK. All resources used by the array are freed.
1344  *  Failure: An HRESULT error code indicating the error.
1345  *
1346  * NOTES
1347  * See SafeArray.
1348  */
1349 HRESULT WINAPI SafeArrayDestroy(SAFEARRAY *psa)
1350 {
1351   TRACE("(%p)\n", psa);
1352 
1353   if(!psa)
1354     return S_OK;
1355 
1356   if(psa->cLocks > 0)
1357     return DISP_E_ARRAYISLOCKED;
1358 
1359   /* Native doesn't check to see if the free succeeds */
1360   SafeArrayDestroyData(psa);
1361   SafeArrayDestroyDescriptor(psa);
1362   return S_OK;
1363 }
1364 
1365 /************************************************************************
1366  *		SafeArrayCopy (OLEAUT32.27)
1367  *
1368  * Make a duplicate of a SafeArray.
1369  *
1370  * PARAMS
1371  *  psa     [I] Source for copy
1372  *  ppsaOut [O] Destination for new copy
1373  *
1374  * RETURNS
1375  *  Success: S_OK. ppsaOut contains a copy of the array.
1376  *  Failure: An HRESULT error code indicating the error.
1377  *
1378  * NOTES
1379  * See SafeArray.
1380  */
1381 HRESULT WINAPI SafeArrayCopy(SAFEARRAY *psa, SAFEARRAY **ppsaOut)
1382 {
1383   HRESULT hRet;
1384 
1385   TRACE("(%p,%p)\n", psa, ppsaOut);
1386 
1387   if (!ppsaOut)
1388     return E_INVALIDARG;
1389 
1390   *ppsaOut = NULL;
1391 
1392   if (!psa)
1393     return S_OK; /* Handles copying of NULL arrays */
1394 
1395   if (!psa->cbElements)
1396     return E_INVALIDARG;
1397 
1398   if (psa->fFeatures & (FADF_RECORD|FADF_HAVEIID|FADF_HAVEVARTYPE))
1399   {
1400     VARTYPE vt;
1401 
1402     hRet = SafeArrayGetVartype(psa, &vt);
1403     if (SUCCEEDED(hRet))
1404       hRet = SafeArrayAllocDescriptorEx(vt, psa->cDims, ppsaOut);
1405   }
1406   else
1407   {
1408     hRet = SafeArrayAllocDescriptor(psa->cDims, ppsaOut);
1409     if (SUCCEEDED(hRet))
1410     {
1411       (*ppsaOut)->fFeatures = psa->fFeatures & ~ignored_copy_features;
1412       (*ppsaOut)->cbElements = psa->cbElements;
1413     }
1414   }
1415 
1416   if (SUCCEEDED(hRet))
1417   {
1418     /* Copy dimension bounds */
1419     memcpy((*ppsaOut)->rgsabound, psa->rgsabound, psa->cDims * sizeof(SAFEARRAYBOUND));
1420 
1421     (*ppsaOut)->pvData = SAFEARRAY_Malloc(SAFEARRAY_GetCellCount(psa) * psa->cbElements);
1422     if (!(*ppsaOut)->pvData)
1423     {
1424       SafeArrayDestroyDescriptor(*ppsaOut);
1425       *ppsaOut = NULL;
1426       return E_OUTOFMEMORY;
1427     }
1428 
1429     hRet = SAFEARRAY_CopyData(psa, *ppsaOut);
1430     if (FAILED(hRet))
1431     {
1432       SAFEARRAY_Free((*ppsaOut)->pvData);
1433       SafeArrayDestroyDescriptor(*ppsaOut);
1434       *ppsaOut = NULL;
1435       return hRet;
1436     }
1437   }
1438 
1439   return hRet;
1440 }
1441 
1442 /************************************************************************
1443  *		SafeArrayRedim (OLEAUT32.40)
1444  *
1445  * Changes the characteristics of the last dimension of a SafeArray
1446  *
1447  * PARAMS
1448  *  psa      [I] Array to change
1449  *  psabound [I] New bound details for the last dimension
1450  *
1451  * RETURNS
1452  *  Success: S_OK. psa is updated to reflect the new bounds.
1453  *  Failure: An HRESULT error code indicating the error.
1454  *
1455  * NOTES
1456  * See SafeArray.
1457  */
1458 HRESULT WINAPI SafeArrayRedim(SAFEARRAY *psa, SAFEARRAYBOUND *psabound)
1459 {
1460   SAFEARRAYBOUND *oldBounds;
1461   HRESULT hr;
1462 
1463   TRACE("(%p,%p)\n", psa, psabound);
1464 
1465   if (!psa || psa->fFeatures & FADF_FIXEDSIZE || !psabound)
1466     return E_INVALIDARG;
1467 
1468   if (psa->cLocks > 0)
1469     return DISP_E_ARRAYISLOCKED;
1470 
1471   hr = SafeArrayLock(psa);
1472   if (FAILED(hr))
1473     return hr;
1474 
1475   oldBounds = psa->rgsabound;
1476   oldBounds->lLbound = psabound->lLbound;
1477 
1478   if (psabound->cElements != oldBounds->cElements)
1479   {
1480     if (psabound->cElements < oldBounds->cElements)
1481     {
1482       /* Shorten the final dimension. */
1483       ULONG ulStartCell = psabound->cElements *
1484                           (SAFEARRAY_GetCellCount(psa) / oldBounds->cElements);
1485       SAFEARRAY_DestroyData(psa, ulStartCell);
1486     }
1487     else
1488     {
1489       /* Lengthen the final dimension */
1490       ULONG ulOldSize, ulNewSize;
1491       PVOID pvNewData;
1492 
1493       ulOldSize = SAFEARRAY_GetCellCount(psa) * psa->cbElements;
1494       if (ulOldSize)
1495         ulNewSize = (ulOldSize / oldBounds->cElements) * psabound->cElements;
1496       else {
1497 	int oldelems = oldBounds->cElements;
1498 	oldBounds->cElements = psabound->cElements;
1499         ulNewSize = SAFEARRAY_GetCellCount(psa) * psa->cbElements;
1500 	oldBounds->cElements = oldelems;
1501       }
1502 
1503       if (!(pvNewData = SAFEARRAY_Malloc(ulNewSize)))
1504       {
1505         SafeArrayUnlock(psa);
1506         return E_OUTOFMEMORY;
1507       }
1508 
1509       memcpy(pvNewData, psa->pvData, ulOldSize);
1510       SAFEARRAY_Free(psa->pvData);
1511       psa->pvData = pvNewData;
1512     }
1513     oldBounds->cElements = psabound->cElements;
1514   }
1515 
1516   SafeArrayUnlock(psa);
1517   return S_OK;
1518 }
1519 
1520 /************************************************************************
1521  *		SafeArrayGetVartype (OLEAUT32.77)
1522  *
1523  * Get the type of the items in a SafeArray.
1524  *
1525  * PARAMS
1526  *  psa [I] Array to get the type from
1527  *  pvt [O] Destination for the type
1528  *
1529  * RETURNS
1530  *  Success: S_OK. pvt contains the type of the items.
1531  *  Failure: An HRESULT error code indicating the error.
1532  *
1533  * NOTES
1534  * See SafeArray.
1535  */
1536 HRESULT WINAPI SafeArrayGetVartype(SAFEARRAY* psa, VARTYPE* pvt)
1537 {
1538   TRACE("(%p,%p)\n", psa, pvt);
1539 
1540   if (!psa || !pvt)
1541     return E_INVALIDARG;
1542 
1543   if (psa->fFeatures & FADF_RECORD)
1544     *pvt = VT_RECORD;
1545   else if ((psa->fFeatures & (FADF_HAVEIID|FADF_DISPATCH)) == (FADF_HAVEIID|FADF_DISPATCH))
1546     *pvt = VT_DISPATCH;
1547   else if (psa->fFeatures & FADF_HAVEIID)
1548     *pvt = VT_UNKNOWN;
1549   else if (psa->fFeatures & FADF_HAVEVARTYPE)
1550   {
1551     VARTYPE vt = SAFEARRAY_GetHiddenDWORD(psa);
1552     *pvt = vt;
1553   }
1554   else
1555     return E_INVALIDARG;
1556 
1557   return S_OK;
1558 }
1559 
1560 /************************************************************************
1561  *		SafeArraySetRecordInfo (OLEAUT32.@)
1562  *
1563  * Set the record info for a SafeArray.
1564  *
1565  * PARAMS
1566  *  psa    [I] Array to set the record info for
1567  *  pRinfo [I] Record info
1568  *
1569  * RETURNS
1570  *  Success: S_OK. The record info is stored with the array.
1571  *  Failure: An HRESULT error code indicating the error.
1572  *
1573  * NOTES
1574  * See SafeArray.
1575  */
1576 HRESULT WINAPI SafeArraySetRecordInfo(SAFEARRAY *psa, IRecordInfo *pRinfo)
1577 {
1578   IRecordInfo** dest = (IRecordInfo**)psa;
1579 
1580   TRACE("(%p,%p)\n", psa, pRinfo);
1581 
1582   if (!psa || !(psa->fFeatures & FADF_RECORD))
1583     return E_INVALIDARG;
1584 
1585   if (pRinfo)
1586     IRecordInfo_AddRef(pRinfo);
1587 
1588   if (dest[-1])
1589     IRecordInfo_Release(dest[-1]);
1590 
1591   dest[-1] = pRinfo;
1592   return S_OK;
1593 }
1594 
1595 /************************************************************************
1596  *		SafeArrayGetRecordInfo (OLEAUT32.@)
1597  *
1598  * Get the record info from a SafeArray.
1599  *
1600  * PARAMS
1601  *  psa    [I] Array to get the record info from
1602  *  pRinfo [O] Destination for the record info
1603  *
1604  * RETURNS
1605  *  Success: S_OK. pRinfo contains the record info, or NULL if there was none.
1606  *  Failure: An HRESULT error code indicating the error.
1607  *
1608  * NOTES
1609  * See SafeArray.
1610  */
1611 HRESULT WINAPI SafeArrayGetRecordInfo(SAFEARRAY *psa, IRecordInfo **pRinfo)
1612 {
1613   IRecordInfo** src = (IRecordInfo**)psa;
1614 
1615   TRACE("(%p,%p)\n", psa, pRinfo);
1616 
1617   if (!psa || !pRinfo || !(psa->fFeatures & FADF_RECORD))
1618     return E_INVALIDARG;
1619 
1620   *pRinfo = src[-1];
1621 
1622   if (*pRinfo)
1623     IRecordInfo_AddRef(*pRinfo);
1624   return S_OK;
1625 }
1626 
1627 /************************************************************************
1628  *		SafeArraySetIID (OLEAUT32.@)
1629  *
1630  * Set the IID for a SafeArray.
1631  *
1632  * PARAMS
1633  *  psa  [I] Array to set the IID from
1634  *  guid [I] IID
1635  *
1636  * RETURNS
1637  *  Success: S_OK. The IID is stored with the array
1638  *  Failure: An HRESULT error code indicating the error.
1639  *
1640  * NOTES
1641  * See SafeArray.
1642  */
1643 HRESULT WINAPI SafeArraySetIID(SAFEARRAY *psa, REFGUID guid)
1644 {
1645   GUID* dest = (GUID*)psa;
1646 
1647   TRACE("(%p,%s)\n", psa, debugstr_guid(guid));
1648 
1649   if (!psa || !guid || !(psa->fFeatures & FADF_HAVEIID))
1650     return E_INVALIDARG;
1651 
1652   dest[-1] = *guid;
1653   return S_OK;
1654 }
1655 
1656 /************************************************************************
1657  *		SafeArrayGetIID (OLEAUT32.@)
1658  *
1659  * Get the IID from a SafeArray.
1660  *
1661  * PARAMS
1662  *  psa   [I] Array to get the ID from
1663  *  pGuid [O] Destination for the IID
1664  *
1665  * RETURNS
1666  *  Success: S_OK. pRinfo contains the IID, or NULL if there was none.
1667  *  Failure: An HRESULT error code indicating the error.
1668  *
1669  * NOTES
1670  * See SafeArray.
1671  */
1672 HRESULT WINAPI SafeArrayGetIID(SAFEARRAY *psa, GUID *pGuid)
1673 {
1674   GUID* src = (GUID*)psa;
1675 
1676   TRACE("(%p,%p)\n", psa, pGuid);
1677 
1678   if (!psa || !pGuid || !(psa->fFeatures & FADF_HAVEIID))
1679     return E_INVALIDARG;
1680 
1681   *pGuid = src[-1];
1682   return S_OK;
1683 }
1684 
1685 /************************************************************************
1686  *		VectorFromBstr (OLEAUT32.@)
1687  *
1688  * Create a SafeArray Vector from the bytes of a BSTR.
1689  *
1690  * PARAMS
1691  *  bstr [I] String to get bytes from
1692  *  ppsa [O] Destination for the array
1693  *
1694  * RETURNS
1695  *  Success: S_OK. ppsa contains the strings bytes as a VT_UI1 array.
1696  *  Failure: An HRESULT error code indicating the error.
1697  *
1698  * NOTES
1699  * See SafeArray.
1700  */
1701 HRESULT WINAPI VectorFromBstr(BSTR bstr, SAFEARRAY **ppsa)
1702 {
1703   SAFEARRAYBOUND sab;
1704 
1705   TRACE("(%p,%p)\n", bstr, ppsa);
1706 
1707   if (!ppsa)
1708     return E_INVALIDARG;
1709 
1710   sab.lLbound = 0;
1711   sab.cElements = SysStringByteLen(bstr);
1712 
1713   *ppsa = SAFEARRAY_Create(VT_UI1, 1, &sab, 0);
1714 
1715   if (*ppsa)
1716   {
1717     memcpy((*ppsa)->pvData, bstr, sab.cElements);
1718     return S_OK;
1719   }
1720   return E_OUTOFMEMORY;
1721 }
1722 
1723 /************************************************************************
1724  *		BstrFromVector (OLEAUT32.@)
1725  *
1726  * Create a BSTR from a SafeArray.
1727  *
1728  * PARAMS
1729  *  psa   [I] Source array
1730  *  pbstr [O] Destination for output BSTR
1731  *
1732  * RETURNS
1733  *  Success: S_OK. pbstr contains the arrays data.
1734  *  Failure: An HRESULT error code indicating the error.
1735  *
1736  * NOTES
1737  *  psa must be a 1 dimensional array of a 1 byte type.
1738  *
1739  * NOTES
1740  * See SafeArray.
1741  */
1742 HRESULT WINAPI BstrFromVector(SAFEARRAY *psa, BSTR *pbstr)
1743 {
1744   TRACE("(%p,%p)\n", psa, pbstr);
1745 
1746   if (!pbstr)
1747     return E_INVALIDARG;
1748 
1749   *pbstr = NULL;
1750 
1751   if (!psa || psa->cbElements != 1 || psa->cDims != 1)
1752     return E_INVALIDARG;
1753 
1754   *pbstr = SysAllocStringByteLen(psa->pvData, psa->rgsabound[0].cElements);
1755   if (!*pbstr)
1756     return E_OUTOFMEMORY;
1757   return S_OK;
1758 }
1759