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