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