Add strmif.h to the headers included in libuuid.
[wine] / dlls / oleaut32 / safearray.c
1 /*************************************************************************
2  * OLE Automation
3  * SafeArray Implementation
4  *
5  * This file contains the implementation of the SafeArray interface.
6  *
7  * Copyright 1999 Sylvain St-Germain
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 /* Memory Layout of a SafeArray:
24  *
25  * -0x10: start of memory.
26  * -0x10: GUID  for VT_DISPATCH and VT_UNKNOWN safearrays (if FADF_HAVEIID)
27  * -0x04: DWORD varianttype; (for all others, except VT_RECORD) (if FADF_HAVEVARTYPE)
28  *  -0x4: IRecordInfo* iface;   (if FADF_RECORD, for VT_RECORD (can be NULL))
29  *  0x00: SAFEARRAY,
30  *  0x10: SAFEARRAYBOUNDS[0...]
31  */
32
33 #include <stdio.h>
34 #include <string.h>
35 #include "windef.h"
36 #include "winerror.h"
37 #include "winbase.h"
38 #include "oleauto.h"
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(ole);
42
43 #define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
44
45 /* Locally used methods */
46 static ULONG
47 calcDisplacement(LONG *coor, SAFEARRAYBOUND *mat, LONG dim);
48
49 static BOOL
50 isPointer(USHORT feature);
51
52 static INT
53 getFeatures(VARTYPE vt);
54
55 static BOOL
56 validCoordinate(LONG *coor, SAFEARRAY *psa);
57
58 static BOOL
59 resizeSafeArray(SAFEARRAY *psa, LONG lDelta);
60
61 static BOOL
62 validArg(SAFEARRAY *psa);
63
64 static ULONG
65 getArraySize(SAFEARRAY *psa);
66
67 static HRESULT
68 duplicateData(SAFEARRAY *psa, SAFEARRAY *ppsaOut);
69
70 /* Association between VARTYPE and their size.
71    A size of zero is defined for the unsupported types.  */
72
73 #define VARTYPE_NOT_SUPPORTED 0
74 static const ULONG VARTYPE_SIZE[] =
75 {
76   /* this is taken from wtypes.h.  Only [S]es are supported by the SafeArray */
77 VARTYPE_NOT_SUPPORTED,  /* VT_EMPTY    [V]   [P]    nothing                     */
78 VARTYPE_NOT_SUPPORTED,  /* VT_NULL     [V]   [P]    SQL style Nul       */
79 2,                      /* VT_I2       [V][T][P][S] 2 byte signed int */
80 4,                      /* VT_I4       [V][T][P][S] 4 byte signed int */
81 4,                      /* VT_R4       [V][T][P][S] 4 byte real */
82 8,                      /* VT_R8       [V][T][P][S] 8 byte real */
83 8,                      /* VT_CY       [V][T][P][S] currency */
84 8,                      /* VT_DATE     [V][T][P][S] date */
85 sizeof(BSTR),           /* VT_BSTR     [V][T][P][S] OLE Automation string*/
86 sizeof(LPDISPATCH),     /* VT_DISPATCH [V][T][P][S] IDispatch * */
87 4,                      /* VT_ERROR    [V][T]   [S] SCODE       */
88 2,                      /* VT_BOOL     [V][T][P][S] True=-1, False=0*/
89 sizeof(VARIANT),        /* VT_VARIANT  [V][T][P][S] VARIANT *   */
90 sizeof(LPUNKNOWN),      /* VT_UNKNOWN  [V][T]   [S] IUnknown * */
91 sizeof(DECIMAL),        /* VT_DECIMAL  [V][T]   [S] 16 byte fixed point */
92 VARTYPE_NOT_SUPPORTED,                         /* no VARTYPE here.....  */
93 1,                      /* VT_I1          [T]   [S] signed char         */
94 1,                      /* VT_UI1      [V][T][P][S] unsigned char       */
95 2,                      /* VT_UI2         [T][P][S] unsigned short      */
96 4,                      /* VT_UI4         [T][P][S] unsigned int        */
97 VARTYPE_NOT_SUPPORTED,  /* VT_I8          [T][P]    signed 64-bit int                   */
98 VARTYPE_NOT_SUPPORTED,  /* VT_UI8         [T][P]    unsigned 64-bit int         */
99 sizeof(INT),            /* VT_INT         [T]       signed machine int          */
100 sizeof(UINT),           /* VT_UINT        [T]       unsigned machine int        */
101 VARTYPE_NOT_SUPPORTED,  /* VT_VOID        [T]       C style void                        */
102 VARTYPE_NOT_SUPPORTED,  /* VT_HRESULT     [T]       Standard return type        */
103 VARTYPE_NOT_SUPPORTED,  /* VT_PTR         [T]       pointer type                        */
104 VARTYPE_NOT_SUPPORTED,  /* VT_SAFEARRAY   [T]       (use VT_ARRAY in VARIANT)*/
105 VARTYPE_NOT_SUPPORTED,  /* VT_CARRAY      [T]       C style array                       */
106 VARTYPE_NOT_SUPPORTED,  /* VT_USERDEFINED [T]       user defined type                   */
107 VARTYPE_NOT_SUPPORTED,  /* VT_LPSTR       [T][P]    null terminated string      */
108 VARTYPE_NOT_SUPPORTED,  /* VT_LPWSTR      [T][P]    wide null term string               */
109 VARTYPE_NOT_SUPPORTED,  /* 32 */
110 VARTYPE_NOT_SUPPORTED,  /* 33 */
111 VARTYPE_NOT_SUPPORTED,  /* 34 */
112 VARTYPE_NOT_SUPPORTED,  /* 35 */
113 VARTYPE_NOT_SUPPORTED,  /* VT_RECORD                record */
114 VARTYPE_NOT_SUPPORTED,  /* 37 */
115 VARTYPE_NOT_SUPPORTED,  /* 38 */
116 VARTYPE_NOT_SUPPORTED,  /* 39 */
117 VARTYPE_NOT_SUPPORTED,  /* 40 */
118 VARTYPE_NOT_SUPPORTED,  /* 41 */
119 VARTYPE_NOT_SUPPORTED,  /* 42 */
120 VARTYPE_NOT_SUPPORTED,  /* 43 */
121 VARTYPE_NOT_SUPPORTED,  /* 44 */
122 VARTYPE_NOT_SUPPORTED,  /* 45 */
123 VARTYPE_NOT_SUPPORTED,  /* 46 */
124 VARTYPE_NOT_SUPPORTED,  /* 47 */
125 VARTYPE_NOT_SUPPORTED,  /* 48 */
126 VARTYPE_NOT_SUPPORTED,  /* 49 */
127 VARTYPE_NOT_SUPPORTED,  /* 50 */
128 VARTYPE_NOT_SUPPORTED,  /* 51 */
129 VARTYPE_NOT_SUPPORTED,  /* 52 */
130 VARTYPE_NOT_SUPPORTED,  /* 53 */
131 VARTYPE_NOT_SUPPORTED,  /* 54 */
132 VARTYPE_NOT_SUPPORTED,  /* 55 */
133 VARTYPE_NOT_SUPPORTED,  /* 56 */
134 VARTYPE_NOT_SUPPORTED,  /* 57 */
135 VARTYPE_NOT_SUPPORTED,  /* 58 */
136 VARTYPE_NOT_SUPPORTED,  /* 59 */
137 VARTYPE_NOT_SUPPORTED,  /* 60 */
138 VARTYPE_NOT_SUPPORTED,  /* 61 */
139 VARTYPE_NOT_SUPPORTED,  /* 62 */
140 VARTYPE_NOT_SUPPORTED,  /* 63 */
141 VARTYPE_NOT_SUPPORTED,  /* VT_FILETIME       [P]    FILETIME                    */
142 VARTYPE_NOT_SUPPORTED,  /* VT_BLOB           [P]    Length prefixed bytes */
143 VARTYPE_NOT_SUPPORTED,  /* VT_STREAM         [P]    Name of stream follows              */
144 VARTYPE_NOT_SUPPORTED,  /* VT_STORAGE        [P]    Name of storage follows     */
145 VARTYPE_NOT_SUPPORTED,  /* VT_STREAMED_OBJECT[P]    Stream contains an object*/
146 VARTYPE_NOT_SUPPORTED,  /* VT_STORED_OBJECT  [P]    Storage contains object*/
147 VARTYPE_NOT_SUPPORTED,  /* VT_BLOB_OBJECT    [P]    Blob contains an object*/
148 VARTYPE_NOT_SUPPORTED,  /* VT_CF             [P]    Clipboard format                    */
149 VARTYPE_NOT_SUPPORTED,  /* VT_CLSID          [P]    A Class ID                  */
150 };
151
152 static const int LAST_VARTYPE = sizeof(VARTYPE_SIZE)/sizeof(VARTYPE_SIZE[0]);
153
154
155 /*************************************************************************
156  *              SafeArrayAllocDescriptor (OLEAUT32.36)
157  * Allocate the appropriate amount of memory for the SafeArray descriptor
158  */
159 HRESULT WINAPI SafeArrayAllocDescriptor(
160   UINT    cDims,
161   SAFEARRAY **ppsaOut)
162 {
163   SAFEARRAYBOUND *sab;
164   LONG allocSize = 0;
165   char *ptr;
166
167   if (!cDims || cDims >= 0x10000) /* 65536 appears to be the limit */
168     return E_INVALIDARG;
169   if (!ppsaOut)
170     return E_POINTER;
171
172   /* GUID + SAFEARRAY + SAFEARRAYBOUND * (cDims -1)
173    * ( -1 because there is already one ( in SAFEARRAY struct
174    */
175   allocSize = sizeof(GUID) + sizeof(**ppsaOut) + (sizeof(*sab) * (cDims-1));
176
177   /* Allocate memory for SAFEARRAY struc */
178   ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, allocSize);
179   if (!ptr)
180     return E_OUTOFMEMORY;
181   *ppsaOut = (SAFEARRAY *)(ptr + sizeof(GUID));
182   (*ppsaOut)->cDims     = cDims;
183   TRACE("(%d): %lu bytes allocated for descriptor.\n", cDims, allocSize);
184
185   return(S_OK);
186 }
187
188 /*************************************************************************
189  *              SafeArrayAllocDescriptorEx (OLEAUT32.41)
190  * Allocate the appropriate amount of memory for the SafeArray descriptor
191  * and also store information about the vartype before the returned pointer.
192  */
193 HRESULT WINAPI SafeArrayAllocDescriptorEx(
194   VARTYPE vt,
195   UINT    cDims,
196   SAFEARRAY **ppsaOut)
197 {
198   HRESULT hres;
199
200   hres = SafeArrayAllocDescriptor (cDims, ppsaOut);
201   if (FAILED(hres))
202     return hres;
203
204   switch (vt) {
205   case VT_DISPATCH:
206     (*ppsaOut)->fFeatures = FADF_HAVEIID;
207     SafeArraySetIID( *ppsaOut, &IID_IDispatch);
208     break;
209   case VT_UNKNOWN:
210     (*ppsaOut)->fFeatures = FADF_HAVEIID;
211     SafeArraySetIID( *ppsaOut, &IID_IUnknown);
212     break;
213   case VT_RECORD:
214     (*ppsaOut)->fFeatures = FADF_RECORD;
215     break;
216   default:
217     (*ppsaOut)->fFeatures = FADF_HAVEVARTYPE;
218     ((DWORD*)*ppsaOut)[-1] = vt;
219     break;
220   }
221   return S_OK;
222 }
223
224 /*************************************************************************
225  *              SafeArrayAllocData (OLEAUT32.37)
226  * Allocate the appropriate amount of data for the SafeArray data
227  */
228 HRESULT WINAPI SafeArrayAllocData(
229   SAFEARRAY *psa)
230 {
231   ULONG  ulWholeArraySize;   /* to store the size of the whole thing */
232
233   if(! validArg(psa))
234     return E_INVALIDARG;
235
236   ulWholeArraySize = getArraySize(psa);
237
238   /* Allocate memory for the data itself */
239   if((psa->pvData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
240         psa->cbElements*ulWholeArraySize)) == NULL)
241     return(E_UNEXPECTED);
242
243   TRACE("SafeArray: %lu bytes allocated for data at %p (%lu objects).\n",
244     psa->cbElements*ulWholeArraySize, psa->pvData, ulWholeArraySize);
245
246   return(S_OK);
247 }
248
249 /*************************************************************************
250  *              SafeArrayCreate (OLEAUT32.15)
251  * Create a SafeArray object by encapsulating AllocDescriptor and AllocData
252  */
253 SAFEARRAY* WINAPI SafeArrayCreate(
254   VARTYPE        vt,
255   UINT         cDims,
256   SAFEARRAYBOUND *rgsabound)
257 {
258   SAFEARRAY *psa;
259   HRESULT   hRes;
260   USHORT    cDim;
261
262   TRACE("(%d, %d, %p)\n", vt, cDims, rgsabound);
263
264   /* Validate supported VARTYPE */
265   if ( (vt >= LAST_VARTYPE) ||
266        ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
267     return NULL;
268
269   /* Allocate memory for the array descriptor */
270   if( FAILED( hRes = SafeArrayAllocDescriptorEx(vt, cDims, &psa)))
271     return NULL;
272
273   /* setup data members... */
274   psa->cDims     = cDims;
275   switch (vt) {
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   default: break;
281   }
282   psa->cLocks    = 0;
283   psa->pvData    = NULL;
284   psa->cbElements= VARTYPE_SIZE[vt];
285
286   /* Invert the bounds ... */
287   for(cDim=0; cDim < psa->cDims; cDim++) {
288     psa->rgsabound[cDim].cElements = rgsabound[psa->cDims-cDim-1].cElements;
289     psa->rgsabound[cDim].lLbound   = rgsabound[psa->cDims-cDim-1].lLbound;
290   }
291
292   /* allocate memory for the data... */
293   if( FAILED( hRes = SafeArrayAllocData(psa))) {
294     SafeArrayDestroyDescriptor(psa);
295     ERR("() : Failed to allocate the Safe Array data\n");
296     return NULL;
297   }
298
299   return(psa);
300 }
301
302 /*************************************************************************
303  *              SafeArrayDestroyDescriptor (OLEAUT32.38)
304  * Frees the memory associated with the descriptor.
305  */
306 HRESULT WINAPI SafeArrayDestroyDescriptor(
307   SAFEARRAY *psa)
308 {
309   LPVOID ptr;
310
311   /* Check for lockness before to free... */
312   if(psa->cLocks > 0)
313     return DISP_E_ARRAYISLOCKED;
314
315   /* The array is unlocked, then, deallocate memory */
316   ptr = ((IID*)psa)-1;
317   if(HeapFree( GetProcessHeap(), 0, ptr) == FALSE)
318     return E_UNEXPECTED;
319   return(S_OK);
320 }
321
322
323 /*************************************************************************
324  *              SafeArrayLock (OLEAUT32.21)
325  * Increment the lock counter
326  *
327  * Doc says (MSDN Library ) that psa->pvData should be made available (!= NULL)
328  * only when psa->cLocks is > 0... I don't get it since pvData is allocated
329  * before the array is locked, therefore
330  */
331 HRESULT WINAPI SafeArrayLock(
332   SAFEARRAY *psa)
333 {
334   if(! validArg(psa))
335     return E_INVALIDARG;
336
337   psa->cLocks++;
338
339   return(S_OK);
340 }
341
342 /*************************************************************************
343  *              SafeArrayUnlock (OLEAUT32.22)
344  * Decrement the lock counter
345  */
346 HRESULT WINAPI SafeArrayUnlock(
347   SAFEARRAY *psa)
348 {
349   if(! validArg(psa))
350     return E_INVALIDARG;
351
352   if (psa->cLocks > 0)
353     psa->cLocks--;
354
355   return(S_OK);
356 }
357
358
359 /*************************************************************************
360  *              SafeArrayPutElement (OLEAUT32.26)
361  * Set the data at the given coordinate
362  */
363 HRESULT WINAPI SafeArrayPutElement(
364   SAFEARRAY *psa,
365   LONG      *rgIndices,
366   void      *pv)
367 {
368   ULONG stepCountInSAData     = 0;    /* Number of array item to skip to get to
369                                          the desired one... */
370   PVOID elementStorageAddress = NULL; /* Address to store the data */
371
372   /* Validate the index given */
373   if(! validCoordinate(rgIndices, psa))
374     return DISP_E_BADINDEX;
375   if(! validArg(psa))
376     return E_INVALIDARG;
377
378   if( SafeArrayLock(psa) == S_OK) {
379
380     /* Figure out the number of items to skip */
381     stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
382
383     /* Figure out the number of byte to skip ... */
384     elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
385
386     if(isPointer(psa->fFeatures)) { /* increment ref count for this pointer */
387
388       *((PVOID*)elementStorageAddress) = *(PVOID*)pv;
389       IUnknown_AddRef( *(IUnknown**)pv);
390
391     } else {
392
393       if(psa->fFeatures & FADF_BSTR) { /* Create a new object */
394         BSTR pbstrReAllocStr = NULL;
395         if(pv &&
396            ((pbstrReAllocStr = SYSDUPSTRING( (OLECHAR*)pv )) == NULL)) {
397           SafeArrayUnlock(psa);
398           return E_OUTOFMEMORY;
399         } else
400           *((BSTR*)elementStorageAddress) = pbstrReAllocStr;
401       }
402       else if(psa->fFeatures & FADF_VARIANT) {
403         HRESULT hr = VariantCopy(elementStorageAddress, pv);
404         if (FAILED(hr)) {
405           SafeArrayUnlock(psa);
406           return hr;
407         }
408       }
409       else /* duplicate the memory */
410         memcpy(elementStorageAddress, pv, SafeArrayGetElemsize(psa) );
411     }
412
413   } else {
414     ERR("SafeArray: Cannot lock array....\n");
415     return E_UNEXPECTED; /* UNDOC error condition */
416   }
417
418   TRACE("SafeArray: item put at address %p.\n",elementStorageAddress);
419   return SafeArrayUnlock(psa);
420 }
421
422
423 /*************************************************************************
424  *              SafeArrayGetElement (OLEAUT32.25)
425  * Return the data element corresponding the the given coordinate
426  */
427 HRESULT WINAPI SafeArrayGetElement(
428   SAFEARRAY *psa,
429   LONG      *rgIndices,
430   void      *pv)
431 {
432   ULONG stepCountInSAData     = 0;    /* Number of array item to skip to get to
433                                          the desired one... */
434   PVOID elementStorageAddress = NULL; /* Address to store the data */
435
436   if(! validArg(psa))
437     return E_INVALIDARG;
438
439   if(! validCoordinate(rgIndices, psa)) /* Validate the index given */
440     return(DISP_E_BADINDEX);
441
442   if( SafeArrayLock(psa) == S_OK) {
443
444     /* Figure out the number of items to skip */
445     stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
446
447     /* Figure out the number of byte to skip ... */
448     elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
449
450     if( psa->fFeatures & FADF_BSTR) {           /* reallocate the obj */
451       BSTR pbstrStoredStr = *(OLECHAR**)elementStorageAddress;
452       BSTR pbstrReturnedStr = NULL;
453       if( pbstrStoredStr &&
454           ((pbstrReturnedStr = SYSDUPSTRING( pbstrStoredStr )) == NULL) ) {
455         SafeArrayUnlock(psa);
456         return E_OUTOFMEMORY;
457       } else
458         *((BSTR*)pv) = pbstrReturnedStr;
459     }
460     else if( psa->fFeatures & FADF_VARIANT) {
461       HRESULT hr;
462       VariantInit(pv);
463       hr = VariantCopy(pv, elementStorageAddress);
464       if (FAILED(hr)) {
465         SafeArrayUnlock(psa);
466         return hr;
467       }
468     }
469     else if( isPointer(psa->fFeatures) )         /* simply copy the pointer */
470       *(PVOID*)pv = *((PVOID*)elementStorageAddress);
471     else                                         /* copy the bytes */
472       memcpy(pv, elementStorageAddress, psa->cbElements );
473
474   } else {
475     ERR("SafeArray: Cannot lock array....\n");
476     return E_UNEXPECTED; /* UNDOC error condition */
477   }
478
479   return( SafeArrayUnlock(psa) );
480 }
481
482 /*************************************************************************
483  *              SafeArrayGetUBound (OLEAUT32.19)
484  * return the UP bound for a given array dimension
485  * Note: [0] is the right most (least significant) array index!
486  */
487 HRESULT WINAPI SafeArrayGetUBound(
488   SAFEARRAY *psa,
489   UINT    nDim,
490   LONG      *plUbound)
491 {
492   if(! validArg(psa))
493     return E_INVALIDARG;
494
495   if(nDim > psa->cDims)
496     return DISP_E_BADINDEX;
497
498   if(0 == nDim)
499     return DISP_E_BADINDEX;
500
501   *plUbound = psa->rgsabound[psa->cDims - nDim].lLbound +
502               psa->rgsabound[psa->cDims - nDim].cElements - 1;
503
504   return S_OK;
505 }
506
507 /*************************************************************************
508  *              SafeArrayGetLBound (OLEAUT32.20)
509  * Return the LO bound for a given array dimension
510  * Note: [0] is the right most (least significant) array index!
511  */
512 HRESULT WINAPI SafeArrayGetLBound(
513   SAFEARRAY *psa,
514   UINT    nDim,
515   LONG      *plLbound)
516 {
517   if(! validArg(psa))
518     return E_INVALIDARG;
519
520   if(nDim > psa->cDims)
521     return DISP_E_BADINDEX;
522
523   if(0 == nDim)
524     return DISP_E_BADINDEX;
525
526   *plLbound = psa->rgsabound[psa->cDims - nDim].lLbound;
527   return S_OK;
528 }
529
530 /*************************************************************************
531  *              SafeArrayGetDim (OLEAUT32.17)
532  * returns the number of dimension in the array
533  */
534 UINT WINAPI SafeArrayGetDim(
535   SAFEARRAY * psa)
536 {
537   /*
538    * A quick test in Windows shows that the behavior here for an invalid
539    * pointer is to return 0.
540    */
541   if(! validArg(psa))
542     return 0;
543
544   return psa->cDims;
545 }
546
547 /*************************************************************************
548  *              SafeArrayGetElemsize (OLEAUT32.18)
549  * Return the size of the element in the array
550  */
551 UINT WINAPI SafeArrayGetElemsize(
552   SAFEARRAY * psa)
553 {
554   /*
555    * A quick test in Windows shows that the behavior here for an invalid
556    * pointer is to return 0.
557    */
558   if(! validArg(psa))
559     return 0;
560
561   return psa->cbElements;
562 }
563
564 /*************************************************************************
565  *              SafeArrayAccessData (OLEAUT32.23)
566  * increment the access count and return the data
567  */
568 HRESULT WINAPI SafeArrayAccessData(
569   SAFEARRAY *psa,
570   void      **ppvData)
571 {
572   HRESULT hRes;
573
574   if(! validArg(psa))
575     return E_INVALIDARG;
576
577   hRes = SafeArrayLock(psa);
578
579   switch (hRes) {
580     case S_OK:
581       (*ppvData) = psa->pvData;
582       break;
583     case E_INVALIDARG:
584       (*ppvData) = NULL;
585       return E_INVALIDARG;
586   }
587
588   return S_OK;
589 }
590
591
592 /*************************************************************************
593  *              SafeArrayUnaccessData (OLEAUT32.24)
594  * Decrement the access count
595  */
596 HRESULT WINAPI SafeArrayUnaccessData(
597   SAFEARRAY * psa)
598 {
599   if(! validArg(psa))
600     return E_INVALIDARG;
601
602   return(SafeArrayUnlock(psa));
603 }
604
605 /************************************************************************
606  *              SafeArrayPtrOfIndex (OLEAUT32.148)
607  * Return a pointer to the element at rgIndices
608  */
609 HRESULT WINAPI SafeArrayPtrOfIndex(
610   SAFEARRAY *psa,
611   LONG      *rgIndices,
612   void      **ppvData)
613 {
614   ULONG stepCountInSAData     = 0;    /* Number of array item to skip to get to
615                                          the desired one... */
616
617   if(! validArg(psa))
618     return E_INVALIDARG;
619
620   if(! validCoordinate(rgIndices, psa))
621     return DISP_E_BADINDEX;
622
623   /* Although it is dangerous to do this without having a lock, it is not
624    * illegal.  Microsoft do warn of the danger.
625    */
626
627   /* Figure out the number of items to skip */
628   stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
629
630   *ppvData = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
631
632   return S_OK;
633 }
634
635 /************************************************************************
636  *              SafeArrayDestroyData (OLEAUT32.39)
637  * Frees the memory data bloc
638  */
639 HRESULT WINAPI SafeArrayDestroyData(
640   SAFEARRAY *psa)
641 {
642   HRESULT  hRes;
643   ULONG    ulWholeArraySize; /* count spot in array  */
644   ULONG    ulDataIter;       /* to iterate the data space */
645
646   if(! validArg(psa))
647     return E_INVALIDARG;
648
649   if(psa->cLocks > 0)
650     return DISP_E_ARRAYISLOCKED;
651
652   if(psa->pvData==NULL)
653     return S_OK;
654
655   ulWholeArraySize = getArraySize(psa);
656
657   if(isPointer(psa->fFeatures)) {           /* release the pointers */
658     IUnknown *punk;
659
660     for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
661       punk = *(IUnknown**)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
662
663       if( punk != NULL)
664         IUnknown_Release(punk);
665     }
666
667   }
668   else if(psa->fFeatures & FADF_BSTR) {  /* deallocate the obj */
669     BSTR bstr;
670
671     for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
672       bstr = *(BSTR*)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
673
674       if( bstr != NULL)
675         SysFreeString( bstr );
676     }
677   }
678   else if(psa->fFeatures & FADF_VARIANT) {  /* deallocate the obj */
679
680     for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
681       VariantClear((VARIANT*)((char *) psa->pvData+(ulDataIter*(psa->cbElements))));
682     }
683   }
684
685   /* check if this array is a Vector, in which case do not free the data
686      block since it has been allocated by AllocDescriptor and therefore
687      deserve to be freed by DestroyDescriptor */
688   if(!(psa->fFeatures & FADF_CREATEVECTOR)) { /* Set when we do CreateVector */
689
690     /* free the whole chunk */
691     if((hRes = HeapFree( GetProcessHeap(), 0, psa->pvData)) == 0) /*failed*/
692       return E_UNEXPECTED; /* UNDOC error condition */
693
694     psa->pvData = NULL;
695   }
696
697   return S_OK;
698 }
699
700 /************************************************************************
701  *              SafeArrayCopyData (OLEAUT32.412)
702  * Copy the psaSource's data block into psaTarget if dimension and size
703  * permits it.
704  */
705 HRESULT WINAPI SafeArrayCopyData(
706   SAFEARRAY *psaSource,
707   SAFEARRAY *psaTarget)
708 {
709   USHORT   cDimCount;        /* looper */
710   LONG     lDelta;           /* looper */
711   IUnknown *punk;
712   ULONG    ulWholeArraySize; /* Number of item in SA */
713   BSTR   bstr;
714
715   if(! (validArg(psaSource) && validArg(psaTarget)) )
716     return E_INVALIDARG;
717
718   if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(psaTarget))
719     return E_INVALIDARG;
720
721   ulWholeArraySize = getArraySize(psaSource);
722
723   /* The two arrays boundaries must be of same lenght */
724   for(cDimCount=0;cDimCount < psaSource->cDims; cDimCount++)
725     if( psaSource->rgsabound[cDimCount].cElements !=
726       psaTarget->rgsabound[cDimCount].cElements)
727       return E_INVALIDARG;
728
729   if( isPointer(psaTarget->fFeatures) ) {         /* the target contains ptr
730                                                      that must be released */
731     for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
732       punk = *(IUnknown**)
733         ((char *) psaTarget->pvData + (lDelta * psaTarget->cbElements));
734
735       if( punk != NULL)
736         IUnknown_Release(punk);
737     }
738
739   }
740   else if( psaTarget->fFeatures & FADF_BSTR) {    /* the target contain BSTR
741                                                         that must be freed */
742     for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
743       bstr =
744         *(BSTR*)((char *) psaTarget->pvData + (lDelta * psaTarget->cbElements));
745
746       if( bstr != NULL)
747         SysFreeString( bstr );
748     }
749   }
750   else if( psaTarget->fFeatures & FADF_VARIANT) {
751
752     for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
753       VariantClear((VARIANT*)((char *) psaTarget->pvData + (lDelta * psaTarget->cbElements)));
754     }
755   }
756
757   return duplicateData(psaSource, psaTarget);
758 }
759
760 /************************************************************************
761  *              SafeArrayDestroy (OLEAUT32.16)
762  * Deallocates all memory reserved for the SafeArray
763  */
764 HRESULT WINAPI SafeArrayDestroy(
765   SAFEARRAY * psa)
766 {
767   HRESULT hRes;
768
769   if(! validArg(psa))
770     return E_INVALIDARG;
771
772   if(psa->cLocks > 0)
773     return DISP_E_ARRAYISLOCKED;
774
775   if((hRes = SafeArrayDestroyData( psa )) == S_OK)
776     if((hRes = SafeArrayDestroyDescriptor( psa )) == S_OK)
777       return S_OK;
778
779   return E_UNEXPECTED; /* UNDOC error condition */
780 }
781
782 /************************************************************************
783  *              SafeArrayCopy (OLEAUT32.27)
784  * Make a dupplicate of a SafeArray
785  */
786 HRESULT WINAPI SafeArrayCopy(
787   SAFEARRAY *psa,
788   SAFEARRAY **ppsaOut)
789 {
790   HRESULT hRes;
791   DWORD   dAllocSize;
792   ULONG   ulWholeArraySize; /* size of the thing */
793
794   if(! validArg(psa))
795     return E_INVALIDARG;
796
797   if((hRes=SafeArrayAllocDescriptor(psa->cDims, ppsaOut)) == S_OK){
798
799     /* Duplicate the SAFEARRAY struct */
800     memcpy(*ppsaOut, psa,
801             sizeof(*psa)+(sizeof(*(psa->rgsabound))*(psa->cDims-1)));
802
803     /* If the features that use storage before the SAFEARRAY struct are
804      * enabled, also copy this memory range. Flags have been copied already.
805      */
806     if (psa->fFeatures & (FADF_HAVEIID | FADF_HAVEVARTYPE))
807       memcpy(((GUID*)*ppsaOut)-1, ((GUID*)psa)-1, sizeof(GUID));
808
809     /* Copy the IRecordInfo* reference */
810     if (psa->fFeatures & FADF_RECORD) {
811       IRecordInfo *ri;
812
813       ri = ((IRecordInfo**)psa)[-1];
814       if (ri) {
815         ((IRecordInfo**)*ppsaOut)[-1] = ri;
816         IRecordInfo_AddRef(ri);
817       }
818     }
819
820     (*ppsaOut)->pvData = NULL; /* do not point to the same data area */
821
822     /* make sure the new safe array doesn't have the FADF_CREATEVECTOR flag,
823        because the data has not been allocated with the descriptor. */
824     (*ppsaOut)->fFeatures &= ~FADF_CREATEVECTOR;
825
826     /* Get the allocated memory size for source and allocate it for target */
827     ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
828     dAllocSize = ulWholeArraySize*psa->cbElements;
829
830     (*ppsaOut)->pvData =
831       HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dAllocSize);
832     if( (*ppsaOut)->pvData != NULL) {   /* HeapAlloc succeed */
833
834       if( (hRes=duplicateData(psa, *ppsaOut)) != S_OK) { /* E_OUTOFMEMORY */
835         HeapFree(GetProcessHeap(), 0, (*ppsaOut)->pvData);
836         (*ppsaOut)->pvData = NULL;
837         SafeArrayDestroyDescriptor(*ppsaOut);
838         return hRes;
839       }
840
841     } else { /* failed to allocate or dupplicate... */
842       SafeArrayDestroyDescriptor(*ppsaOut);
843       return E_UNEXPECTED; /* UNDOC error condition */
844     }
845   } else { /* failed to allocate mem for descriptor */
846     return E_OUTOFMEMORY; /* UNDOC error condiftion */
847   }
848
849   return S_OK;
850 }
851
852 /************************************************************************
853  *              SafeArrayCreateVector (OLEAUT32.411)
854  * Creates a one dimension safearray where the data is next to the
855  * SAFEARRAY structure.
856  */
857 SAFEARRAY* WINAPI SafeArrayCreateVector(
858   VARTYPE vt,
859   LONG    lLbound,
860   ULONG   cElements)
861 {
862   SAFEARRAY *psa;
863   BYTE *ptr;
864
865   TRACE("%d, %ld, %ld\n", vt, lLbound, cElements);
866
867   /* Validate supported VARTYPE */
868   if ( (vt >= LAST_VARTYPE) ||
869        ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
870     return NULL;
871
872   /* Allocate memory for the array descriptor and data contiguously  */
873   ptr = HeapAlloc( GetProcessHeap(),
874                       HEAP_ZERO_MEMORY,
875                       (sizeof(GUID)+sizeof(*psa)+(VARTYPE_SIZE[vt]*cElements)));
876   if (!ptr)
877     return NULL;
878   psa = (SAFEARRAY*)(ptr+sizeof(GUID));
879
880   /* setup data members... */
881   psa->cDims      = 1; /* always and forever */
882   psa->fFeatures  = getFeatures(vt) | FADF_CREATEVECTOR;  /* undocumented flag used by Microsoft */
883   psa->cLocks     = 0;
884   psa->pvData     = (BYTE*)psa + sizeof(*psa);
885   psa->cbElements = VARTYPE_SIZE[vt];
886
887   psa->rgsabound[0].cElements = cElements;
888   psa->rgsabound[0].lLbound   = lLbound;
889
890   return(psa);
891 }
892
893 /************************************************************************
894  *              SafeArrayRedim (OLEAUT32.40)
895  * Changes the caracteristics of the last dimension of the SafeArray
896  */
897 HRESULT WINAPI SafeArrayRedim(
898   SAFEARRAY      *psa,
899   SAFEARRAYBOUND *psaboundNew)
900 {
901   LONG   lDelta;  /* hold difference in size */
902   USHORT cDims=1; /* dims counter */
903
904   if( !validArg(psa) )
905     return E_INVALIDARG;
906
907   if( psa->cLocks > 0 )
908     return DISP_E_ARRAYISLOCKED;
909
910   if( psa->fFeatures & FADF_FIXEDSIZE )
911     return E_INVALIDARG;
912
913   if( SafeArrayLock(psa)==E_UNEXPECTED )
914     return E_UNEXPECTED;/* UNDOC error condition */
915
916   /* find the delta in number of array spot to apply to the new array */
917   lDelta = psaboundNew->cElements - psa->rgsabound[0].cElements;
918   for(; cDims < psa->cDims; cDims++)
919     /* delta in number of spot implied by modifying the last dimension */
920     lDelta *= psa->rgsabound[cDims].cElements;
921
922   TRACE("elements=%ld, Lbound=%ld (delta=%ld)\n", psaboundNew->cElements, psaboundNew->lLbound, lDelta);
923
924   if (lDelta == 0) { ;/* same size, maybe a change of lLbound, just set it */
925
926   } else /* need to enlarge (lDelta +) reduce (lDelta -) */
927     if(! resizeSafeArray(psa, lDelta))
928       return E_UNEXPECTED; /* UNDOC error condition */
929
930   /* the only modifyable dimension sits in [0] as the dimensions were reversed
931      at array creation time... */
932   psa->rgsabound[0].cElements = psaboundNew->cElements;
933   psa->rgsabound[0].lLbound   = psaboundNew->lLbound;
934
935   return SafeArrayUnlock(psa);
936 }
937
938 /************************************************************************
939  * NOT WINDOWS API - SafeArray* Utility functions
940  ************************************************************************/
941
942 /************************************************************************
943  * Used to validate the SAFEARRAY type of arg
944  */
945 static BOOL validArg(
946   SAFEARRAY *psa)
947 {
948   SAFEARRAYBOUND *sab;
949   LONG psaSize  = 0;
950   LONG descSize = 0;
951   LONG fullSize = 0;
952
953   /*
954    * Let's check for the null pointer just in case.
955    */
956   if (psa == NULL)
957     return FALSE;
958
959   /* Check whether the size of the chunk makes sense... That's the only thing
960      I can think of now... */
961
962   psaSize = HeapSize(GetProcessHeap(), 0, ((IID*)psa)-1);
963   if (psaSize == -1)
964     /* uh, foreign heap. Better don't mess with it ! */
965     return TRUE;
966
967   /* size of the descriptor when the SA is not created with CreateVector */
968   descSize = sizeof(GUID) + sizeof(*psa) + (sizeof(*sab) * (psa->cDims-1));
969
970   /* size of the descriptor + data when created with CreateVector */
971   fullSize = sizeof(*psa) + (psa->cbElements * psa->rgsabound[0].cElements);
972
973   return((psaSize >= descSize) || (psaSize >= fullSize));
974 }
975
976 /************************************************************************
977  * Used to reallocate memory
978  */
979 static BOOL resizeSafeArray(
980   SAFEARRAY *psa,
981   LONG lDelta)
982 {
983   ULONG    ulWholeArraySize;  /* use as multiplicator */
984   PVOID    pvNewBlock = NULL;
985   IUnknown *punk;
986   BSTR   bstr;
987
988   ulWholeArraySize = getArraySize(psa);
989
990   if(lDelta < 0) {                    /* array needs to be shorthen  */
991     if( isPointer(psa->fFeatures))    /* ptr that need to be released */
992       for(;lDelta < 0; lDelta++) {
993               punk = *(IUnknown**)
994           ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
995
996         if( punk != NULL )
997           IUnknown_Release(punk);
998             }
999
1000     else if(psa->fFeatures & FADF_BSTR)  /* BSTR that need to be freed */
1001       for(;lDelta < 0; lDelta++) {
1002         bstr = *(BSTR*)
1003           ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
1004
1005         if( bstr != NULL )
1006           SysFreeString( bstr );
1007       }
1008     else if(psa->fFeatures & FADF_VARIANT)
1009       for(;lDelta < 0; lDelta++) {
1010         VariantClear((VARIANT*)((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements)));
1011       }
1012   }
1013
1014   if (!(psa->fFeatures & FADF_CREATEVECTOR))
1015   {
1016     /* Ok now, if we are enlarging the array, we *MUST* move the whole block
1017        pointed to by pvData.   If we are shorthening the array, this move is
1018        optional but we do it anyway becuase the benefit is that we are
1019        releasing to the system the unused memory */
1020
1021     if((pvNewBlock = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, psa->pvData,
1022        (ulWholeArraySize + lDelta) * psa->cbElements)) == NULL)
1023         return FALSE; /* TODO If we get here it means:
1024                          SHRINK situation :  we've deleted the undesired
1025                                              data and did not release the memory
1026                          GROWING situation:  we've been unable to grow the array
1027                       */
1028   }
1029   else
1030   {
1031     /* Allocate a new block, because the previous data has been allocated with
1032        the descriptor in SafeArrayCreateVector function. */
1033
1034     if((pvNewBlock = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1035        ulWholeArraySize * psa->cbElements)) == NULL)
1036         return FALSE;
1037
1038     psa->fFeatures &= ~FADF_CREATEVECTOR;
1039   }
1040   /* reassign to the new block of data */
1041   psa->pvData = pvNewBlock;
1042   return TRUE;
1043 }
1044
1045 /************************************************************************
1046  * Used to set the fFeatures data member of the SAFEARRAY structure.
1047  */
1048 static INT getFeatures(VARTYPE vt) {
1049   switch (vt) {
1050   case VT_BSTR:      return FADF_BSTR;
1051   case VT_UNKNOWN:   return FADF_UNKNOWN;
1052   case VT_DISPATCH:  return FADF_DISPATCH;
1053   case VT_VARIANT:   return FADF_VARIANT;
1054   }
1055   return 0;
1056 }
1057
1058 /************************************************************************
1059  * Used to figure out if the fFeatures data member of the SAFEARRAY
1060  * structure contain any information about the type of data stored...
1061  */
1062 static BOOL isPointer(
1063   USHORT feature)
1064 {
1065   switch(feature) {
1066     case FADF_UNKNOWN:  return TRUE; /* those are pointers */
1067     case FADF_DISPATCH: return TRUE;
1068   }
1069   return FALSE;
1070 }
1071
1072 /************************************************************************
1073  * Used to calculate the displacement when accessing or modifying
1074  * safearray data set.
1075  *
1076  *  Parameters: - LONG *coor is the desired location in the multidimension
1077  *              table.  Ex for a 3 dim table: coor[] = {1,2,3};
1078  *              - ULONG *mat is the format of the table.  Ex for a 3 dim
1079  *              table mat[] = {4,4,4};
1080  *              - USHORT dim is the number of dimension of the SafeArray
1081  */
1082 static ULONG calcDisplacement(
1083   LONG           *coor,
1084   SAFEARRAYBOUND *mat,
1085   LONG           dim)
1086 {
1087   ULONG res = 0;
1088   LONG  iterDim;
1089
1090   TRACE("dims is %ld\n", dim);
1091
1092   for (iterDim = dim-1; iterDim >= 0; iterDim--) {
1093         TRACE("%ld: lbound is %ld, adding %ld\n", iterDim, mat[dim-iterDim-1].lLbound,(coor[iterDim] - mat[dim-iterDim-1].lLbound));
1094         res += (coor[iterDim] - mat[dim-iterDim-1].lLbound);
1095
1096         if (iterDim > 0)
1097                 res *= mat[dim-iterDim].cElements;
1098   }
1099
1100   TRACE("SafeArray: calculated displacement is %lu.\n", res);
1101   return(res);
1102 }
1103
1104 /************************************************************************
1105  * Method used to validate the coordinate received in Put and Get
1106  * methods.
1107  */
1108 static BOOL validCoordinate(
1109   LONG      *coor,
1110   SAFEARRAY *psa)
1111 {
1112   INT   iter=0;
1113   LONG    lUBound;
1114   LONG    lLBound;
1115   HRESULT hRes;
1116
1117   if (!psa->cDims) { FIXME("no dims?\n");return FALSE; }
1118   for(; iter<psa->cDims; iter++) {
1119     TRACE("coor[%d]=%ld\n", iter, coor[iter]);
1120     if((hRes = SafeArrayGetLBound(psa, (iter+1), &lLBound)) != S_OK) {
1121       FIXME("No lbound?\n");
1122       return FALSE;
1123     }
1124     if((hRes = SafeArrayGetUBound(psa, (iter+1), &lUBound)) != S_OK) {
1125       FIXME("No ubound?\n");
1126       return FALSE;
1127     }
1128     if(lLBound > lUBound) {
1129       FIXME("lbound larger than ubound?\n");
1130       return FALSE;
1131     }
1132
1133     if((coor[iter] < lLBound) || (coor[iter] > lUBound)) {
1134       FIXME("coordinate %ld not within %ld - %ld\n",coor[iter], lLBound, lUBound);
1135       return FALSE;
1136     }
1137   }
1138   return TRUE;
1139 }
1140
1141 /************************************************************************
1142  * Method used to calculate the number of cells of the SA
1143  */
1144 static ULONG getArraySize(
1145   SAFEARRAY *psa)
1146 {
1147   USHORT cCount;
1148   ULONG  ulWholeArraySize = 1;
1149
1150   for(cCount=0; cCount < psa->cDims; cCount++) /* foreach dimensions... */
1151     ulWholeArraySize *= psa->rgsabound[cCount].cElements;
1152
1153   return ulWholeArraySize;
1154 }
1155
1156
1157 /************************************************************************
1158  * Method used to handle data space dupplication for Copy32 and CopyData32
1159  */
1160 static HRESULT duplicateData(
1161   SAFEARRAY *psa,
1162   SAFEARRAY *ppsaOut)
1163 {
1164   ULONG    ulWholeArraySize; /* size of the thing */
1165   LONG     lDelta;
1166
1167   ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
1168
1169   SafeArrayLock(ppsaOut);
1170
1171   if( isPointer(psa->fFeatures) ) {  /* If datatype is object increment
1172                                         object's reference count */
1173     IUnknown *punk;
1174
1175     for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1176       punk = *(IUnknown**)((char *) psa->pvData+(lDelta * psa->cbElements));
1177
1178       if( punk != NULL)
1179         IUnknown_AddRef(punk);
1180     }
1181
1182     /* Copy the source array data into target array */
1183     memcpy(ppsaOut->pvData, psa->pvData, ulWholeArraySize*psa->cbElements);
1184
1185   }
1186   else if( psa->fFeatures & FADF_BSTR ) { /* if datatype is BSTR allocate
1187                                              the BSTR in the new array */
1188     BSTR   pbstrReAllocStr = NULL;
1189
1190     for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1191       if(( pbstrReAllocStr = SYSDUPSTRING(
1192             *(BSTR*)((char *) psa->pvData+(lDelta * psa->cbElements)))) == NULL) {
1193
1194         SafeArrayUnlock(ppsaOut);
1195         return E_OUTOFMEMORY;
1196       }
1197
1198       *((BSTR*)((char *)ppsaOut->pvData+(lDelta * psa->cbElements))) =
1199         pbstrReAllocStr;
1200     }
1201
1202   }
1203   else if( psa->fFeatures & FADF_VARIANT ) {
1204
1205     for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1206       VariantCopy((VARIANT*)((char *) ppsaOut->pvData+(lDelta * psa->cbElements)),
1207                   (VARIANT*)((char *) psa->pvData+(lDelta * psa->cbElements)));
1208     }
1209
1210   } else { /* Simply copy the source array data into target array */
1211     memcpy(ppsaOut->pvData, psa->pvData, ulWholeArraySize*psa->cbElements);
1212   }
1213   SafeArrayUnlock(ppsaOut);
1214   return S_OK;
1215 }
1216
1217
1218 /************************************************************************
1219  *              SafeArrayGetVartype (OLEAUT32.77)
1220  * Returns the VARTYPE stored in the given safearray
1221  */
1222 HRESULT WINAPI SafeArrayGetVartype(
1223   SAFEARRAY* psa,
1224   VARTYPE*   pvt)
1225 {
1226   if (psa->fFeatures & FADF_HAVEVARTYPE)
1227   {
1228     /* VT tag @ negative offset 4 in the array descriptor */
1229     *pvt = ((DWORD*)psa)[-1];
1230     return S_OK;
1231   }
1232
1233   if (psa->fFeatures & FADF_RECORD)
1234   {
1235     *pvt = VT_RECORD;
1236     return S_OK;
1237   }
1238
1239   if (psa->fFeatures & FADF_BSTR)
1240   {
1241     *pvt = VT_BSTR;
1242     return S_OK;
1243   }
1244
1245   if (psa->fFeatures & FADF_UNKNOWN)
1246   {
1247     *pvt = VT_UNKNOWN;
1248     return S_OK;
1249   }
1250
1251   if (psa->fFeatures & FADF_DISPATCH)
1252   {
1253     *pvt = VT_UNKNOWN; /* Yes, checked against windows */
1254     return S_OK;
1255   }
1256
1257   if (psa->fFeatures & FADF_VARIANT)
1258   {
1259     *pvt = VT_VARIANT;
1260     return S_OK;
1261   }
1262   if (psa->fFeatures & FADF_HAVEIID)
1263   {
1264     /* We could check the IID here, but Windows apparently does not
1265      * do that and returns VT_UNKNOWN for VT_DISPATCH too.
1266      */
1267     *pvt = VT_UNKNOWN;
1268     return S_OK;
1269   }
1270
1271   WARN("No vt found for safearray\n");
1272   return E_INVALIDARG;
1273 }
1274
1275 /************************************************************************
1276  *              SafeArraySetIID (OLEAUT32.57)
1277  */
1278 HRESULT WINAPI SafeArraySetIID(SAFEARRAY *arr, REFIID riid) {
1279   IID *xiid = ((IID*)arr)-1;
1280   TRACE("(%p, %s).\n",arr,debugstr_guid(riid));
1281
1282   if (!arr || !(arr->fFeatures & FADF_HAVEIID))
1283     return E_INVALIDARG;
1284   memcpy(xiid, riid, sizeof(GUID));
1285   return S_OK;
1286 }
1287
1288 /************************************************************************
1289  *              SafeArrayGetIID (OLEAUT32.67)
1290  */
1291 HRESULT WINAPI SafeArrayGetIID(SAFEARRAY *arr, IID *riid) {
1292   IID *xiid = ((IID*)arr)-1;
1293   TRACE("(%p, %s).\n",arr,debugstr_guid(riid));
1294
1295   if (!arr || !(arr->fFeatures & FADF_HAVEIID))
1296     return E_INVALIDARG;
1297   memcpy(riid, xiid, sizeof(GUID));
1298   return S_OK;
1299 }
1300
1301 /************************************************************************
1302  *              SafeArraySetRecordInfo (OLEAUT32.44)
1303  */
1304 HRESULT WINAPI SafeArraySetRecordInfo(SAFEARRAY *arr, IRecordInfo *iface) {
1305   LPRECORDINFO oldiface;
1306
1307   if (!arr || !(arr->fFeatures & FADF_RECORD))
1308     return E_INVALIDARG;
1309   oldiface = ((IRecordInfo**)arr)[-1];
1310   if (oldiface)
1311     IRecordInfo_Release(oldiface);
1312   ((IRecordInfo**)arr)[-1] = iface;
1313   if (iface)
1314     IRecordInfo_AddRef(iface);
1315   return S_OK;
1316 }
1317
1318 /************************************************************************
1319  *              SafeArrayGetRecordInfo (OLEAUT32.45)
1320  */
1321 HRESULT WINAPI SafeArrayGetRecordInfo(SAFEARRAY *arr, IRecordInfo** iface) {
1322   if (!arr || !(arr->fFeatures & FADF_RECORD))
1323     return E_INVALIDARG;
1324   *iface = ((IRecordInfo**)arr)[-1];
1325   if (*iface)
1326     IRecordInfo_AddRef(*iface);
1327   return S_OK;
1328 }