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) {
361 hr = VariantCopy(pv, elementStorageAddress);
363 SafeArrayUnlock(psa);
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 );
373 ERR("SafeArray: Cannot lock array....\n");
374 return E_UNEXPECTED; /* UNDOC error condition */
377 return( SafeArrayUnlock(psa) );
380 /*************************************************************************
381 * SafeArrayGetUBound (OLEAUT32.19)
382 * return the UP bound for a given array dimension
384 HRESULT WINAPI SafeArrayGetUBound(
392 if(nDim > psa->cDims)
393 return DISP_E_BADINDEX;
396 return DISP_E_BADINDEX;
398 *plUbound = psa->rgsabound[nDim-1].lLbound +
399 psa->rgsabound[nDim-1].cElements - 1;
404 /*************************************************************************
405 * SafeArrayGetLBound (OLEAUT32.20)
406 * Return the LO bound for a given array dimension
408 HRESULT WINAPI SafeArrayGetLBound(
416 if(nDim > psa->cDims)
417 return DISP_E_BADINDEX;
420 return DISP_E_BADINDEX;
422 *plLbound = psa->rgsabound[nDim-1].lLbound;
426 /*************************************************************************
427 * SafeArrayGetDim (OLEAUT32.17)
428 * returns the number of dimension in the array
430 UINT WINAPI SafeArrayGetDim(
434 * A quick test in Windows shows that the behavior here for an invalid
435 * pointer is to return 0.
443 /*************************************************************************
444 * SafeArrayGetElemsize (OLEAUT32.18)
445 * Return the size of the element in the array
447 UINT WINAPI SafeArrayGetElemsize(
451 * A quick test in Windows shows that the behavior here for an invalid
452 * pointer is to return 0.
457 return psa->cbElements;
460 /*************************************************************************
461 * SafeArrayAccessData (OLEAUT32.23)
462 * increment the access count and return the data
464 HRESULT WINAPI SafeArrayAccessData(
473 hRes = SafeArrayLock(psa);
477 (*ppvData) = psa->pvData;
488 /*************************************************************************
489 * SafeArrayUnaccessData (OLEAUT32.24)
490 * Decrement the access count
492 HRESULT WINAPI SafeArrayUnaccessData(
498 return(SafeArrayUnlock(psa));
501 /************************************************************************
502 * SafeArrayPtrOfIndex (OLEAUT32.148)
503 * Return a pointer to the element at rgIndices
505 HRESULT WINAPI SafeArrayPtrOfIndex(
510 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
511 the desired one... */
516 if(! validCoordinate(rgIndices, psa))
517 return DISP_E_BADINDEX;
519 /* Figure out the number of items to skip */
520 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
522 *ppvData = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
527 /************************************************************************
528 * SafeArrayDestroyData (OLEAUT32.39)
529 * Frees the memory data bloc
531 HRESULT WINAPI SafeArrayDestroyData(
535 ULONG ulWholeArraySize; /* count spot in array */
536 ULONG ulDataIter; /* to iterate the data space */
542 return DISP_E_ARRAYISLOCKED;
544 ulWholeArraySize = getArraySize(psa);
546 if(isPointer(psa->fFeatures)) { /* release the pointers */
549 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
550 punk = *(IUnknown**)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
553 IUnknown_Release(punk);
557 else if(psa->fFeatures & FADF_BSTR) { /* deallocate the obj */
560 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
561 bstr = *(BSTR*)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
564 SysFreeString( bstr );
567 else if(psa->fFeatures & FADF_VARIANT) { /* deallocate the obj */
569 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
570 VariantClear((VARIANT*)((char *) psa->pvData+(ulDataIter*(psa->cbElements))));
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 */
579 /* free the whole chunk */
580 if((hRes = HeapFree( GetProcessHeap(), 0, psa->pvData)) == 0) /*falied*/
581 return E_UNEXPECTED; /* UNDOC error condition */
589 /************************************************************************
590 * SafeArrayCopyData (OLEAUT32.412)
591 * Copy the psaSource's data block into psaTarget if dimension and size
594 HRESULT WINAPI SafeArrayCopyData(
595 SAFEARRAY *psaSource,
596 SAFEARRAY **psaTarget)
598 USHORT cDimCount; /* looper */
599 LONG lDelta; /* looper */
601 ULONG ulWholeArraySize; /* Number of item in SA */
604 if(! (validArg(psaSource) && validArg(*psaTarget)) )
607 if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(*psaTarget))
610 ulWholeArraySize = getArraySize(psaSource);
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)
618 if( isPointer((*psaTarget)->fFeatures) ) { /* the target contains ptr
619 that must be released */
620 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
622 ((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
625 IUnknown_Release(punk);
629 else if( (*psaTarget)->fFeatures & FADF_BSTR) { /* the target contain BSTR
630 that must be freed */
631 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
633 *(BSTR*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
636 SysFreeString( bstr );
639 else if( (*psaTarget)->fFeatures & FADF_VARIANT) {
641 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
642 VariantClear((VARIANT*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements)));
646 return duplicateData(psaSource, psaTarget);
649 /************************************************************************
650 * SafeArrayDestroy (OLEAUT32.16)
651 * Deallocates all memory reserved for the SafeArray
653 HRESULT WINAPI SafeArrayDestroy(
662 return DISP_E_ARRAYISLOCKED;
664 if((hRes = SafeArrayDestroyData( psa )) == S_OK)
665 if((hRes = SafeArrayDestroyDescriptor( psa )) == S_OK)
668 return E_UNEXPECTED; /* UNDOC error condition */
671 /************************************************************************
672 * SafeArrayCopy (OLEAUT32.27)
673 * Make a dupplicate of a SafeArray
675 HRESULT WINAPI SafeArrayCopy(
681 ULONG ulWholeArraySize; /* size of the thing */
686 if((hRes=SafeArrayAllocDescriptor(psa->cDims, ppsaOut)) == S_OK){
688 /* Duplicate the SAFEARRAY struc */
689 memcpy(*ppsaOut, psa,
690 sizeof(*psa)+(sizeof(*(psa->rgsabound))*(psa->cDims-1)));
692 (*ppsaOut)->pvData = NULL; /* do not point to the same data area */
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;
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;
703 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dAllocSize);
704 if( (*ppsaOut)->pvData != NULL) { /* HeapAlloc succeed */
706 if( (hRes=duplicateData(psa, ppsaOut)) != S_OK) { /* E_OUTOFMEMORY */
707 HeapFree(GetProcessHeap(), 0, (*ppsaOut)->pvData);
708 (*ppsaOut)->pvData = NULL;
709 SafeArrayDestroyDescriptor(*ppsaOut);
713 } else { /* failed to allocate or dupplicate... */
714 SafeArrayDestroyDescriptor(*ppsaOut);
715 return E_UNEXPECTED; /* UNDOC error condition */
717 } else { /* failed to allocate mem for descriptor */
718 return E_OUTOFMEMORY; /* UNDOC error condiftion */
724 /************************************************************************
725 * SafeArrayCreateVector (OLEAUT32.411)
726 * Creates a one dimension safearray where the data is next to the
727 * SAFEARRAY structure.
729 SAFEARRAY* WINAPI SafeArrayCreateVector(
736 /* Validate supported VARTYPE */
737 if ( (vt >= LAST_VARTYPE) ||
738 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
741 /* Allocate memory for the array descriptor and data contiguously */
742 if( FAILED( psa = HeapAlloc( GetProcessHeap(),
744 (sizeof(*psa) + (VARTYPE_SIZE[vt] * cElements))))) {
748 /* setup data members... */
749 psa->cDims = 1; /* always and forever */
750 psa->fFeatures = getFeatures(vt) | FADF_CREATEVECTOR; /* undocumented flag used by Microsoft */
752 psa->pvData = (BYTE*)psa + sizeof(*psa);
753 psa->cbElements = VARTYPE_SIZE[vt];
755 psa->rgsabound[0].cElements = cElements;
756 psa->rgsabound[0].lLbound = lLbound;
761 /************************************************************************
762 * SafeArrayRedim (OLEAUT32.40)
763 * Changes the caracteristics of the last dimension of the SafeArray
765 HRESULT WINAPI SafeArrayRedim(
767 SAFEARRAYBOUND *psaboundNew)
769 LONG lDelta; /* hold difference in size */
770 USHORT cDims=1; /* dims counter */
775 if( psa->cLocks > 0 )
776 return DISP_E_ARRAYISLOCKED;
778 if( psa->fFeatures & FADF_FIXEDSIZE )
781 if( SafeArrayLock(psa)==E_UNEXPECTED )
782 return E_UNEXPECTED;/* UNDOC error condition */
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;
790 TRACE("elements=%ld, Lbound=%ld (delta=%ld)\n", psaboundNew->cElements, psaboundNew->lLbound, lDelta);
792 if (lDelta == 0) { ;/* same size, maybe a change of lLbound, just set it */
794 } else /* need to enlarge (lDelta +) reduce (lDelta -) */
795 if(! resizeSafeArray(psa, lDelta))
796 return E_UNEXPECTED; /* UNDOC error condition */
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;
803 return SafeArrayUnlock(psa);
806 /************************************************************************
807 * NOT WINDOWS API - SafeArray* Utility functions
808 ************************************************************************/
810 /************************************************************************
811 * Used to validate the SAFEARRAY type of arg
813 static BOOL validArg(
822 * Let's check for the null pointer just in case.
827 /* Check whether the size of the chunk makes sense... That's the only thing
828 I can think of now... */
830 psaSize = HeapSize(GetProcessHeap(), 0, psa);
832 /* uh, foreign heap. Better don't mess with it ! */
835 /* size of the descriptor when the SA is not created with CreateVector */
836 descSize = sizeof(*psa) + (sizeof(*sab) * (psa->cDims-1));
838 /* size of the descriptor + data when created with CreateVector */
839 fullSize = sizeof(*psa) + (psa->cbElements * psa->rgsabound[0].cElements);
841 return((psaSize >= descSize) || (psaSize >= fullSize));
844 /************************************************************************
845 * Used to reallocate memory
847 static BOOL resizeSafeArray(
851 ULONG ulWholeArraySize; /* use as multiplicator */
852 PVOID pvNewBlock = NULL;
856 ulWholeArraySize = getArraySize(psa);
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++) {
862 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
865 IUnknown_Release(punk);
868 else if(psa->fFeatures & FADF_BSTR) /* BSTR that need to be freed */
869 for(;lDelta < 0; lDelta++) {
871 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
874 SysFreeString( bstr );
876 else if(psa->fFeatures & FADF_VARIANT)
877 for(;lDelta < 0; lDelta++) {
878 VariantClear((VARIANT*)((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements)));
882 if (!(psa->fFeatures & FADF_CREATEVECTOR))
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 */
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
899 /* Allocate a new block, because the previous data has been allocated with
900 the descriptor in SafeArrayCreateVector function. */
902 if((pvNewBlock = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
903 ulWholeArraySize * psa->cbElements)) == NULL)
906 psa->fFeatures &= ~FADF_CREATEVECTOR;
908 /* reassign to the new block of data */
909 psa->pvData = pvNewBlock;
913 /************************************************************************
914 * Used to set the fFeatures data member of the SAFEARRAY structure.
916 static INT getFeatures(
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;
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...
932 static BOOL isPointer(
936 case FADF_UNKNOWN: return TRUE; /* those are pointers */
937 case FADF_DISPATCH: return TRUE;
942 /************************************************************************
943 * Used to calculate the displacement when accessing or modifying
944 * safearray data set.
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
952 static ULONG calcDisplacement(
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));
965 TRACE("SafeArray: calculated displacement is %lu.\n", res);
969 /************************************************************************
970 * Recursivity agent for calcDisplacement method. Used within Put and
982 return (endOfDim(coor, mat, dim+1, realDim) * mat[dim].cElements);
986 /************************************************************************
987 * Method used to validate the coordinate received in Put and Get
990 static BOOL validCoordinate(
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)
1004 if((hRes = SafeArrayGetUBound(psa, (iter+1), &lUBound)) != S_OK)
1007 if(lLBound > lUBound)
1010 if((coor[iter] < lLBound) || (coor[iter] > lUBound))
1016 /************************************************************************
1017 * Method used to calculate the number of cells of the SA
1019 static ULONG getArraySize(
1023 ULONG ulWholeArraySize = 1;
1025 for(cCount=0; cCount < psa->cDims; cCount++) /* foreach dimensions... */
1026 ulWholeArraySize *= psa->rgsabound[cCount].cElements;
1028 return ulWholeArraySize;
1032 /************************************************************************
1033 * Method used to handle data space dupplication for Copy32 and CopyData32
1035 static HRESULT duplicateData(
1037 SAFEARRAY **ppsaOut)
1039 ULONG ulWholeArraySize; /* size of the thing */
1042 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
1044 SafeArrayLock(*ppsaOut);
1046 if( isPointer(psa->fFeatures) ) { /* If datatype is object increment
1047 object's reference count */
1050 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1051 punk = *(IUnknown**)((char *) psa->pvData+(lDelta * psa->cbElements));
1054 IUnknown_AddRef(punk);
1057 /* Copy the source array data into target array */
1058 memcpy((*ppsaOut)->pvData, psa->pvData,
1059 ulWholeArraySize*psa->cbElements);
1062 else if( psa->fFeatures & FADF_BSTR ) { /* if datatype is BSTR allocate
1063 the BSTR in the new array */
1064 BSTR pbstrReAllocStr = NULL;
1066 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1067 if(( pbstrReAllocStr = SYSDUPSTRING(
1068 *(BSTR*)((char *) psa->pvData+(lDelta * psa->cbElements)))) == NULL) {
1070 SafeArrayUnlock(*ppsaOut);
1071 return E_OUTOFMEMORY;
1074 *((BSTR*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements))) =
1079 else if( psa->fFeatures & FADF_VARIANT ) {
1081 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1082 VariantCopy((VARIANT*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements)),
1083 (VARIANT*)((char *) psa->pvData+(lDelta * psa->cbElements)));
1087 else { /* Simply copy the source array data into target array */
1089 memcpy((*ppsaOut)->pvData, psa->pvData,
1090 ulWholeArraySize*psa->cbElements);
1093 SafeArrayUnlock(*ppsaOut);
1099 /************************************************************************
1100 * SafeArrayGetVarType (OLEAUT32.77)
1101 * Returns the VARTYPE stored in the given safearray
1103 HRESULT WINAPI SafeArrayGetVarType(
1107 HRESULT hr = E_INVALIDARG;
1108 VARTYPE vt = VT_EMPTY;
1110 /* const short VARTYPE_OFFSET = -4; */
1112 if (psa->fFeatures & FADF_HAVEVARTYPE)
1114 /* VT tag @ negative offset 4 in the array descriptor */
1115 FIXME("Returning VT_BSTR instead of VT_...\n");
1118 else if (psa->fFeatures & FADF_RECORD)
1122 else if (psa->fFeatures & FADF_BSTR)
1126 else if (psa->fFeatures & FADF_UNKNOWN)
1130 else if (psa->fFeatures & FADF_DISPATCH)
1134 else if (psa->fFeatures & FADF_VARIANT)
1145 TRACE("HRESULT = %08lx\n", hr);