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