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 /* Localy 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(ULONG);
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 * SafeArrayAllocData (OLEAUT32.37)
134 * Allocate the appropriate amount of data for the SafeArray data
136 HRESULT WINAPI SafeArrayAllocData(
139 ULONG ulWholeArraySize; /* to store the size of the whole thing */
144 ulWholeArraySize = getArraySize(psa);
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);
151 TRACE("SafeArray: %lu bytes allocated for data at %p (%lu objects).\n",
152 psa->cbElements*ulWholeArraySize, psa->pvData, ulWholeArraySize);
157 /*************************************************************************
158 * SafeArrayCreate (OLEAUT32.15)
159 * Create a SafeArray object by encapsulating AllocDescriptor and AllocData
161 SAFEARRAY* WINAPI SafeArrayCreate(
164 SAFEARRAYBOUND *rgsabound)
170 /* Validate supported VARTYPE */
171 if ( (vt >= LAST_VARTYPE) ||
172 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
175 /* Allocate memory for the array descriptor */
176 if( FAILED( hRes = SafeArrayAllocDescriptor(cDims, &psa)))
179 /* setup data members... */
181 psa->fFeatures = getFeatures(vt);
184 psa->cbElements= VARTYPE_SIZE[vt];
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;
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");
202 /*************************************************************************
203 * SafeArrayDestroyDescriptor (OLEAUT32.38)
204 * Frees the memory associated with the descriptor.
206 HRESULT WINAPI SafeArrayDestroyDescriptor(
209 /* Check for lockness before to free... */
211 return DISP_E_ARRAYISLOCKED;
213 /* The array is unlocked, then, deallocate memory */
214 if(HeapFree( GetProcessHeap(), 0, psa) == FALSE)
221 /*************************************************************************
222 * SafeArrayLock (OLEAUT32.21)
223 * Increment the lock counter
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
229 HRESULT WINAPI SafeArrayLock(
240 /*************************************************************************
241 * SafeArrayUnlock (OLEAUT32.22)
242 * Decrement the lock counter
244 HRESULT WINAPI SafeArrayUnlock(
257 /*************************************************************************
258 * SafeArrayPutElement (OLEAUT32.26)
259 * Set the data at the given coordinate
261 HRESULT WINAPI SafeArrayPutElement(
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 */
270 /* Validate the index given */
271 if(! validCoordinate(rgIndices, psa))
272 return DISP_E_BADINDEX;
276 if( SafeArrayLock(psa) == S_OK) {
278 /* Figure out the number of items to skip */
279 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
281 /* Figure out the number of byte to skip ... */
282 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
284 if(isPointer(psa->fFeatures)) { /* increment ref count for this pointer */
286 *((PVOID*)elementStorageAddress) = *(PVOID*)pv;
287 IUnknown_AddRef( *(IUnknown**)pv);
291 if(psa->fFeatures == FADF_BSTR) { /* Create a new object */
292 BSTR pbstrReAllocStr = NULL;
294 ((pbstrReAllocStr = SYSDUPSTRING( (OLECHAR*)pv )) == NULL)) {
295 SafeArrayUnlock(psa);
296 return E_OUTOFMEMORY;
298 *((BSTR*)elementStorageAddress) = pbstrReAllocStr;
300 else if(psa->fFeatures == FADF_VARIANT) {
301 HRESULT hr = VariantCopy(elementStorageAddress, pv);
303 SafeArrayUnlock(psa);
307 else /* duplicate the memory */
308 memcpy(elementStorageAddress, pv, SafeArrayGetElemsize(psa) );
312 ERR("SafeArray: Cannot lock array....\n");
313 return E_UNEXPECTED; /* UNDOC error condition */
316 TRACE("SafeArray: item put at adress %p.\n",elementStorageAddress);
317 return SafeArrayUnlock(psa);
321 /*************************************************************************
322 * SafeArrayGetElement (OLEAUT32.25)
323 * Return the data element corresponding the the given coordinate
325 HRESULT WINAPI SafeArrayGetElement(
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 */
337 if(! validCoordinate(rgIndices, psa)) /* Validate the index given */
338 return(DISP_E_BADINDEX);
340 if( SafeArrayLock(psa) == S_OK) {
342 /* Figure out the number of items to skip */
343 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
345 /* Figure out the number of byte to skip ... */
346 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
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;
356 *((BSTR*)pv) = pbstrReturnedStr;
358 else if( psa->fFeatures == FADF_VARIANT) {
359 HRESULT hr = VariantCopy(pv, elementStorageAddress);
361 SafeArrayUnlock(psa);
365 else if( isPointer(psa->fFeatures) ) /* simply copy the pointer */
366 *(PVOID*)pv = *((PVOID*)elementStorageAddress);
367 else /* copy the bytes */
368 memcpy(pv, elementStorageAddress, psa->cbElements );
371 ERR("SafeArray: Cannot lock array....\n");
372 return E_UNEXPECTED; /* UNDOC error condition */
375 return( SafeArrayUnlock(psa) );
378 /*************************************************************************
379 * SafeArrayGetUBound (OLEAUT32.19)
380 * return the UP bound for a given array dimension
382 HRESULT WINAPI SafeArrayGetUBound(
390 if(nDim > psa->cDims)
391 return DISP_E_BADINDEX;
394 return DISP_E_BADINDEX;
396 *plUbound = psa->rgsabound[nDim-1].lLbound +
397 psa->rgsabound[nDim-1].cElements - 1;
402 /*************************************************************************
403 * SafeArrayGetLBound (OLEAUT32.20)
404 * Return the LO bound for a given array dimension
406 HRESULT WINAPI SafeArrayGetLBound(
414 if(nDim > psa->cDims)
415 return DISP_E_BADINDEX;
418 return DISP_E_BADINDEX;
420 *plLbound = psa->rgsabound[nDim-1].lLbound;
424 /*************************************************************************
425 * SafeArrayGetDim (OLEAUT32.17)
426 * returns the number of dimension in the array
428 UINT WINAPI SafeArrayGetDim(
432 * A quick test in Windows shows that the behavior here for an invalid
433 * pointer is to return 0.
441 /*************************************************************************
442 * SafeArrayGetElemsize (OLEAUT32.18)
443 * Return the size of the element in the array
445 UINT WINAPI SafeArrayGetElemsize(
449 * A quick test in Windows shows that the behavior here for an invalid
450 * pointer is to return 0.
455 return psa->cbElements;
458 /*************************************************************************
459 * SafeArrayAccessData (OLEAUT32.23)
460 * increment the access count and return the data
462 HRESULT WINAPI SafeArrayAccessData(
471 hRes = SafeArrayLock(psa);
475 (*ppvData) = psa->pvData;
486 /*************************************************************************
487 * SafeArrayUnaccessData (OLEAUT32.24)
488 * Decrement the access count
490 HRESULT WINAPI SafeArrayUnaccessData(
496 return(SafeArrayUnlock(psa));
499 /************************************************************************
500 * SafeArrayPtrOfIndex (OLEAUT32.148)
501 * Return a pointer to the element at rgIndices
503 HRESULT WINAPI SafeArrayPtrOfIndex(
508 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
509 the desired one... */
514 if(! validCoordinate(rgIndices, psa))
515 return DISP_E_BADINDEX;
517 /* Figure out the number of items to skip */
518 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
520 *ppvData = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
525 /************************************************************************
526 * SafeArrayDestroyData (OLEAUT32.39)
527 * Frees the memory data bloc
529 HRESULT WINAPI SafeArrayDestroyData(
533 ULONG ulWholeArraySize; /* count spot in array */
534 ULONG ulDataIter; /* to iterate the data space */
540 return DISP_E_ARRAYISLOCKED;
542 ulWholeArraySize = getArraySize(psa);
544 if(isPointer(psa->fFeatures)) { /* release the pointers */
547 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
548 punk = *(IUnknown**)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
551 IUnknown_Release(punk);
555 else if(psa->fFeatures & FADF_BSTR) { /* deallocate the obj */
558 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
559 bstr = *(BSTR*)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
562 SysFreeString( bstr );
565 else if(psa->fFeatures & FADF_VARIANT) { /* deallocate the obj */
567 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
568 VariantClear((VARIANT*)((char *) psa->pvData+(ulDataIter*(psa->cbElements))));
572 /* check if this array is a Vector, in which case do not free the data
573 block since it has been allocated by AllocDescriptor and therefore
574 deserve to be freed by DestroyDescriptor */
575 if(!(psa->fFeatures & FADF_CREATEVECTOR)) { /* Set when we do CreateVector */
577 /* free the whole chunk */
578 if((hRes = HeapFree( GetProcessHeap(), 0, psa->pvData)) == 0) /*falied*/
579 return E_UNEXPECTED; /* UNDOC error condition */
587 /************************************************************************
588 * SafeArrayCopyData (OLEAUT32.412)
589 * Copy the psaSource's data block into psaTarget if dimension and size
592 HRESULT WINAPI SafeArrayCopyData(
593 SAFEARRAY *psaSource,
594 SAFEARRAY **psaTarget)
596 USHORT cDimCount; /* looper */
597 LONG lDelta; /* looper */
599 ULONG ulWholeArraySize; /* Number of item in SA */
602 if(! (validArg(psaSource) && validArg(*psaTarget)) )
605 if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(*psaTarget))
608 ulWholeArraySize = getArraySize(psaSource);
610 /* The two arrays boundaries must be of same lenght */
611 for(cDimCount=0;cDimCount < psaSource->cDims; cDimCount++)
612 if( psaSource->rgsabound[cDimCount].cElements !=
613 (*psaTarget)->rgsabound[cDimCount].cElements)
616 if( isPointer((*psaTarget)->fFeatures) ) { /* the target contains ptr
617 that must be released */
618 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
620 ((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
623 IUnknown_Release(punk);
627 else if( (*psaTarget)->fFeatures & FADF_BSTR) { /* the target contain BSTR
628 that must be freed */
629 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
631 *(BSTR*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
634 SysFreeString( bstr );
637 else if( (*psaTarget)->fFeatures & FADF_VARIANT) {
639 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
640 VariantClear((VARIANT*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements)));
644 return duplicateData(psaSource, psaTarget);
647 /************************************************************************
648 * SafeArrayDestroy (OLEAUT32.16)
649 * Deallocates all memory reserved for the SafeArray
651 HRESULT WINAPI SafeArrayDestroy(
660 return DISP_E_ARRAYISLOCKED;
662 if((hRes = SafeArrayDestroyData( psa )) == S_OK)
663 if((hRes = SafeArrayDestroyDescriptor( psa )) == S_OK)
666 return E_UNEXPECTED; /* UNDOC error condition */
669 /************************************************************************
670 * SafeArrayCopy (OLEAUT32.27)
671 * Make a dupplicate of a SafeArray
673 HRESULT WINAPI SafeArrayCopy(
679 ULONG ulWholeArraySize; /* size of the thing */
684 if((hRes=SafeArrayAllocDescriptor(psa->cDims, ppsaOut)) == S_OK){
686 /* Duplicate the SAFEARRAY struc */
687 memcpy(*ppsaOut, psa,
688 sizeof(*psa)+(sizeof(*(psa->rgsabound))*(psa->cDims-1)));
690 (*ppsaOut)->pvData = NULL; /* do not point to the same data area */
692 /* make sure the new safe array doesn't have the FADF_CREATEVECTOR flag,
693 because the data has not been allocated with the descriptor. */
694 (*ppsaOut)->fFeatures &= ~FADF_CREATEVECTOR;
696 /* Get the allocated memory size for source and allocate it for target */
697 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
698 dAllocSize = ulWholeArraySize*psa->cbElements;
701 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dAllocSize);
702 if( (*ppsaOut)->pvData != NULL) { /* HeapAlloc succeed */
704 if( (hRes=duplicateData(psa, ppsaOut)) != S_OK) { /* E_OUTOFMEMORY */
705 HeapFree(GetProcessHeap(), 0, (*ppsaOut)->pvData);
706 (*ppsaOut)->pvData = NULL;
707 SafeArrayDestroyDescriptor(*ppsaOut);
711 } else { /* failed to allocate or dupplicate... */
712 SafeArrayDestroyDescriptor(*ppsaOut);
713 return E_UNEXPECTED; /* UNDOC error condition */
715 } else { /* failed to allocate mem for descriptor */
716 return E_OUTOFMEMORY; /* UNDOC error condiftion */
722 /************************************************************************
723 * SafeArrayCreateVector (OLEAUT32.411)
724 * Creates a one dimension safearray where the data is next to the
725 * SAFEARRAY structure.
727 SAFEARRAY* WINAPI SafeArrayCreateVector(
734 /* Validate supported VARTYPE */
735 if ( (vt >= LAST_VARTYPE) ||
736 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
739 /* Allocate memory for the array descriptor and data contiguously */
740 if( FAILED( psa = HeapAlloc( GetProcessHeap(),
742 (sizeof(*psa) + (VARTYPE_SIZE[vt] * cElements))))) {
746 /* setup data members... */
747 psa->cDims = 1; /* always and forever */
748 psa->fFeatures = getFeatures(vt) | FADF_CREATEVECTOR; /* undocumented flag used by Microsoft */
750 psa->pvData = (BYTE*)psa + sizeof(*psa);
751 psa->cbElements = VARTYPE_SIZE[vt];
753 psa->rgsabound[0].cElements = cElements;
754 psa->rgsabound[0].lLbound = lLbound;
759 /************************************************************************
760 * SafeArrayRedim (OLEAUT32.40)
761 * Changes the caracteristics of the last dimension of the SafeArray
763 HRESULT WINAPI SafeArrayRedim(
765 SAFEARRAYBOUND *psaboundNew)
767 LONG lDelta; /* hold difference in size */
768 USHORT cDims=1; /* dims counter */
773 if( psa->cLocks > 0 )
774 return DISP_E_ARRAYISLOCKED;
776 if( psa->fFeatures & FADF_FIXEDSIZE )
779 if( SafeArrayLock(psa)==E_UNEXPECTED )
780 return E_UNEXPECTED;/* UNDOC error condition */
782 /* find the delta in number of array spot to apply to the new array */
783 lDelta = psaboundNew->cElements - psa->rgsabound[0].cElements;
784 for(; cDims < psa->cDims; cDims++)
785 /* delta in number of spot implied by modifying the last dimension */
786 lDelta *= psa->rgsabound[cDims].cElements;
788 TRACE("elements=%ld, Lbound=%ld (delta=%ld)\n", psaboundNew->cElements, psaboundNew->lLbound, lDelta);
790 if (lDelta == 0) { ;/* same size, maybe a change of lLbound, just set it */
792 } else /* need to enlarge (lDelta +) reduce (lDelta -) */
793 if(! resizeSafeArray(psa, lDelta))
794 return E_UNEXPECTED; /* UNDOC error condition */
796 /* the only modifyable dimension sits in [0] as the dimensions were reversed
797 at array creation time... */
798 psa->rgsabound[0].cElements = psaboundNew->cElements;
799 psa->rgsabound[0].lLbound = psaboundNew->lLbound;
801 return SafeArrayUnlock(psa);
804 /************************************************************************
805 * NOT WINDOWS API - SafeArray* Utility functions
806 ************************************************************************/
808 /************************************************************************
809 * Used to validate the SAFEARRAY type of arg
811 static BOOL validArg(
820 * Let's check for the null pointer just in case.
825 /* Check whether the size of the chunk makes sense... That's the only thing
826 I can think of now... */
828 psaSize = HeapSize(GetProcessHeap(), 0, psa);
830 /* uh, foreign heap. Better don't mess with it ! */
833 /* size of the descriptor when the SA is not created with CreateVector */
834 descSize = sizeof(*psa) + (sizeof(*sab) * (psa->cDims-1));
836 /* size of the descriptor + data when created with CreateVector */
837 fullSize = sizeof(*psa) + (psa->cbElements * psa->rgsabound[0].cElements);
839 return((psaSize >= descSize) || (psaSize >= fullSize));
842 /************************************************************************
843 * Used to reallocate memory
845 static BOOL resizeSafeArray(
849 ULONG ulWholeArraySize; /* use as multiplicator */
850 PVOID pvNewBlock = NULL;
854 ulWholeArraySize = getArraySize(psa);
856 if(lDelta < 0) { /* array needs to be shorthen */
857 if( isPointer(psa->fFeatures)) /* ptr that need to be released */
858 for(;lDelta < 0; lDelta++) {
860 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
863 IUnknown_Release(punk);
866 else if(psa->fFeatures & FADF_BSTR) /* BSTR that need to be freed */
867 for(;lDelta < 0; lDelta++) {
869 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
872 SysFreeString( bstr );
874 else if(psa->fFeatures & FADF_VARIANT)
875 for(;lDelta < 0; lDelta++) {
876 VariantClear((VARIANT*)((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements)));
880 if (!(psa->fFeatures & FADF_CREATEVECTOR))
882 /* Ok now, if we are enlarging the array, we *MUST* move the whole block
883 pointed to by pvData. If we are shorthening the array, this move is
884 optional but we do it anyway becuase the benefit is that we are
885 releasing to the system the unused memory */
887 if((pvNewBlock = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, psa->pvData,
888 (ulWholeArraySize + lDelta) * psa->cbElements)) == NULL)
889 return FALSE; /* TODO If we get here it means:
890 SHRINK situation : we've deleted the undesired
891 data and did not release the memory
892 GROWING situation: we've been unable to grow the array
897 /* Allocate a new block, because the previous data has been allocated with
898 the descriptor in SafeArrayCreateVector function. */
900 if((pvNewBlock = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
901 ulWholeArraySize * psa->cbElements)) == NULL)
904 psa->fFeatures &= ~FADF_CREATEVECTOR;
906 /* reassign to the new block of data */
907 psa->pvData = pvNewBlock;
911 /************************************************************************
912 * Used to set the fFeatures data member of the SAFEARRAY structure.
914 static INT getFeatures(
918 case VT_BSTR: return FADF_BSTR;
919 case VT_UNKNOWN: return FADF_UNKNOWN;
920 case VT_DISPATCH: return FADF_DISPATCH;
921 case VT_VARIANT: return FADF_VARIANT;
926 /************************************************************************
927 * Used to figure out if the fFeatures data member of the SAFEARRAY
928 * structure contain any information about the type of data stored...
930 static BOOL isPointer(
934 case FADF_UNKNOWN: return TRUE; /* those are pointers */
935 case FADF_DISPATCH: return TRUE;
940 /************************************************************************
941 * Used to calculate the displacement when accessing or modifying
942 * safearray data set.
944 * Parameters: - LONG *coor is the desired location in the multidimension
945 * table. Ex for a 3 dim table: coor[] = {1,2,3};
946 * - ULONG *mat is the format of the table. Ex for a 3 dim
947 * table mat[] = {4,4,4};
948 * - USHORT dim is the number of dimension of the SafeArray
950 static ULONG calcDisplacement(
958 for(iterDim=0; iterDim<dim; iterDim++)
959 /* the -mat[dim] bring coor[dim] relative to 0 for calculation */
960 res += ((coor[iterDim]-mat[iterDim].lLbound) *
961 endOfDim(coor, mat, iterDim+1, dim));
963 TRACE("SafeArray: calculated displacement is %lu.\n", res);
967 /************************************************************************
968 * Recursivity agent for calcDisplacement method. Used within Put and
980 return (endOfDim(coor, mat, dim+1, realDim) * mat[dim].cElements);
984 /************************************************************************
985 * Method used to validate the coordinate received in Put and Get
988 static BOOL validCoordinate(
997 if (!psa->cDims) return FALSE;
998 for(; iter<psa->cDims; iter++) {
999 TRACE("coor[%d]=%ld\n", iter, coor[iter]);
1000 if((hRes = SafeArrayGetLBound(psa, (iter+1), &lLBound)) != S_OK)
1002 if((hRes = SafeArrayGetUBound(psa, (iter+1), &lUBound)) != S_OK)
1005 if(lLBound > lUBound)
1008 if((coor[iter] < lLBound) || (coor[iter] > lUBound))
1014 /************************************************************************
1015 * Method used to calculate the number of cells of the SA
1017 static ULONG getArraySize(
1021 ULONG ulWholeArraySize = 1;
1023 for(cCount=0; cCount < psa->cDims; cCount++) /* foreach dimensions... */
1024 ulWholeArraySize *= psa->rgsabound[cCount].cElements;
1026 return ulWholeArraySize;
1030 /************************************************************************
1031 * Method used to handle data space dupplication for Copy32 and CopyData32
1033 static HRESULT duplicateData(
1035 SAFEARRAY **ppsaOut)
1037 ULONG ulWholeArraySize; /* size of the thing */
1040 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
1042 SafeArrayLock(*ppsaOut);
1044 if( isPointer(psa->fFeatures) ) { /* If datatype is object increment
1045 object's reference count */
1048 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1049 punk = *(IUnknown**)((char *) psa->pvData+(lDelta * psa->cbElements));
1052 IUnknown_AddRef(punk);
1055 /* Copy the source array data into target array */
1056 memcpy((*ppsaOut)->pvData, psa->pvData,
1057 ulWholeArraySize*psa->cbElements);
1060 else if( psa->fFeatures & FADF_BSTR ) { /* if datatype is BSTR allocate
1061 the BSTR in the new array */
1062 BSTR pbstrReAllocStr = NULL;
1064 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1065 if(( pbstrReAllocStr = SYSDUPSTRING(
1066 *(BSTR*)((char *) psa->pvData+(lDelta * psa->cbElements)))) == NULL) {
1068 SafeArrayUnlock(*ppsaOut);
1069 return E_OUTOFMEMORY;
1072 *((BSTR*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements))) =
1077 else if( psa->fFeatures & FADF_VARIANT ) {
1079 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1080 VariantCopy((VARIANT*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements)),
1081 (VARIANT*)((char *) psa->pvData+(lDelta * psa->cbElements)));
1085 else { /* Simply copy the source array data into target array */
1087 memcpy((*ppsaOut)->pvData, psa->pvData,
1088 ulWholeArraySize*psa->cbElements);
1091 SafeArrayUnlock(*ppsaOut);
1097 /************************************************************************
1098 * SafeArrayGetVarType (OLEAUT32.77)
1099 * Returns the VARTYPE stored in the given safearray
1101 HRESULT WINAPI SafeArrayGetVarType(
1105 HRESULT hr = E_INVALIDARG;
1106 VARTYPE vt = VT_EMPTY;
1108 /* const short VARTYPE_OFFSET = -4; */
1110 if (psa->fFeatures & FADF_HAVEVARTYPE)
1112 /* VT tag @ negative offset 4 in the array descriptor */
1113 FIXME("Returning VT_BSTR instead of VT_...\n");
1116 else if (psa->fFeatures & FADF_RECORD)
1120 else if (psa->fFeatures & FADF_BSTR)
1124 else if (psa->fFeatures & FADF_UNKNOWN)
1128 else if (psa->fFeatures & FADF_DISPATCH)
1132 else if (psa->fFeatures & FADF_VARIANT)
1143 TRACE("HRESULT = %08lx\n", hr);