Jean-Claude Batista
[wine.git] / dlls / oleaut32 / safearray.c
blob57ed899474fd9e1f7aadde9ea59dbd0c16fbd985
1 /*************************************************************************
2 * OLE Automation
3 * SafeArray Implementation
5 * This file contains the implementation of the SafeArray interface.
7 * Copyright 1999 Sylvain St-Germain
8 */
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"
19 DEFAULT_DEBUG_CHANNEL(ole)
21 /* Localy used methods */
22 static INT
23 endOfDim(LONG *coor, SAFEARRAYBOUND *mat, LONG dim, LONG realDim);
25 static ULONG
26 calcDisplacement(LONG *coor, SAFEARRAYBOUND *mat, LONG dim);
28 static BOOL
29 isPointer(USHORT feature);
31 static INT
32 getFeatures(VARTYPE vt);
34 static BOOL
35 validCoordinate(LONG *coor, SAFEARRAY *psa);
37 static BOOL
38 resizeSafeArray(SAFEARRAY *psa, LONG lDelta);
40 static BOOL
41 validArg(SAFEARRAY *psa);
43 static ULONG
44 getArraySize(SAFEARRAY *psa);
46 static HRESULT
47 duplicateData(SAFEARRAY *psa, SAFEARRAY **ppsaOut);
49 /* Association between VARTYPE and their size.
50 A size of zero is defined for the unsupported types. */
52 #define VARTYPE_NOT_SUPPORTED 0
53 const static ULONG VARTYPE_SIZE[] =
55 /* this is taken from wtypes.h. Only [S]es are supported by the SafeArray */
56 VARTYPE_NOT_SUPPORTED, /* VT_EMPTY [V] [P] nothing */
57 VARTYPE_NOT_SUPPORTED, /* VT_NULL [V] [P] SQL style Nul */
58 2, /* VT_I2 [V][T][P][S] 2 byte signed int */
59 4, /* VT_I4 [V][T][P][S] 4 byte signed int */
60 4, /* VT_R4 [V][T][P][S] 4 byte real */
61 8, /* VT_R8 [V][T][P][S] 8 byte real */
62 8, /* VT_CY [V][T][P][S] currency */
63 8, /* VT_DATE [V][T][P][S] date */
64 4, /* VT_BSTR [V][T][P][S] OLE Automation string*/
65 4, /* VT_DISPATCH [V][T][P][S] IDispatch * */
66 4, /* VT_ERROR [V][T] [S] SCODE */
67 4, /* VT_BOOL [V][T][P][S] True=-1, False=0*/
68 24, /* VT_VARIANT [V][T][P][S] VARIANT * */
69 4, /* VT_UNKNOWN [V][T] [S] IUnknown * */
70 16, /* VT_DECIMAL [V][T] [S] 16 byte fixed point */
71 VARTYPE_NOT_SUPPORTED, /* no VARTYPE here..... */
72 VARTYPE_NOT_SUPPORTED, /* VT_I1 [T] signed char */
73 1, /* VT_UI1 [V][T][P][S] unsigned char */
74 VARTYPE_NOT_SUPPORTED, /* VT_UI2 [T][P] unsigned short */
75 VARTYPE_NOT_SUPPORTED, /* VT_UI4 [T][P] unsigned short */
76 VARTYPE_NOT_SUPPORTED, /* VT_I8 [T][P] signed 64-bit int */
77 VARTYPE_NOT_SUPPORTED, /* VT_UI8 [T][P] unsigned 64-bit int */
78 VARTYPE_NOT_SUPPORTED, /* VT_INT [T] signed machine int */
79 VARTYPE_NOT_SUPPORTED, /* VT_UINT [T] unsigned machine int */
80 VARTYPE_NOT_SUPPORTED, /* VT_VOID [T] C style void */
81 VARTYPE_NOT_SUPPORTED, /* VT_HRESULT [T] Standard return type */
82 VARTYPE_NOT_SUPPORTED, /* VT_PTR [T] pointer type */
83 VARTYPE_NOT_SUPPORTED, /* VT_SAFEARRAY [T] (use VT_ARRAY in VARIANT)*/
84 VARTYPE_NOT_SUPPORTED, /* VT_CARRAY [T] C style array */
85 VARTYPE_NOT_SUPPORTED, /* VT_USERDEFINED [T] user defined type */
86 VARTYPE_NOT_SUPPORTED, /* VT_LPSTR [T][P] null terminated string */
87 VARTYPE_NOT_SUPPORTED, /* VT_LPWSTR [T][P] wide null term string */
88 VARTYPE_NOT_SUPPORTED, /* VT_FILETIME [P] FILETIME */
89 VARTYPE_NOT_SUPPORTED, /* VT_BLOB [P] Length prefixed bytes */
90 VARTYPE_NOT_SUPPORTED, /* VT_STREAM [P] Name of stream follows */
91 VARTYPE_NOT_SUPPORTED, /* VT_STORAGE [P] Name of storage follows */
92 VARTYPE_NOT_SUPPORTED, /* VT_STREAMED_OBJECT[P] Stream contains an object*/
93 VARTYPE_NOT_SUPPORTED, /* VT_STORED_OBJECT [P] Storage contains object*/
94 VARTYPE_NOT_SUPPORTED, /* VT_BLOB_OBJECT [P] Blob contains an object*/
95 VARTYPE_NOT_SUPPORTED, /* VT_CF [P] Clipboard format */
96 VARTYPE_NOT_SUPPORTED, /* VT_CLSID [P] A Class ID */
97 VARTYPE_NOT_SUPPORTED, /* VT_VECTOR [P] simple counted array */
98 VARTYPE_NOT_SUPPORTED, /* VT_ARRAY [V] SAFEARRAY* */
99 VARTYPE_NOT_SUPPORTED /* VT_BYREF [V] void* for local use */
102 const static int LAST_VARTYPE = sizeof(VARTYPE_SIZE)/sizeof(ULONG);
105 /*************************************************************************
106 * SafeArrayAllocDescriptor
107 * Allocate the appropriate amount of memory for the SafeArray descriptor
109 HRESULT WINAPI SafeArrayAllocDescriptor(
110 UINT cDims,
111 SAFEARRAY **ppsaOut)
113 SAFEARRAYBOUND *sab;
114 LONG allocSize = 0;
116 /* SAFEARRAY + SAFEARRAYBOUND * (cDims -1) ( -1 because there is already one
117 ( in SAFEARRAY struct */
118 allocSize = sizeof(**ppsaOut) + (sizeof(*sab) * (cDims-1));
120 /* Allocate memory for SAFEARRAY struc */
121 if(( (*ppsaOut)=HeapAlloc(
122 GetProcessHeap(), HEAP_ZERO_MEMORY, allocSize)) == NULL){
123 return(E_UNEXPECTED);
125 TRACE("SafeArray: %lu bytes allocated for descriptor.\n", allocSize);
127 return(S_OK);
130 /*************************************************************************
131 * SafeArrayAllocData
132 * Allocate the appropriate amount of data for the SafeArray data
134 HRESULT WINAPI SafeArrayAllocData(
135 SAFEARRAY *psa)
137 ULONG ulWholeArraySize; /* to store the size of the whole thing */
139 if(! validArg(psa))
140 return E_INVALIDARG;
142 ulWholeArraySize = getArraySize(psa);
144 /* Allocate memory for the data itself */
145 if((psa->pvData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
146 psa->cbElements*ulWholeArraySize)) == NULL)
147 return(E_UNEXPECTED);
149 TRACE("SafeArray: %lu bytes allocated for data at %p (%lu objects).\n",
150 psa->cbElements*ulWholeArraySize, psa->pvData, ulWholeArraySize);
152 return(S_OK);
155 /*************************************************************************
156 * SafeArrayCreate
157 * Create a SafeArray object by encapsulating AllocDescriptor and AllocData
159 SAFEARRAY* WINAPI SafeArrayCreate(
160 VARTYPE vt,
161 UINT cDims,
162 SAFEARRAYBOUND *rgsabound)
164 SAFEARRAY *psa;
165 HRESULT hRes;
166 USHORT cDim;
168 /* Validate supported VARTYPE */
169 if ( (vt >= LAST_VARTYPE) ||
170 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
171 return NULL;
173 /* Allocate memory for the array descriptor */
174 if( FAILED( hRes = SafeArrayAllocDescriptor(cDims, &psa)))
175 return NULL;
177 /* setup data members... */
178 psa->cDims = cDims;
179 psa->fFeatures = getFeatures(vt);
180 psa->cLocks = 0;
181 psa->pvData = NULL;
182 psa->cbElements= VARTYPE_SIZE[vt];
184 /* Invert the bounds ... */
185 for(cDim=0; cDim < psa->cDims; cDim++) {
186 psa->rgsabound[cDim].cElements = rgsabound[psa->cDims-cDim-1].cElements;
187 psa->rgsabound[cDim].lLbound = rgsabound[psa->cDims-cDim-1].lLbound;
190 /* allocate memory for the data... */
191 if( FAILED( hRes = SafeArrayAllocData(psa))) {
192 SafeArrayDestroyDescriptor(psa);
193 ERR("() : Failed to allocate the Safe Array data\n");
194 return NULL;
197 return(psa);
200 /*************************************************************************
201 * SafeArrayDestroyDescriptor
202 * Frees the memory associated with the descriptor.
204 HRESULT WINAPI SafeArrayDestroyDescriptor(
205 SAFEARRAY *psa)
207 /* Check for lockness before to free... */
208 if(psa->cLocks > 0)
209 return DISP_E_ARRAYISLOCKED;
211 /* The array is unlocked, then, deallocate memory */
212 if(HeapFree( GetProcessHeap(), 0, psa) == FALSE)
213 return E_UNEXPECTED;
215 return(S_OK);
219 /*************************************************************************
220 * SafeArrayLock
221 * Increment the lock counter
223 * Doc says (MSDN Library ) that psa->pvData should be made available (!= NULL)
224 * only when psa->cLocks is > 0... I don't get it since pvData is allocated
225 * before the array is locked, therefore
227 HRESULT WINAPI SafeArrayLock(
228 SAFEARRAY *psa)
230 if(! validArg(psa))
231 return E_INVALIDARG;
233 psa->cLocks++;
235 return(S_OK);
238 /*************************************************************************
239 * SafeArrayUnlock
240 * Decrement the lock counter
242 HRESULT WINAPI SafeArrayUnlock(
243 SAFEARRAY *psa)
245 if(! validArg(psa))
246 return E_INVALIDARG;
248 if (psa->cLocks > 0)
249 psa->cLocks--;
251 return(S_OK);
255 /*************************************************************************
256 * SafeArrayPutElement
257 * Set the data at the given coordinate
259 HRESULT WINAPI SafeArrayPutElement(
260 SAFEARRAY *psa,
261 LONG *rgIndices,
262 void *pv)
264 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
265 the desired one... */
266 PVOID elementStorageAddress = NULL; /* Adress to store the data */
267 BSTR pbstrReAllocStr = NULL; /* BSTR reallocated */
269 /* Validate the index given */
270 if(! validCoordinate(rgIndices, psa))
271 return DISP_E_BADINDEX;
272 if(! validArg(psa))
273 return E_INVALIDARG;
275 if( SafeArrayLock(psa) == S_OK) {
277 /* Figure out the number of items to skip */
278 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
280 /* Figure out the number of byte to skip ... */
281 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
283 if(isPointer(psa->fFeatures)) { /* increment ref count for this pointer */
285 *((VOID**)elementStorageAddress) = *(VOID**)pv;
286 IUnknown_AddRef( *(IUnknown**)pv);
288 } else {
290 if(psa->fFeatures == FADF_BSTR) { /* Create a new object */
292 if((pbstrReAllocStr = SysAllocString( (OLECHAR*)pv )) == NULL) {
293 SafeArrayUnlock(psa);
294 return E_OUTOFMEMORY;
295 } else
296 *((BSTR*)elementStorageAddress) = pbstrReAllocStr;
298 } else /* dupplicate the memory */
299 memcpy(elementStorageAddress, pv, SafeArrayGetElemsize(psa) );
302 } else {
303 ERR("SafeArray: Cannot lock array....\n");
304 return E_UNEXPECTED; /* UNDOC error condition */
307 TRACE("SafeArray: item put at adress %p.\n",elementStorageAddress);
308 return SafeArrayUnlock(psa);
312 /*************************************************************************
313 * SafeArrayGetElement
314 * Return the data element corresponding the the given coordinate
316 HRESULT WINAPI SafeArrayGetElement(
317 SAFEARRAY *psa,
318 LONG *rgIndices,
319 void *pv)
321 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
322 the desired one... */
323 PVOID elementStorageAddress = NULL; /* Adress to store the data */
324 BSTR pbstrReturnedStr = NULL; /* BSTR reallocated */
326 if(! validArg(psa))
327 return E_INVALIDARG;
329 if(! validCoordinate(rgIndices, psa)) /* Validate the index given */
330 return(DISP_E_BADINDEX);
332 if( SafeArrayLock(psa) == S_OK) {
334 /* Figure out the number of items to skip */
335 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
337 /* Figure out the number of byte to skip ... */
338 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
340 if( psa->fFeatures == FADF_BSTR) { /* reallocate the obj */
341 if( (pbstrReturnedStr =
342 SysAllocString( *(OLECHAR**)elementStorageAddress )) == NULL) {
343 SafeArrayUnlock(psa);
344 return E_OUTOFMEMORY;
345 } else
346 *((BSTR*)pv) = pbstrReturnedStr;
348 } else if( isPointer(psa->fFeatures) ) /* simply copy the pointer */
349 pv = *((PVOID*)elementStorageAddress);
350 else /* copy the bytes */
351 memcpy(pv, elementStorageAddress, SafeArrayGetElemsize(psa) );
353 } else {
354 ERR("SafeArray: Cannot lock array....\n");
355 return E_UNEXPECTED; /* UNDOC error condition */
358 return( SafeArrayUnlock(psa) );
361 /*************************************************************************
362 * SafeArrayGetUBound
363 * return the UP bound for a given array dimension
365 HRESULT WINAPI SafeArrayGetUBound(
366 SAFEARRAY *psa,
367 UINT nDim,
368 LONG *plUbound)
370 if(! validArg(psa))
371 return E_INVALIDARG;
373 if(nDim > psa->cDims)
374 return DISP_E_BADINDEX;
376 *plUbound = psa->rgsabound[nDim-1].lLbound +
377 psa->rgsabound[nDim-1].cElements - 1;
379 return S_OK;
382 /*************************************************************************
383 * SafeArrayGetLBound
384 * Return the LO bound for a given array dimension
386 HRESULT WINAPI SafeArrayGetLBound(
387 SAFEARRAY *psa,
388 UINT nDim,
389 LONG *plLbound)
391 if(! validArg(psa))
392 return E_INVALIDARG;
394 if(nDim > psa->cDims)
395 return DISP_E_BADINDEX;
397 *plLbound = psa->rgsabound[nDim-1].lLbound;
398 return S_OK;
401 /*************************************************************************
402 * SafeArrayGetDim
403 * returns the number of dimension in the array
405 UINT WINAPI SafeArrayGetDim(
406 SAFEARRAY * psa)
409 * A quick test in Windows shows that the behavior here for an invalid
410 * pointer is to return 0.
412 if(! validArg(psa))
413 return 0;
415 return psa->cDims;
418 /*************************************************************************
419 * SafeArrayGetElemsize
420 * Return the size of the element in the array
422 UINT WINAPI SafeArrayGetElemsize(
423 SAFEARRAY * psa)
426 * A quick test in Windows shows that the behavior here for an invalid
427 * pointer is to return 0.
429 if(! validArg(psa))
430 return 0;
432 return psa->cbElements;
435 /*************************************************************************
436 * SafeArrayAccessData
437 * increment the access count and return the data
439 HRESULT WINAPI SafeArrayAccessData(
440 SAFEARRAY *psa,
441 void **ppvData)
443 HRESULT hRes;
445 if(! validArg(psa))
446 return E_INVALIDARG;
448 hRes = SafeArrayLock(psa);
450 switch (hRes) {
451 case S_OK:
452 (*ppvData) = psa->pvData;
453 break;
454 case E_INVALIDARG:
455 (*ppvData) = NULL;
456 return E_INVALIDARG;
459 return S_OK;
463 /*************************************************************************
464 * SafeArrayUnaccessData
465 * Decrement the access count
467 HRESULT WINAPI SafeArrayUnaccessData(
468 SAFEARRAY * psa)
470 if(! validArg(psa))
471 return E_INVALIDARG;
473 return(SafeArrayUnlock(psa));
476 /************************************************************************
477 * SafeArrayPtrOfIndex
478 * Return a pointer to the element at rgIndices
480 HRESULT WINAPI SafeArrayPtrOfIndex(
481 SAFEARRAY *psa,
482 LONG *rgIndices,
483 void **ppvData)
485 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
486 the desired one... */
488 if(! validArg(psa))
489 return E_INVALIDARG;
491 if(! validCoordinate(rgIndices, psa))
492 return DISP_E_BADINDEX;
494 /* Figure out the number of items to skip */
495 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
497 *ppvData = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
499 return S_OK;
502 /************************************************************************
503 * SafeArrayDestroyData
504 * Frees the memory data bloc
506 HRESULT WINAPI SafeArrayDestroyData(
507 SAFEARRAY *psa)
509 HRESULT hRes;
510 ULONG ulWholeArraySize; /* count spot in array */
511 ULONG ulDataIter; /* to iterate the data space */
512 IUnknown *punk;
513 BSTR bstr;
515 if(! validArg(psa))
516 return E_INVALIDARG;
518 if(psa->cLocks > 0)
519 return DISP_E_ARRAYISLOCKED;
521 ulWholeArraySize = getArraySize(psa);
523 if(isPointer(psa->fFeatures)) { /* release the pointers */
525 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
526 punk = *(IUnknown**)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
528 if( punk != NULL)
529 IUnknown_Release(punk);
532 } else if(psa->fFeatures & FADF_BSTR) { /* deallocate the obj */
534 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
535 bstr = *(BSTR*)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
537 if( bstr != NULL)
538 SysFreeString( bstr );
542 /* check if this array is a Vector, in which case do not free the data
543 block since it has been allocated by AllocDescriptor and therefore
544 deserve to be freed by DestroyDescriptor */
545 if(!(psa->fFeatures & FADF_FIXEDSIZE)) { /* Set when we do CreateVector */
547 /* free the whole chunk */
548 if((hRes = HeapFree( GetProcessHeap(), 0, psa->pvData)) == 0) /*falied*/
549 return E_UNEXPECTED; /* UNDOC error condition */
551 psa->pvData = NULL;
554 return S_OK;
557 /************************************************************************
558 * SafeArrayCopyData
559 * Copy the psaSource's data block into psaTarget if dimension and size
560 * permits it.
562 HRESULT WINAPI SafeArrayCopyData(
563 SAFEARRAY *psaSource,
564 SAFEARRAY **psaTarget)
566 USHORT cDimCount; /* looper */
567 LONG lDelta; /* looper */
568 IUnknown *punk;
569 ULONG ulWholeArraySize; /* Number of item in SA */
570 BSTR bstr;
572 if(! (validArg(psaSource) && validArg(*psaTarget)) )
573 return E_INVALIDARG;
575 if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(*psaTarget))
576 return E_INVALIDARG;
578 ulWholeArraySize = getArraySize(psaSource);
580 /* The two arrays boundaries must be of same lenght */
581 for(cDimCount=0;cDimCount < psaSource->cDims; cDimCount++)
582 if( psaSource->rgsabound[cDimCount].cElements !=
583 (*psaTarget)->rgsabound[cDimCount].cElements)
584 return E_INVALIDARG;
586 if( isPointer((*psaTarget)->fFeatures) ) { /* the target contains ptr
587 that must be released */
588 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
589 punk = *(IUnknown**)
590 ((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
592 if( punk != NULL)
593 IUnknown_Release(punk);
596 } else if( (*psaTarget)->fFeatures & FADF_BSTR) { /* the target contain BSTR
597 that must be freed */
598 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
599 bstr =
600 *(BSTR*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
602 if( bstr != NULL)
603 SysFreeString( bstr );
607 return duplicateData(psaSource, psaTarget);
610 /************************************************************************
611 * SafeArrayDestroy
612 * Deallocates all memory reserved for the SafeArray
614 HRESULT WINAPI SafeArrayDestroy(
615 SAFEARRAY * psa)
617 HRESULT hRes;
619 if(! validArg(psa))
620 return E_INVALIDARG;
622 if(psa->cLocks > 0)
623 return DISP_E_ARRAYISLOCKED;
625 if((hRes = SafeArrayDestroyData( psa )) == S_OK)
626 if((hRes = SafeArrayDestroyDescriptor( psa )) == S_OK)
627 return S_OK;
629 return E_UNEXPECTED; /* UNDOC error condition */
632 /************************************************************************
633 * SafeArrayCopy
634 * Make a dupplicate of a SafeArray
636 HRESULT WINAPI SafeArrayCopy(
637 SAFEARRAY *psa,
638 SAFEARRAY **ppsaOut)
640 HRESULT hRes;
641 DWORD dAllocSize;
643 if(! validArg(psa))
644 return E_INVALIDARG;
646 if((hRes=SafeArrayAllocDescriptor(psa->cDims, ppsaOut)) == S_OK){
648 /* Duplicate the SAFEARRAY struc */
649 memcpy(*ppsaOut, psa,
650 sizeof(*psa)+(sizeof(*(psa->rgsabound))*(psa->cDims-1)));
652 (*ppsaOut)->pvData = NULL; /* do not point to the same data area */
654 /* Get the allocated memory size for source and allocate it for target */
655 dAllocSize = HeapSize(GetProcessHeap(), 0, psa->pvData);
656 (*ppsaOut)->pvData =
657 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dAllocSize);
659 if( (*ppsaOut)->pvData != NULL) { /* HeapAlloc succeed */
661 if( (hRes=duplicateData(psa, ppsaOut)) != S_OK) { /* E_OUTOFMEMORY */
662 HeapFree(GetProcessHeap(), 0, (*ppsaOut)->pvData);
663 (*ppsaOut)->pvData = NULL;
664 SafeArrayDestroyDescriptor(*ppsaOut);
665 return hRes;
668 } else { /* failed to allocate or dupplicate... */
669 SafeArrayDestroyDescriptor(*ppsaOut);
670 return E_UNEXPECTED; /* UNDOC error condition */
672 } else { /* failed to allocate mem for descriptor */
673 return E_OUTOFMEMORY; /* UNDOC error condiftion */
676 return S_OK;
679 /************************************************************************
680 * SafeArrayCreateVector
681 * Creates a one dimension safearray where the data is next to the
682 * SAFEARRAY structure.
684 SAFEARRAY* WINAPI SafeArrayCreateVector(
685 VARTYPE vt,
686 LONG lLbound,
687 ULONG cElements)
689 SAFEARRAY *psa;
691 /* Validate supported VARTYPE */
692 if ( (vt >= LAST_VARTYPE) ||
693 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
694 return NULL;
696 /* Allocate memory for the array descriptor and data contiguously */
697 if( FAILED( psa = HeapAlloc( GetProcessHeap(),
698 HEAP_ZERO_MEMORY,
699 (sizeof(*psa) + (VARTYPE_SIZE[vt] * cElements))))) {
700 return NULL;
703 /* setup data members... */
704 psa->cDims = 1; /* always and forever */
705 psa->fFeatures = getFeatures(vt) | FADF_FIXEDSIZE;
706 psa->cLocks = 0;
707 psa->pvData = psa+sizeof(*psa);
708 psa->cbElements = VARTYPE_SIZE[vt];
710 psa->rgsabound[0].cElements = cElements;
711 psa->rgsabound[0].lLbound = lLbound;
713 return(psa);
716 /************************************************************************
717 * SafeArrayRedim
718 * Changes the caracteristics of the last dimension of the SafeArray
720 HRESULT WINAPI SafeArrayRedim(
721 SAFEARRAY *psa,
722 SAFEARRAYBOUND *psaboundNew)
724 LONG lDelta; /* hold difference in size */
725 USHORT cDims=1; /* dims counter */
727 if( !validArg(psa) )
728 return E_INVALIDARG;
730 if( psa->cLocks > 0 )
731 return DISP_E_ARRAYISLOCKED;
733 if( psa->fFeatures & FADF_FIXEDSIZE )
734 return E_INVALIDARG;
736 if( SafeArrayLock(psa)==E_UNEXPECTED )
737 return E_UNEXPECTED;/* UNDOC error condition */
739 /* find the delta in number of array spot to apply to the new array */
740 lDelta = psaboundNew->cElements - psa->rgsabound[0].cElements;
741 for(; cDims < psa->cDims; cDims++)
742 /* delta in number of spot implied by modifying the last dimension */
743 lDelta *= psa->rgsabound[cDims].cElements;
745 if (lDelta == 0) { ;/* same size, maybe a change of lLbound, just set it */
747 } else /* need to enlarge (lDelta +) reduce (lDelta -) */
748 if(! resizeSafeArray(psa, lDelta))
749 return E_UNEXPECTED; /* UNDOC error condition */
751 /* the only modifyable dimension sits in [0] as the dimensions were reversed
752 at array creation time... */
753 psa->rgsabound[0].cElements = psaboundNew->cElements;
754 psa->rgsabound[0].lLbound = psaboundNew->lLbound;
756 return SafeArrayUnlock(psa);
759 /************************************************************************
760 * NOT WINDOWS API - SafeArray* Utility functions
761 ************************************************************************/
763 /************************************************************************
764 * Used to validate the SAFEARRAY type of arg
766 static BOOL validArg(
767 SAFEARRAY *psa)
769 SAFEARRAYBOUND *sab;
770 LONG psaSize = 0;
771 LONG descSize = 0;
772 LONG fullSize = 0;
775 * Let's check for the null pointer just in case.
777 if (psa == NULL)
778 return FALSE;
780 /* Check whether the size of the chunk make sens... That's the only thing
781 I can think of now... */
783 psaSize = HeapSize(GetProcessHeap(), 0, psa);
785 /* size of the descriptor when the SA is not created with CreateVector */
786 descSize = sizeof(*psa) + (sizeof(*sab) * (psa->cDims-1));
788 /* size of the descriptor + data when created with CreateVector */
789 fullSize = sizeof(*psa) + (psa->cbElements * psa->rgsabound[0].cElements);
791 return((psaSize >= descSize) || (psaSize >= fullSize));
794 /************************************************************************
795 * Used to reallocate memory
797 static BOOL resizeSafeArray(
798 SAFEARRAY *psa,
799 LONG lDelta)
801 ULONG ulWholeArraySize; /* use as multiplicator */
802 PVOID pvNewBlock = NULL;
803 IUnknown *punk;
804 BSTR bstr;
806 ulWholeArraySize = getArraySize(psa);
808 if(lDelta < 0) { /* array needs to be shorthen */
809 if( isPointer(psa->fFeatures)) /* ptr that need to be released */
810 for(;lDelta < 0; lDelta++) {
811 punk = *(IUnknown**)
812 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
814 if( punk != NULL )
815 IUnknown_Release(punk);
818 else if(psa->fFeatures & FADF_BSTR) /* BSTR that need to be freed */
819 for(;lDelta < 0; lDelta++) {
820 bstr = *(BSTR*)
821 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
823 if( bstr != NULL )
824 SysFreeString( bstr );
828 /* Ok now, if we are enlarging the array, we *MUST* move the whole block
829 pointed to by pvData. If we are shorthening the array, this move is
830 optional but we do it anyway becuase the benefit is that we are
831 releasing to the system the unused memory */
833 if((pvNewBlock = HeapReAlloc(GetProcessHeap(), 0, psa->pvData,
834 (ulWholeArraySize + lDelta) * psa->cbElements)) == NULL)
835 return FALSE; /* TODO If we get here it means:
836 SHRINK situation : we've deleted the undesired
837 data and did not release the memory
838 GROWING situation: we've been unable to grow the array
841 /* reassign to the new block of data */
842 psa->pvData = pvNewBlock;
843 return TRUE;
846 /************************************************************************
847 * Used to set the fFeatures data member of the SAFEARRAY structure.
849 static INT getFeatures(
850 VARTYPE vt)
852 switch(vt) {
853 case VT_UNKNOWN: return FADF_UNKNOWN;
854 case VT_DISPATCH: return FADF_DISPATCH;
855 case VT_BSTR: return FADF_BSTR;
857 return 0;
860 /************************************************************************
861 * Used to figure out if the fFeatures data member of the SAFEARRAY
862 * structure contain any information about the type of data stored...
864 static BOOL isPointer(
865 USHORT feature)
867 switch(feature) {
868 case FADF_UNKNOWN: return TRUE; /* those are pointers */
869 case FADF_DISPATCH: return TRUE;
871 return FALSE;
874 /************************************************************************
875 * Used to calculate the displacement when accessing or modifying
876 * safearray data set.
878 * Parameters: - LONG *coor is the desired location in the multidimension
879 * table. Ex for a 3 dim table: coor[] = {1,2,3};
880 * - ULONG *mat is the format of the table. Ex for a 3 dim
881 * table mat[] = {4,4,4};
882 * - USHORT dim is the number of dimension of the SafeArray
884 static ULONG calcDisplacement(
885 LONG *coor,
886 SAFEARRAYBOUND *mat,
887 LONG dim)
889 ULONG res = 0;
890 LONG iterDim;
892 for(iterDim=0; iterDim<dim; iterDim++)
893 /* the -mat[dim] bring coor[dim] relative to 0 for calculation */
894 res += ((coor[iterDim]-mat[iterDim].lLbound) *
895 endOfDim(coor, mat, iterDim+1, dim));
897 TRACE("SafeArray: calculated displacement is %lu.\n", res);
898 return(res);
901 /************************************************************************
902 * Recursivity agent for calcDisplacement method. Used within Put and
903 * Get methods.
905 static INT endOfDim(
906 LONG *coor,
907 SAFEARRAYBOUND *mat,
908 LONG dim,
909 LONG realDim)
911 if(dim==realDim)
912 return 1;
913 else
914 return (endOfDim(coor, mat, dim+1, realDim) * mat[dim].cElements);
918 /************************************************************************
919 * Method used to validate the coordinate received in Put and Get
920 * methods.
922 static BOOL validCoordinate(
923 LONG *coor,
924 SAFEARRAY *psa)
926 INT iter=0;
927 LONG lUBound;
928 LONG lLBound;
929 HRESULT hRes;
931 for(; iter<psa->cDims; iter++) {
932 if((hRes = SafeArrayGetLBound(psa, iter, &lLBound)) != S_OK)
933 return FALSE;
934 if((hRes = SafeArrayGetUBound(psa, iter, &lUBound)) != S_OK)
935 return FALSE;
937 if(lLBound == lUBound)
938 return FALSE;
940 if((coor[iter] >= lLBound) && (coor[iter] <= lUBound))
941 return TRUE;
942 else
943 return FALSE;
945 return FALSE;
948 /************************************************************************
949 * Method used to calculate the number of cells of the SA
951 static ULONG getArraySize(
952 SAFEARRAY *psa)
954 USHORT cCount;
955 ULONG ulWholeArraySize = 1;
957 for(cCount=0; cCount < psa->cDims; cCount++) /* foreach dimensions... */
958 ulWholeArraySize *= psa->rgsabound[cCount].cElements;
960 return ulWholeArraySize;
964 /************************************************************************
965 * Method used to handle data space dupplication for Copy32 and CopyData32
967 static HRESULT duplicateData(
968 SAFEARRAY *psa,
969 SAFEARRAY **ppsaOut)
971 ULONG ulWholeArraySize; /* size of the thing */
972 LONG lDelta;
973 IUnknown *punk;
974 BSTR pbstrReAllocStr = NULL; /* BSTR reallocated */
976 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
978 SafeArrayLock(*ppsaOut);
980 if( isPointer(psa->fFeatures) ) { /* If datatype is object increment
981 object's reference count */
983 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
984 punk = *(IUnknown**)((char *) psa->pvData+(lDelta * psa->cbElements));
986 if( punk != NULL)
987 IUnknown_AddRef(punk);
990 /* Copy the source array data into target array */
991 memcpy((*ppsaOut)->pvData, psa->pvData,
992 ulWholeArraySize*psa->cbElements);
994 } else if( psa->fFeatures & FADF_BSTR ) { /* if datatype is BSTR allocate
995 the BSTR in the new array */
997 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
998 if(( pbstrReAllocStr = SysAllocString(
999 *(BSTR*)((char *) psa->pvData+(lDelta * psa->cbElements)))) == NULL) {
1001 SafeArrayUnlock(*ppsaOut);
1002 return E_OUTOFMEMORY;
1005 *((BSTR*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements))) =
1006 pbstrReAllocStr;
1009 } else { /* Simply copy the source array data into target array */
1011 memcpy((*ppsaOut)->pvData, psa->pvData,
1012 ulWholeArraySize*psa->cbElements);
1015 SafeArrayUnlock(*ppsaOut);
1017 return S_OK;