1 /*************************************************************************
3 * SafeArray Implementation
5 * This file contains the implementation of the SafeArray interface.
7 * Copyright 1999 Sylvain St-Germain
16 #include "wine/obj_base.h"
17 #include "debugtools.h"
19 DEFAULT_DEBUG_CHANNEL(ole);
21 #define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
23 /* Locally used methods */
25 endOfDim(LONG *coor, SAFEARRAYBOUND *mat, LONG dim, LONG realDim);
28 calcDisplacement(LONG *coor, SAFEARRAYBOUND *mat, LONG dim);
31 isPointer(USHORT feature);
34 getFeatures(VARTYPE vt);
37 validCoordinate(LONG *coor, SAFEARRAY *psa);
40 resizeSafeArray(SAFEARRAY *psa, LONG lDelta);
43 validArg(SAFEARRAY *psa);
46 getArraySize(SAFEARRAY *psa);
49 duplicateData(SAFEARRAY *psa, SAFEARRAY **ppsaOut);
51 /* Association between VARTYPE and their size.
52 A size of zero is defined for the unsupported types. */
54 #define VARTYPE_NOT_SUPPORTED 0
55 static const ULONG VARTYPE_SIZE[] =
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 */
104 static const int LAST_VARTYPE = sizeof(VARTYPE_SIZE)/sizeof(VARTYPE_SIZE[0]);
107 /*************************************************************************
108 * SafeArrayAllocDescriptor (OLEAUT32.36)
109 * Allocate the appropriate amount of memory for the SafeArray descriptor
111 HRESULT WINAPI SafeArrayAllocDescriptor(
118 /* SAFEARRAY + SAFEARRAYBOUND * (cDims -1) ( -1 because there is already one
119 ( in SAFEARRAY struct */
120 allocSize = sizeof(**ppsaOut) + (sizeof(*sab) * (cDims-1));
122 /* Allocate memory for SAFEARRAY struc */
123 if(( (*ppsaOut)=HeapAlloc(
124 GetProcessHeap(), HEAP_ZERO_MEMORY, allocSize)) == NULL){
125 return(E_UNEXPECTED);
127 TRACE("SafeArray: %lu bytes allocated for descriptor.\n", allocSize);
132 /*************************************************************************
133 * SafeArrayAllocDescriptorEx (OLEAUT32.429)
134 * Allocate the appropriate amount of memory for the SafeArray descriptor
136 * This is a minimal implementation just to get things moving.
138 * The MSDN documentation on this doesn't tell us much.
140 HRESULT WINAPI SafeArrayAllocDescriptorEx(
145 if ( (vt >= LAST_VARTYPE) ||
146 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
149 return SafeArrayAllocDescriptor (cDims, ppsaOut);
152 /*************************************************************************
153 * SafeArrayAllocData (OLEAUT32.37)
154 * Allocate the appropriate amount of data for the SafeArray data
156 HRESULT WINAPI SafeArrayAllocData(
159 ULONG ulWholeArraySize; /* to store the size of the whole thing */
164 ulWholeArraySize = getArraySize(psa);
166 /* Allocate memory for the data itself */
167 if((psa->pvData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
168 psa->cbElements*ulWholeArraySize)) == NULL)
169 return(E_UNEXPECTED);
171 TRACE("SafeArray: %lu bytes allocated for data at %p (%lu objects).\n",
172 psa->cbElements*ulWholeArraySize, psa->pvData, ulWholeArraySize);
177 /*************************************************************************
178 * SafeArrayCreate (OLEAUT32.15)
179 * Create a SafeArray object by encapsulating AllocDescriptor and AllocData
181 SAFEARRAY* WINAPI SafeArrayCreate(
184 SAFEARRAYBOUND *rgsabound)
190 /* Validate supported VARTYPE */
191 if ( (vt >= LAST_VARTYPE) ||
192 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
195 /* Allocate memory for the array descriptor */
196 if( FAILED( hRes = SafeArrayAllocDescriptor(cDims, &psa)))
199 /* setup data members... */
201 psa->fFeatures = getFeatures(vt);
204 psa->cbElements= VARTYPE_SIZE[vt];
206 /* Invert the bounds ... */
207 for(cDim=0; cDim < psa->cDims; cDim++) {
208 psa->rgsabound[cDim].cElements = rgsabound[psa->cDims-cDim-1].cElements;
209 psa->rgsabound[cDim].lLbound = rgsabound[psa->cDims-cDim-1].lLbound;
212 /* allocate memory for the data... */
213 if( FAILED( hRes = SafeArrayAllocData(psa))) {
214 SafeArrayDestroyDescriptor(psa);
215 ERR("() : Failed to allocate the Safe Array data\n");
222 /*************************************************************************
223 * SafeArrayDestroyDescriptor (OLEAUT32.38)
224 * Frees the memory associated with the descriptor.
226 HRESULT WINAPI SafeArrayDestroyDescriptor(
229 /* Check for lockness before to free... */
231 return DISP_E_ARRAYISLOCKED;
233 /* The array is unlocked, then, deallocate memory */
234 if(HeapFree( GetProcessHeap(), 0, psa) == FALSE)
241 /*************************************************************************
242 * SafeArrayLock (OLEAUT32.21)
243 * Increment the lock counter
245 * Doc says (MSDN Library ) that psa->pvData should be made available (!= NULL)
246 * only when psa->cLocks is > 0... I don't get it since pvData is allocated
247 * before the array is locked, therefore
249 HRESULT WINAPI SafeArrayLock(
260 /*************************************************************************
261 * SafeArrayUnlock (OLEAUT32.22)
262 * Decrement the lock counter
264 HRESULT WINAPI SafeArrayUnlock(
277 /*************************************************************************
278 * SafeArrayPutElement (OLEAUT32.26)
279 * Set the data at the given coordinate
281 HRESULT WINAPI SafeArrayPutElement(
286 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
287 the desired one... */
288 PVOID elementStorageAddress = NULL; /* Adress to store the data */
290 /* Validate the index given */
291 if(! validCoordinate(rgIndices, psa))
292 return DISP_E_BADINDEX;
296 if( SafeArrayLock(psa) == S_OK) {
298 /* Figure out the number of items to skip */
299 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
301 /* Figure out the number of byte to skip ... */
302 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
304 if(isPointer(psa->fFeatures)) { /* increment ref count for this pointer */
306 *((PVOID*)elementStorageAddress) = *(PVOID*)pv;
307 IUnknown_AddRef( *(IUnknown**)pv);
311 if(psa->fFeatures == FADF_BSTR) { /* Create a new object */
312 BSTR pbstrReAllocStr = NULL;
314 ((pbstrReAllocStr = SYSDUPSTRING( (OLECHAR*)pv )) == NULL)) {
315 SafeArrayUnlock(psa);
316 return E_OUTOFMEMORY;
318 *((BSTR*)elementStorageAddress) = pbstrReAllocStr;
320 else if(psa->fFeatures == FADF_VARIANT) {
321 HRESULT hr = VariantCopy(elementStorageAddress, pv);
323 SafeArrayUnlock(psa);
327 else /* duplicate the memory */
328 memcpy(elementStorageAddress, pv, SafeArrayGetElemsize(psa) );
332 ERR("SafeArray: Cannot lock array....\n");
333 return E_UNEXPECTED; /* UNDOC error condition */
336 TRACE("SafeArray: item put at adress %p.\n",elementStorageAddress);
337 return SafeArrayUnlock(psa);
341 /*************************************************************************
342 * SafeArrayGetElement (OLEAUT32.25)
343 * Return the data element corresponding the the given coordinate
345 HRESULT WINAPI SafeArrayGetElement(
350 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
351 the desired one... */
352 PVOID elementStorageAddress = NULL; /* Adress to store the data */
357 if(! validCoordinate(rgIndices, psa)) /* Validate the index given */
358 return(DISP_E_BADINDEX);
360 if( SafeArrayLock(psa) == S_OK) {
362 /* Figure out the number of items to skip */
363 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
365 /* Figure out the number of byte to skip ... */
366 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
368 if( psa->fFeatures == FADF_BSTR) { /* reallocate the obj */
369 BSTR pbstrStoredStr = *(OLECHAR**)elementStorageAddress;
370 BSTR pbstrReturnedStr = NULL;
371 if( pbstrStoredStr &&
372 ((pbstrReturnedStr = SYSDUPSTRING( pbstrStoredStr )) == NULL) ) {
373 SafeArrayUnlock(psa);
374 return E_OUTOFMEMORY;
376 *((BSTR*)pv) = pbstrReturnedStr;
378 else if( psa->fFeatures == FADF_VARIANT) {
381 hr = VariantCopy(pv, elementStorageAddress);
383 SafeArrayUnlock(psa);
387 else if( isPointer(psa->fFeatures) ) /* simply copy the pointer */
388 *(PVOID*)pv = *((PVOID*)elementStorageAddress);
389 else /* copy the bytes */
390 memcpy(pv, elementStorageAddress, psa->cbElements );
393 ERR("SafeArray: Cannot lock array....\n");
394 return E_UNEXPECTED; /* UNDOC error condition */
397 return( SafeArrayUnlock(psa) );
400 /*************************************************************************
401 * SafeArrayGetUBound (OLEAUT32.19)
402 * return the UP bound for a given array dimension
404 HRESULT WINAPI SafeArrayGetUBound(
412 if(nDim > psa->cDims)
413 return DISP_E_BADINDEX;
416 return DISP_E_BADINDEX;
418 *plUbound = psa->rgsabound[nDim-1].lLbound +
419 psa->rgsabound[nDim-1].cElements - 1;
424 /*************************************************************************
425 * SafeArrayGetLBound (OLEAUT32.20)
426 * Return the LO bound for a given array dimension
428 HRESULT WINAPI SafeArrayGetLBound(
436 if(nDim > psa->cDims)
437 return DISP_E_BADINDEX;
440 return DISP_E_BADINDEX;
442 *plLbound = psa->rgsabound[nDim-1].lLbound;
446 /*************************************************************************
447 * SafeArrayGetDim (OLEAUT32.17)
448 * returns the number of dimension in the array
450 UINT WINAPI SafeArrayGetDim(
454 * A quick test in Windows shows that the behavior here for an invalid
455 * pointer is to return 0.
463 /*************************************************************************
464 * SafeArrayGetElemsize (OLEAUT32.18)
465 * Return the size of the element in the array
467 UINT WINAPI SafeArrayGetElemsize(
471 * A quick test in Windows shows that the behavior here for an invalid
472 * pointer is to return 0.
477 return psa->cbElements;
480 /*************************************************************************
481 * SafeArrayAccessData (OLEAUT32.23)
482 * increment the access count and return the data
484 HRESULT WINAPI SafeArrayAccessData(
493 hRes = SafeArrayLock(psa);
497 (*ppvData) = psa->pvData;
508 /*************************************************************************
509 * SafeArrayUnaccessData (OLEAUT32.24)
510 * Decrement the access count
512 HRESULT WINAPI SafeArrayUnaccessData(
518 return(SafeArrayUnlock(psa));
521 /************************************************************************
522 * SafeArrayPtrOfIndex (OLEAUT32.148)
523 * Return a pointer to the element at rgIndices
525 HRESULT WINAPI SafeArrayPtrOfIndex(
530 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
531 the desired one... */
536 if(! validCoordinate(rgIndices, psa))
537 return DISP_E_BADINDEX;
539 /* Although it is dangerous to do this without having a lock, it is not
540 * illegal. Microsoft do warn of the danger.
543 /* Figure out the number of items to skip */
544 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
546 *ppvData = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
551 /************************************************************************
552 * SafeArrayDestroyData (OLEAUT32.39)
553 * Frees the memory data bloc
555 HRESULT WINAPI SafeArrayDestroyData(
559 ULONG ulWholeArraySize; /* count spot in array */
560 ULONG ulDataIter; /* to iterate the data space */
566 return DISP_E_ARRAYISLOCKED;
568 ulWholeArraySize = getArraySize(psa);
570 if(isPointer(psa->fFeatures)) { /* release the pointers */
573 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
574 punk = *(IUnknown**)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
577 IUnknown_Release(punk);
581 else if(psa->fFeatures & FADF_BSTR) { /* deallocate the obj */
584 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
585 bstr = *(BSTR*)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
588 SysFreeString( bstr );
591 else if(psa->fFeatures & FADF_VARIANT) { /* deallocate the obj */
593 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
594 VariantClear((VARIANT*)((char *) psa->pvData+(ulDataIter*(psa->cbElements))));
598 /* check if this array is a Vector, in which case do not free the data
599 block since it has been allocated by AllocDescriptor and therefore
600 deserve to be freed by DestroyDescriptor */
601 if(!(psa->fFeatures & FADF_CREATEVECTOR)) { /* Set when we do CreateVector */
603 /* free the whole chunk */
604 if((hRes = HeapFree( GetProcessHeap(), 0, psa->pvData)) == 0) /*falied*/
605 return E_UNEXPECTED; /* UNDOC error condition */
613 /************************************************************************
614 * SafeArrayCopyData (OLEAUT32.412)
615 * Copy the psaSource's data block into psaTarget if dimension and size
618 HRESULT WINAPI SafeArrayCopyData(
619 SAFEARRAY *psaSource,
620 SAFEARRAY **psaTarget)
622 USHORT cDimCount; /* looper */
623 LONG lDelta; /* looper */
625 ULONG ulWholeArraySize; /* Number of item in SA */
628 if(! (validArg(psaSource) && validArg(*psaTarget)) )
631 if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(*psaTarget))
634 ulWholeArraySize = getArraySize(psaSource);
636 /* The two arrays boundaries must be of same lenght */
637 for(cDimCount=0;cDimCount < psaSource->cDims; cDimCount++)
638 if( psaSource->rgsabound[cDimCount].cElements !=
639 (*psaTarget)->rgsabound[cDimCount].cElements)
642 if( isPointer((*psaTarget)->fFeatures) ) { /* the target contains ptr
643 that must be released */
644 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
646 ((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
649 IUnknown_Release(punk);
653 else if( (*psaTarget)->fFeatures & FADF_BSTR) { /* the target contain BSTR
654 that must be freed */
655 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
657 *(BSTR*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
660 SysFreeString( bstr );
663 else if( (*psaTarget)->fFeatures & FADF_VARIANT) {
665 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
666 VariantClear((VARIANT*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements)));
670 return duplicateData(psaSource, psaTarget);
673 /************************************************************************
674 * SafeArrayDestroy (OLEAUT32.16)
675 * Deallocates all memory reserved for the SafeArray
677 HRESULT WINAPI SafeArrayDestroy(
686 return DISP_E_ARRAYISLOCKED;
688 if((hRes = SafeArrayDestroyData( psa )) == S_OK)
689 if((hRes = SafeArrayDestroyDescriptor( psa )) == S_OK)
692 return E_UNEXPECTED; /* UNDOC error condition */
695 /************************************************************************
696 * SafeArrayCopy (OLEAUT32.27)
697 * Make a dupplicate of a SafeArray
699 HRESULT WINAPI SafeArrayCopy(
705 ULONG ulWholeArraySize; /* size of the thing */
710 if((hRes=SafeArrayAllocDescriptor(psa->cDims, ppsaOut)) == S_OK){
712 /* Duplicate the SAFEARRAY struc */
713 memcpy(*ppsaOut, psa,
714 sizeof(*psa)+(sizeof(*(psa->rgsabound))*(psa->cDims-1)));
716 (*ppsaOut)->pvData = NULL; /* do not point to the same data area */
718 /* make sure the new safe array doesn't have the FADF_CREATEVECTOR flag,
719 because the data has not been allocated with the descriptor. */
720 (*ppsaOut)->fFeatures &= ~FADF_CREATEVECTOR;
722 /* Get the allocated memory size for source and allocate it for target */
723 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
724 dAllocSize = ulWholeArraySize*psa->cbElements;
727 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dAllocSize);
728 if( (*ppsaOut)->pvData != NULL) { /* HeapAlloc succeed */
730 if( (hRes=duplicateData(psa, ppsaOut)) != S_OK) { /* E_OUTOFMEMORY */
731 HeapFree(GetProcessHeap(), 0, (*ppsaOut)->pvData);
732 (*ppsaOut)->pvData = NULL;
733 SafeArrayDestroyDescriptor(*ppsaOut);
737 } else { /* failed to allocate or dupplicate... */
738 SafeArrayDestroyDescriptor(*ppsaOut);
739 return E_UNEXPECTED; /* UNDOC error condition */
741 } else { /* failed to allocate mem for descriptor */
742 return E_OUTOFMEMORY; /* UNDOC error condiftion */
748 /************************************************************************
749 * SafeArrayCreateVector (OLEAUT32.411)
750 * Creates a one dimension safearray where the data is next to the
751 * SAFEARRAY structure.
753 SAFEARRAY* WINAPI SafeArrayCreateVector(
760 /* Validate supported VARTYPE */
761 if ( (vt >= LAST_VARTYPE) ||
762 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
765 /* Allocate memory for the array descriptor and data contiguously */
766 if( FAILED( psa = HeapAlloc( GetProcessHeap(),
768 (sizeof(*psa) + (VARTYPE_SIZE[vt] * cElements))))) {
772 /* setup data members... */
773 psa->cDims = 1; /* always and forever */
774 psa->fFeatures = getFeatures(vt) | FADF_CREATEVECTOR; /* undocumented flag used by Microsoft */
776 psa->pvData = (BYTE*)psa + sizeof(*psa);
777 psa->cbElements = VARTYPE_SIZE[vt];
779 psa->rgsabound[0].cElements = cElements;
780 psa->rgsabound[0].lLbound = lLbound;
785 /************************************************************************
786 * SafeArrayRedim (OLEAUT32.40)
787 * Changes the caracteristics of the last dimension of the SafeArray
789 HRESULT WINAPI SafeArrayRedim(
791 SAFEARRAYBOUND *psaboundNew)
793 LONG lDelta; /* hold difference in size */
794 USHORT cDims=1; /* dims counter */
799 if( psa->cLocks > 0 )
800 return DISP_E_ARRAYISLOCKED;
802 if( psa->fFeatures & FADF_FIXEDSIZE )
805 if( SafeArrayLock(psa)==E_UNEXPECTED )
806 return E_UNEXPECTED;/* UNDOC error condition */
808 /* find the delta in number of array spot to apply to the new array */
809 lDelta = psaboundNew->cElements - psa->rgsabound[0].cElements;
810 for(; cDims < psa->cDims; cDims++)
811 /* delta in number of spot implied by modifying the last dimension */
812 lDelta *= psa->rgsabound[cDims].cElements;
814 TRACE("elements=%ld, Lbound=%ld (delta=%ld)\n", psaboundNew->cElements, psaboundNew->lLbound, lDelta);
816 if (lDelta == 0) { ;/* same size, maybe a change of lLbound, just set it */
818 } else /* need to enlarge (lDelta +) reduce (lDelta -) */
819 if(! resizeSafeArray(psa, lDelta))
820 return E_UNEXPECTED; /* UNDOC error condition */
822 /* the only modifyable dimension sits in [0] as the dimensions were reversed
823 at array creation time... */
824 psa->rgsabound[0].cElements = psaboundNew->cElements;
825 psa->rgsabound[0].lLbound = psaboundNew->lLbound;
827 return SafeArrayUnlock(psa);
830 /************************************************************************
831 * NOT WINDOWS API - SafeArray* Utility functions
832 ************************************************************************/
834 /************************************************************************
835 * Used to validate the SAFEARRAY type of arg
837 static BOOL validArg(
846 * Let's check for the null pointer just in case.
851 /* Check whether the size of the chunk makes sense... That's the only thing
852 I can think of now... */
854 psaSize = HeapSize(GetProcessHeap(), 0, psa);
856 /* uh, foreign heap. Better don't mess with it ! */
859 /* size of the descriptor when the SA is not created with CreateVector */
860 descSize = sizeof(*psa) + (sizeof(*sab) * (psa->cDims-1));
862 /* size of the descriptor + data when created with CreateVector */
863 fullSize = sizeof(*psa) + (psa->cbElements * psa->rgsabound[0].cElements);
865 return((psaSize >= descSize) || (psaSize >= fullSize));
868 /************************************************************************
869 * Used to reallocate memory
871 static BOOL resizeSafeArray(
875 ULONG ulWholeArraySize; /* use as multiplicator */
876 PVOID pvNewBlock = NULL;
880 ulWholeArraySize = getArraySize(psa);
882 if(lDelta < 0) { /* array needs to be shorthen */
883 if( isPointer(psa->fFeatures)) /* ptr that need to be released */
884 for(;lDelta < 0; lDelta++) {
886 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
889 IUnknown_Release(punk);
892 else if(psa->fFeatures & FADF_BSTR) /* BSTR that need to be freed */
893 for(;lDelta < 0; lDelta++) {
895 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
898 SysFreeString( bstr );
900 else if(psa->fFeatures & FADF_VARIANT)
901 for(;lDelta < 0; lDelta++) {
902 VariantClear((VARIANT*)((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements)));
906 if (!(psa->fFeatures & FADF_CREATEVECTOR))
908 /* Ok now, if we are enlarging the array, we *MUST* move the whole block
909 pointed to by pvData. If we are shorthening the array, this move is
910 optional but we do it anyway becuase the benefit is that we are
911 releasing to the system the unused memory */
913 if((pvNewBlock = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, psa->pvData,
914 (ulWholeArraySize + lDelta) * psa->cbElements)) == NULL)
915 return FALSE; /* TODO If we get here it means:
916 SHRINK situation : we've deleted the undesired
917 data and did not release the memory
918 GROWING situation: we've been unable to grow the array
923 /* Allocate a new block, because the previous data has been allocated with
924 the descriptor in SafeArrayCreateVector function. */
926 if((pvNewBlock = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
927 ulWholeArraySize * psa->cbElements)) == NULL)
930 psa->fFeatures &= ~FADF_CREATEVECTOR;
932 /* reassign to the new block of data */
933 psa->pvData = pvNewBlock;
937 /************************************************************************
938 * Used to set the fFeatures data member of the SAFEARRAY structure.
940 static INT getFeatures(
944 case VT_BSTR: return FADF_BSTR;
945 case VT_UNKNOWN: return FADF_UNKNOWN;
946 case VT_DISPATCH: return FADF_DISPATCH;
947 case VT_VARIANT: return FADF_VARIANT;
952 /************************************************************************
953 * Used to figure out if the fFeatures data member of the SAFEARRAY
954 * structure contain any information about the type of data stored...
956 static BOOL isPointer(
960 case FADF_UNKNOWN: return TRUE; /* those are pointers */
961 case FADF_DISPATCH: return TRUE;
966 /************************************************************************
967 * Used to calculate the displacement when accessing or modifying
968 * safearray data set.
970 * Parameters: - LONG *coor is the desired location in the multidimension
971 * table. Ex for a 3 dim table: coor[] = {1,2,3};
972 * - ULONG *mat is the format of the table. Ex for a 3 dim
973 * table mat[] = {4,4,4};
974 * - USHORT dim is the number of dimension of the SafeArray
976 static ULONG calcDisplacement(
984 for(iterDim=0; iterDim<dim; iterDim++)
985 /* the -mat[dim] bring coor[dim] relative to 0 for calculation */
986 res += ((coor[iterDim]-mat[iterDim].lLbound) *
987 endOfDim(coor, mat, iterDim+1, dim));
989 TRACE("SafeArray: calculated displacement is %lu.\n", res);
993 /************************************************************************
994 * Recursivity agent for calcDisplacement method. Used within Put and
1006 return (endOfDim(coor, mat, dim+1, realDim) * mat[dim].cElements);
1010 /************************************************************************
1011 * Method used to validate the coordinate received in Put and Get
1014 static BOOL validCoordinate(
1023 if (!psa->cDims) return FALSE;
1024 for(; iter<psa->cDims; iter++) {
1025 TRACE("coor[%d]=%ld\n", iter, coor[iter]);
1026 if((hRes = SafeArrayGetLBound(psa, (iter+1), &lLBound)) != S_OK)
1028 if((hRes = SafeArrayGetUBound(psa, (iter+1), &lUBound)) != S_OK)
1031 if(lLBound > lUBound)
1034 if((coor[iter] < lLBound) || (coor[iter] > lUBound))
1040 /************************************************************************
1041 * Method used to calculate the number of cells of the SA
1043 static ULONG getArraySize(
1047 ULONG ulWholeArraySize = 1;
1049 for(cCount=0; cCount < psa->cDims; cCount++) /* foreach dimensions... */
1050 ulWholeArraySize *= psa->rgsabound[cCount].cElements;
1052 return ulWholeArraySize;
1056 /************************************************************************
1057 * Method used to handle data space dupplication for Copy32 and CopyData32
1059 static HRESULT duplicateData(
1061 SAFEARRAY **ppsaOut)
1063 ULONG ulWholeArraySize; /* size of the thing */
1066 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
1068 SafeArrayLock(*ppsaOut);
1070 if( isPointer(psa->fFeatures) ) { /* If datatype is object increment
1071 object's reference count */
1074 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1075 punk = *(IUnknown**)((char *) psa->pvData+(lDelta * psa->cbElements));
1078 IUnknown_AddRef(punk);
1081 /* Copy the source array data into target array */
1082 memcpy((*ppsaOut)->pvData, psa->pvData,
1083 ulWholeArraySize*psa->cbElements);
1086 else if( psa->fFeatures & FADF_BSTR ) { /* if datatype is BSTR allocate
1087 the BSTR in the new array */
1088 BSTR pbstrReAllocStr = NULL;
1090 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1091 if(( pbstrReAllocStr = SYSDUPSTRING(
1092 *(BSTR*)((char *) psa->pvData+(lDelta * psa->cbElements)))) == NULL) {
1094 SafeArrayUnlock(*ppsaOut);
1095 return E_OUTOFMEMORY;
1098 *((BSTR*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements))) =
1103 else if( psa->fFeatures & FADF_VARIANT ) {
1105 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1106 VariantCopy((VARIANT*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements)),
1107 (VARIANT*)((char *) psa->pvData+(lDelta * psa->cbElements)));
1111 else { /* Simply copy the source array data into target array */
1113 memcpy((*ppsaOut)->pvData, psa->pvData,
1114 ulWholeArraySize*psa->cbElements);
1117 SafeArrayUnlock(*ppsaOut);
1123 /************************************************************************
1124 * SafeArrayGetVarType (OLEAUT32.77)
1125 * Returns the VARTYPE stored in the given safearray
1127 HRESULT WINAPI SafeArrayGetVarType(
1131 HRESULT hr = E_INVALIDARG;
1132 VARTYPE vt = VT_EMPTY;
1134 /* const short VARTYPE_OFFSET = -4; */
1136 if (psa->fFeatures & FADF_HAVEVARTYPE)
1138 /* VT tag @ negative offset 4 in the array descriptor */
1139 FIXME("Returning VT_BSTR instead of VT_...\n");
1142 else if (psa->fFeatures & FADF_RECORD)
1146 else if (psa->fFeatures & FADF_BSTR)
1150 else if (psa->fFeatures & FADF_UNKNOWN)
1154 else if (psa->fFeatures & FADF_DISPATCH)
1158 else if (psa->fFeatures & FADF_VARIANT)
1169 TRACE("HRESULT = %08lx\n", hr);