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