1 /*************************************************************************
3 * SafeArray Implementation
5 * This file contains the implementation of the SafeArray interface.
7 * Copyright 1999 Sylvain St-Germain
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(ole);
34 #define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
36 /* Locally used methods */
38 endOfDim(LONG *coor, SAFEARRAYBOUND *mat, LONG dim, LONG realDim);
41 calcDisplacement(LONG *coor, SAFEARRAYBOUND *mat, LONG dim);
44 isPointer(USHORT feature);
47 getFeatures(VARTYPE vt);
50 validCoordinate(LONG *coor, SAFEARRAY *psa);
53 resizeSafeArray(SAFEARRAY *psa, LONG lDelta);
56 validArg(SAFEARRAY *psa);
59 getArraySize(SAFEARRAY *psa);
62 duplicateData(SAFEARRAY *psa, SAFEARRAY **ppsaOut);
64 /* Association between VARTYPE and their size.
65 A size of zero is defined for the unsupported types. */
67 #define VARTYPE_NOT_SUPPORTED 0
68 static const ULONG VARTYPE_SIZE[] =
70 /* this is taken from wtypes.h. Only [S]es are supported by the SafeArray */
71 VARTYPE_NOT_SUPPORTED, /* VT_EMPTY [V] [P] nothing */
72 VARTYPE_NOT_SUPPORTED, /* VT_NULL [V] [P] SQL style Nul */
73 2, /* VT_I2 [V][T][P][S] 2 byte signed int */
74 4, /* VT_I4 [V][T][P][S] 4 byte signed int */
75 4, /* VT_R4 [V][T][P][S] 4 byte real */
76 8, /* VT_R8 [V][T][P][S] 8 byte real */
77 8, /* VT_CY [V][T][P][S] currency */
78 8, /* VT_DATE [V][T][P][S] date */
79 sizeof(BSTR), /* VT_BSTR [V][T][P][S] OLE Automation string*/
80 sizeof(LPDISPATCH), /* VT_DISPATCH [V][T][P][S] IDispatch * */
81 4, /* VT_ERROR [V][T] [S] SCODE */
82 4, /* VT_BOOL [V][T][P][S] True=-1, False=0*/
83 sizeof(VARIANT), /* VT_VARIANT [V][T][P][S] VARIANT * */
84 sizeof(LPUNKNOWN), /* VT_UNKNOWN [V][T] [S] IUnknown * */
85 sizeof(DECIMAL), /* VT_DECIMAL [V][T] [S] 16 byte fixed point */
86 VARTYPE_NOT_SUPPORTED, /* no VARTYPE here..... */
87 VARTYPE_NOT_SUPPORTED, /* VT_I1 [T] signed char */
88 1, /* VT_UI1 [V][T][P][S] unsigned char */
89 VARTYPE_NOT_SUPPORTED, /* VT_UI2 [T][P] unsigned short */
90 VARTYPE_NOT_SUPPORTED, /* VT_UI4 [T][P] unsigned short */
91 VARTYPE_NOT_SUPPORTED, /* VT_I8 [T][P] signed 64-bit int */
92 VARTYPE_NOT_SUPPORTED, /* VT_UI8 [T][P] unsigned 64-bit int */
93 VARTYPE_NOT_SUPPORTED, /* VT_INT [T] signed machine int */
94 VARTYPE_NOT_SUPPORTED, /* VT_UINT [T] unsigned machine int */
95 VARTYPE_NOT_SUPPORTED, /* VT_VOID [T] C style void */
96 VARTYPE_NOT_SUPPORTED, /* VT_HRESULT [T] Standard return type */
97 VARTYPE_NOT_SUPPORTED, /* VT_PTR [T] pointer type */
98 VARTYPE_NOT_SUPPORTED, /* VT_SAFEARRAY [T] (use VT_ARRAY in VARIANT)*/
99 VARTYPE_NOT_SUPPORTED, /* VT_CARRAY [T] C style array */
100 VARTYPE_NOT_SUPPORTED, /* VT_USERDEFINED [T] user defined type */
101 VARTYPE_NOT_SUPPORTED, /* VT_LPSTR [T][P] null terminated string */
102 VARTYPE_NOT_SUPPORTED, /* VT_LPWSTR [T][P] wide null term string */
103 VARTYPE_NOT_SUPPORTED, /* VT_FILETIME [P] FILETIME */
104 VARTYPE_NOT_SUPPORTED, /* VT_BLOB [P] Length prefixed bytes */
105 VARTYPE_NOT_SUPPORTED, /* VT_STREAM [P] Name of stream follows */
106 VARTYPE_NOT_SUPPORTED, /* VT_STORAGE [P] Name of storage follows */
107 VARTYPE_NOT_SUPPORTED, /* VT_STREAMED_OBJECT[P] Stream contains an object*/
108 VARTYPE_NOT_SUPPORTED, /* VT_STORED_OBJECT [P] Storage contains object*/
109 VARTYPE_NOT_SUPPORTED, /* VT_BLOB_OBJECT [P] Blob contains an object*/
110 VARTYPE_NOT_SUPPORTED, /* VT_CF [P] Clipboard format */
111 VARTYPE_NOT_SUPPORTED, /* VT_CLSID [P] A Class ID */
112 VARTYPE_NOT_SUPPORTED, /* VT_VECTOR [P] simple counted array */
113 VARTYPE_NOT_SUPPORTED, /* VT_ARRAY [V] SAFEARRAY* */
114 VARTYPE_NOT_SUPPORTED /* VT_BYREF [V] void* for local use */
117 static const int LAST_VARTYPE = sizeof(VARTYPE_SIZE)/sizeof(VARTYPE_SIZE[0]);
120 /*************************************************************************
121 * SafeArrayAllocDescriptor (OLEAUT32.36)
122 * Allocate the appropriate amount of memory for the SafeArray descriptor
124 HRESULT WINAPI SafeArrayAllocDescriptor(
131 /* SAFEARRAY + SAFEARRAYBOUND * (cDims -1) ( -1 because there is already one
132 ( in SAFEARRAY struct */
133 allocSize = sizeof(**ppsaOut) + (sizeof(*sab) * (cDims-1));
135 /* Allocate memory for SAFEARRAY struc */
136 if(( (*ppsaOut)=HeapAlloc(
137 GetProcessHeap(), HEAP_ZERO_MEMORY, allocSize)) == NULL){
138 return(E_UNEXPECTED);
140 TRACE("SafeArray: %lu bytes allocated for descriptor.\n", allocSize);
145 /*************************************************************************
146 * SafeArrayAllocDescriptorEx (OLEAUT32.41)
147 * Allocate the appropriate amount of memory for the SafeArray descriptor
149 * This is a minimal implementation just to get things moving.
151 * The MSDN documentation on this doesn't tell us much.
153 HRESULT WINAPI SafeArrayAllocDescriptorEx(
158 if ( (vt >= LAST_VARTYPE) ||
159 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
162 return SafeArrayAllocDescriptor (cDims, ppsaOut);
165 /*************************************************************************
166 * SafeArrayAllocData (OLEAUT32.37)
167 * Allocate the appropriate amount of data for the SafeArray data
169 HRESULT WINAPI SafeArrayAllocData(
172 ULONG ulWholeArraySize; /* to store the size of the whole thing */
177 ulWholeArraySize = getArraySize(psa);
179 /* Allocate memory for the data itself */
180 if((psa->pvData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
181 psa->cbElements*ulWholeArraySize)) == NULL)
182 return(E_UNEXPECTED);
184 TRACE("SafeArray: %lu bytes allocated for data at %p (%lu objects).\n",
185 psa->cbElements*ulWholeArraySize, psa->pvData, ulWholeArraySize);
190 /*************************************************************************
191 * SafeArrayCreate (OLEAUT32.15)
192 * Create a SafeArray object by encapsulating AllocDescriptor and AllocData
194 SAFEARRAY* WINAPI SafeArrayCreate(
197 SAFEARRAYBOUND *rgsabound)
203 /* Validate supported VARTYPE */
204 if ( (vt >= LAST_VARTYPE) ||
205 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
208 /* Allocate memory for the array descriptor */
209 if( FAILED( hRes = SafeArrayAllocDescriptor(cDims, &psa)))
212 /* setup data members... */
214 psa->fFeatures = getFeatures(vt);
217 psa->cbElements= VARTYPE_SIZE[vt];
219 /* Invert the bounds ... */
220 for(cDim=0; cDim < psa->cDims; cDim++) {
221 psa->rgsabound[cDim].cElements = rgsabound[psa->cDims-cDim-1].cElements;
222 psa->rgsabound[cDim].lLbound = rgsabound[psa->cDims-cDim-1].lLbound;
225 /* allocate memory for the data... */
226 if( FAILED( hRes = SafeArrayAllocData(psa))) {
227 SafeArrayDestroyDescriptor(psa);
228 ERR("() : Failed to allocate the Safe Array data\n");
235 /*************************************************************************
236 * SafeArrayDestroyDescriptor (OLEAUT32.38)
237 * Frees the memory associated with the descriptor.
239 HRESULT WINAPI SafeArrayDestroyDescriptor(
242 /* Check for lockness before to free... */
244 return DISP_E_ARRAYISLOCKED;
246 /* The array is unlocked, then, deallocate memory */
247 if(HeapFree( GetProcessHeap(), 0, psa) == FALSE)
254 /*************************************************************************
255 * SafeArrayLock (OLEAUT32.21)
256 * Increment the lock counter
258 * Doc says (MSDN Library ) that psa->pvData should be made available (!= NULL)
259 * only when psa->cLocks is > 0... I don't get it since pvData is allocated
260 * before the array is locked, therefore
262 HRESULT WINAPI SafeArrayLock(
273 /*************************************************************************
274 * SafeArrayUnlock (OLEAUT32.22)
275 * Decrement the lock counter
277 HRESULT WINAPI SafeArrayUnlock(
290 /*************************************************************************
291 * SafeArrayPutElement (OLEAUT32.26)
292 * Set the data at the given coordinate
294 HRESULT WINAPI SafeArrayPutElement(
299 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
300 the desired one... */
301 PVOID elementStorageAddress = NULL; /* Adress to store the data */
303 /* Validate the index given */
304 if(! validCoordinate(rgIndices, psa))
305 return DISP_E_BADINDEX;
309 if( SafeArrayLock(psa) == S_OK) {
311 /* Figure out the number of items to skip */
312 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
314 /* Figure out the number of byte to skip ... */
315 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
317 if(isPointer(psa->fFeatures)) { /* increment ref count for this pointer */
319 *((PVOID*)elementStorageAddress) = *(PVOID*)pv;
320 IUnknown_AddRef( *(IUnknown**)pv);
324 if(psa->fFeatures == FADF_BSTR) { /* Create a new object */
325 BSTR pbstrReAllocStr = NULL;
327 ((pbstrReAllocStr = SYSDUPSTRING( (OLECHAR*)pv )) == NULL)) {
328 SafeArrayUnlock(psa);
329 return E_OUTOFMEMORY;
331 *((BSTR*)elementStorageAddress) = pbstrReAllocStr;
333 else if(psa->fFeatures == FADF_VARIANT) {
334 HRESULT hr = VariantCopy(elementStorageAddress, pv);
336 SafeArrayUnlock(psa);
340 else /* duplicate the memory */
341 memcpy(elementStorageAddress, pv, SafeArrayGetElemsize(psa) );
345 ERR("SafeArray: Cannot lock array....\n");
346 return E_UNEXPECTED; /* UNDOC error condition */
349 TRACE("SafeArray: item put at adress %p.\n",elementStorageAddress);
350 return SafeArrayUnlock(psa);
354 /*************************************************************************
355 * SafeArrayGetElement (OLEAUT32.25)
356 * Return the data element corresponding the the given coordinate
358 HRESULT WINAPI SafeArrayGetElement(
363 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
364 the desired one... */
365 PVOID elementStorageAddress = NULL; /* Adress to store the data */
370 if(! validCoordinate(rgIndices, psa)) /* Validate the index given */
371 return(DISP_E_BADINDEX);
373 if( SafeArrayLock(psa) == S_OK) {
375 /* Figure out the number of items to skip */
376 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
378 /* Figure out the number of byte to skip ... */
379 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
381 if( psa->fFeatures == FADF_BSTR) { /* reallocate the obj */
382 BSTR pbstrStoredStr = *(OLECHAR**)elementStorageAddress;
383 BSTR pbstrReturnedStr = NULL;
384 if( pbstrStoredStr &&
385 ((pbstrReturnedStr = SYSDUPSTRING( pbstrStoredStr )) == NULL) ) {
386 SafeArrayUnlock(psa);
387 return E_OUTOFMEMORY;
389 *((BSTR*)pv) = pbstrReturnedStr;
391 else if( psa->fFeatures == FADF_VARIANT) {
394 hr = VariantCopy(pv, elementStorageAddress);
396 SafeArrayUnlock(psa);
400 else if( isPointer(psa->fFeatures) ) /* simply copy the pointer */
401 *(PVOID*)pv = *((PVOID*)elementStorageAddress);
402 else /* copy the bytes */
403 memcpy(pv, elementStorageAddress, psa->cbElements );
406 ERR("SafeArray: Cannot lock array....\n");
407 return E_UNEXPECTED; /* UNDOC error condition */
410 return( SafeArrayUnlock(psa) );
413 /*************************************************************************
414 * SafeArrayGetUBound (OLEAUT32.19)
415 * return the UP bound for a given array dimension
417 HRESULT WINAPI SafeArrayGetUBound(
425 if(nDim > psa->cDims)
426 return DISP_E_BADINDEX;
429 return DISP_E_BADINDEX;
431 *plUbound = psa->rgsabound[nDim-1].lLbound +
432 psa->rgsabound[nDim-1].cElements - 1;
437 /*************************************************************************
438 * SafeArrayGetLBound (OLEAUT32.20)
439 * Return the LO bound for a given array dimension
441 HRESULT WINAPI SafeArrayGetLBound(
449 if(nDim > psa->cDims)
450 return DISP_E_BADINDEX;
453 return DISP_E_BADINDEX;
455 *plLbound = psa->rgsabound[nDim-1].lLbound;
459 /*************************************************************************
460 * SafeArrayGetDim (OLEAUT32.17)
461 * returns the number of dimension in the array
463 UINT WINAPI SafeArrayGetDim(
467 * A quick test in Windows shows that the behavior here for an invalid
468 * pointer is to return 0.
476 /*************************************************************************
477 * SafeArrayGetElemsize (OLEAUT32.18)
478 * Return the size of the element in the array
480 UINT WINAPI SafeArrayGetElemsize(
484 * A quick test in Windows shows that the behavior here for an invalid
485 * pointer is to return 0.
490 return psa->cbElements;
493 /*************************************************************************
494 * SafeArrayAccessData (OLEAUT32.23)
495 * increment the access count and return the data
497 HRESULT WINAPI SafeArrayAccessData(
506 hRes = SafeArrayLock(psa);
510 (*ppvData) = psa->pvData;
521 /*************************************************************************
522 * SafeArrayUnaccessData (OLEAUT32.24)
523 * Decrement the access count
525 HRESULT WINAPI SafeArrayUnaccessData(
531 return(SafeArrayUnlock(psa));
534 /************************************************************************
535 * SafeArrayPtrOfIndex (OLEAUT32.148)
536 * Return a pointer to the element at rgIndices
538 HRESULT WINAPI SafeArrayPtrOfIndex(
543 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
544 the desired one... */
549 if(! validCoordinate(rgIndices, psa))
550 return DISP_E_BADINDEX;
552 /* Although it is dangerous to do this without having a lock, it is not
553 * illegal. Microsoft do warn of the danger.
556 /* Figure out the number of items to skip */
557 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
559 *ppvData = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
564 /************************************************************************
565 * SafeArrayDestroyData (OLEAUT32.39)
566 * Frees the memory data bloc
568 HRESULT WINAPI SafeArrayDestroyData(
572 ULONG ulWholeArraySize; /* count spot in array */
573 ULONG ulDataIter; /* to iterate the data space */
579 return DISP_E_ARRAYISLOCKED;
581 if(psa->pvData==NULL)
584 ulWholeArraySize = getArraySize(psa);
586 if(isPointer(psa->fFeatures)) { /* release the pointers */
589 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
590 punk = *(IUnknown**)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
593 IUnknown_Release(punk);
597 else if(psa->fFeatures & FADF_BSTR) { /* deallocate the obj */
600 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
601 bstr = *(BSTR*)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
604 SysFreeString( bstr );
607 else if(psa->fFeatures & FADF_VARIANT) { /* deallocate the obj */
609 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
610 VariantClear((VARIANT*)((char *) psa->pvData+(ulDataIter*(psa->cbElements))));
614 /* check if this array is a Vector, in which case do not free the data
615 block since it has been allocated by AllocDescriptor and therefore
616 deserve to be freed by DestroyDescriptor */
617 if(!(psa->fFeatures & FADF_CREATEVECTOR)) { /* Set when we do CreateVector */
619 /* free the whole chunk */
620 if((hRes = HeapFree( GetProcessHeap(), 0, psa->pvData)) == 0) /*falied*/
621 return E_UNEXPECTED; /* UNDOC error condition */
629 /************************************************************************
630 * SafeArrayCopyData (OLEAUT32.412)
631 * Copy the psaSource's data block into psaTarget if dimension and size
634 HRESULT WINAPI SafeArrayCopyData(
635 SAFEARRAY *psaSource,
636 SAFEARRAY **psaTarget)
638 USHORT cDimCount; /* looper */
639 LONG lDelta; /* looper */
641 ULONG ulWholeArraySize; /* Number of item in SA */
644 if(! (validArg(psaSource) && validArg(*psaTarget)) )
647 if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(*psaTarget))
650 ulWholeArraySize = getArraySize(psaSource);
652 /* The two arrays boundaries must be of same lenght */
653 for(cDimCount=0;cDimCount < psaSource->cDims; cDimCount++)
654 if( psaSource->rgsabound[cDimCount].cElements !=
655 (*psaTarget)->rgsabound[cDimCount].cElements)
658 if( isPointer((*psaTarget)->fFeatures) ) { /* the target contains ptr
659 that must be released */
660 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
662 ((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
665 IUnknown_Release(punk);
669 else if( (*psaTarget)->fFeatures & FADF_BSTR) { /* the target contain BSTR
670 that must be freed */
671 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
673 *(BSTR*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
676 SysFreeString( bstr );
679 else if( (*psaTarget)->fFeatures & FADF_VARIANT) {
681 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
682 VariantClear((VARIANT*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements)));
686 return duplicateData(psaSource, psaTarget);
689 /************************************************************************
690 * SafeArrayDestroy (OLEAUT32.16)
691 * Deallocates all memory reserved for the SafeArray
693 HRESULT WINAPI SafeArrayDestroy(
702 return DISP_E_ARRAYISLOCKED;
704 if((hRes = SafeArrayDestroyData( psa )) == S_OK)
705 if((hRes = SafeArrayDestroyDescriptor( psa )) == S_OK)
708 return E_UNEXPECTED; /* UNDOC error condition */
711 /************************************************************************
712 * SafeArrayCopy (OLEAUT32.27)
713 * Make a dupplicate of a SafeArray
715 HRESULT WINAPI SafeArrayCopy(
721 ULONG ulWholeArraySize; /* size of the thing */
726 if((hRes=SafeArrayAllocDescriptor(psa->cDims, ppsaOut)) == S_OK){
728 /* Duplicate the SAFEARRAY struc */
729 memcpy(*ppsaOut, psa,
730 sizeof(*psa)+(sizeof(*(psa->rgsabound))*(psa->cDims-1)));
732 (*ppsaOut)->pvData = NULL; /* do not point to the same data area */
734 /* make sure the new safe array doesn't have the FADF_CREATEVECTOR flag,
735 because the data has not been allocated with the descriptor. */
736 (*ppsaOut)->fFeatures &= ~FADF_CREATEVECTOR;
738 /* Get the allocated memory size for source and allocate it for target */
739 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
740 dAllocSize = ulWholeArraySize*psa->cbElements;
743 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dAllocSize);
744 if( (*ppsaOut)->pvData != NULL) { /* HeapAlloc succeed */
746 if( (hRes=duplicateData(psa, ppsaOut)) != S_OK) { /* E_OUTOFMEMORY */
747 HeapFree(GetProcessHeap(), 0, (*ppsaOut)->pvData);
748 (*ppsaOut)->pvData = NULL;
749 SafeArrayDestroyDescriptor(*ppsaOut);
753 } else { /* failed to allocate or dupplicate... */
754 SafeArrayDestroyDescriptor(*ppsaOut);
755 return E_UNEXPECTED; /* UNDOC error condition */
757 } else { /* failed to allocate mem for descriptor */
758 return E_OUTOFMEMORY; /* UNDOC error condiftion */
764 /************************************************************************
765 * SafeArrayCreateVector (OLEAUT32.411)
766 * Creates a one dimension safearray where the data is next to the
767 * SAFEARRAY structure.
769 SAFEARRAY* WINAPI SafeArrayCreateVector(
776 /* Validate supported VARTYPE */
777 if ( (vt >= LAST_VARTYPE) ||
778 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
781 /* Allocate memory for the array descriptor and data contiguously */
782 if( FAILED( psa = HeapAlloc( GetProcessHeap(),
784 (sizeof(*psa) + (VARTYPE_SIZE[vt] * cElements))))) {
788 /* setup data members... */
789 psa->cDims = 1; /* always and forever */
790 psa->fFeatures = getFeatures(vt) | FADF_CREATEVECTOR; /* undocumented flag used by Microsoft */
792 psa->pvData = (BYTE*)psa + sizeof(*psa);
793 psa->cbElements = VARTYPE_SIZE[vt];
795 psa->rgsabound[0].cElements = cElements;
796 psa->rgsabound[0].lLbound = lLbound;
801 /************************************************************************
802 * SafeArrayRedim (OLEAUT32.40)
803 * Changes the caracteristics of the last dimension of the SafeArray
805 HRESULT WINAPI SafeArrayRedim(
807 SAFEARRAYBOUND *psaboundNew)
809 LONG lDelta; /* hold difference in size */
810 USHORT cDims=1; /* dims counter */
815 if( psa->cLocks > 0 )
816 return DISP_E_ARRAYISLOCKED;
818 if( psa->fFeatures & FADF_FIXEDSIZE )
821 if( SafeArrayLock(psa)==E_UNEXPECTED )
822 return E_UNEXPECTED;/* UNDOC error condition */
824 /* find the delta in number of array spot to apply to the new array */
825 lDelta = psaboundNew->cElements - psa->rgsabound[0].cElements;
826 for(; cDims < psa->cDims; cDims++)
827 /* delta in number of spot implied by modifying the last dimension */
828 lDelta *= psa->rgsabound[cDims].cElements;
830 TRACE("elements=%ld, Lbound=%ld (delta=%ld)\n", psaboundNew->cElements, psaboundNew->lLbound, lDelta);
832 if (lDelta == 0) { ;/* same size, maybe a change of lLbound, just set it */
834 } else /* need to enlarge (lDelta +) reduce (lDelta -) */
835 if(! resizeSafeArray(psa, lDelta))
836 return E_UNEXPECTED; /* UNDOC error condition */
838 /* the only modifyable dimension sits in [0] as the dimensions were reversed
839 at array creation time... */
840 psa->rgsabound[0].cElements = psaboundNew->cElements;
841 psa->rgsabound[0].lLbound = psaboundNew->lLbound;
843 return SafeArrayUnlock(psa);
846 /************************************************************************
847 * NOT WINDOWS API - SafeArray* Utility functions
848 ************************************************************************/
850 /************************************************************************
851 * Used to validate the SAFEARRAY type of arg
853 static BOOL validArg(
862 * Let's check for the null pointer just in case.
867 /* Check whether the size of the chunk makes sense... That's the only thing
868 I can think of now... */
870 psaSize = HeapSize(GetProcessHeap(), 0, psa);
872 /* uh, foreign heap. Better don't mess with it ! */
875 /* size of the descriptor when the SA is not created with CreateVector */
876 descSize = sizeof(*psa) + (sizeof(*sab) * (psa->cDims-1));
878 /* size of the descriptor + data when created with CreateVector */
879 fullSize = sizeof(*psa) + (psa->cbElements * psa->rgsabound[0].cElements);
881 return((psaSize >= descSize) || (psaSize >= fullSize));
884 /************************************************************************
885 * Used to reallocate memory
887 static BOOL resizeSafeArray(
891 ULONG ulWholeArraySize; /* use as multiplicator */
892 PVOID pvNewBlock = NULL;
896 ulWholeArraySize = getArraySize(psa);
898 if(lDelta < 0) { /* array needs to be shorthen */
899 if( isPointer(psa->fFeatures)) /* ptr that need to be released */
900 for(;lDelta < 0; lDelta++) {
902 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
905 IUnknown_Release(punk);
908 else if(psa->fFeatures & FADF_BSTR) /* BSTR that need to be freed */
909 for(;lDelta < 0; lDelta++) {
911 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
914 SysFreeString( bstr );
916 else if(psa->fFeatures & FADF_VARIANT)
917 for(;lDelta < 0; lDelta++) {
918 VariantClear((VARIANT*)((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements)));
922 if (!(psa->fFeatures & FADF_CREATEVECTOR))
924 /* Ok now, if we are enlarging the array, we *MUST* move the whole block
925 pointed to by pvData. If we are shorthening the array, this move is
926 optional but we do it anyway becuase the benefit is that we are
927 releasing to the system the unused memory */
929 if((pvNewBlock = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, psa->pvData,
930 (ulWholeArraySize + lDelta) * psa->cbElements)) == NULL)
931 return FALSE; /* TODO If we get here it means:
932 SHRINK situation : we've deleted the undesired
933 data and did not release the memory
934 GROWING situation: we've been unable to grow the array
939 /* Allocate a new block, because the previous data has been allocated with
940 the descriptor in SafeArrayCreateVector function. */
942 if((pvNewBlock = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
943 ulWholeArraySize * psa->cbElements)) == NULL)
946 psa->fFeatures &= ~FADF_CREATEVECTOR;
948 /* reassign to the new block of data */
949 psa->pvData = pvNewBlock;
953 /************************************************************************
954 * Used to set the fFeatures data member of the SAFEARRAY structure.
956 static INT getFeatures(
960 case VT_BSTR: return FADF_BSTR;
961 case VT_UNKNOWN: return FADF_UNKNOWN;
962 case VT_DISPATCH: return FADF_DISPATCH;
963 case VT_VARIANT: return FADF_VARIANT;
968 /************************************************************************
969 * Used to figure out if the fFeatures data member of the SAFEARRAY
970 * structure contain any information about the type of data stored...
972 static BOOL isPointer(
976 case FADF_UNKNOWN: return TRUE; /* those are pointers */
977 case FADF_DISPATCH: return TRUE;
982 /************************************************************************
983 * Used to calculate the displacement when accessing or modifying
984 * safearray data set.
986 * Parameters: - LONG *coor is the desired location in the multidimension
987 * table. Ex for a 3 dim table: coor[] = {1,2,3};
988 * - ULONG *mat is the format of the table. Ex for a 3 dim
989 * table mat[] = {4,4,4};
990 * - USHORT dim is the number of dimension of the SafeArray
992 static ULONG calcDisplacement(
1000 for(iterDim=0; iterDim<dim; iterDim++)
1001 /* the -mat[dim] bring coor[dim] relative to 0 for calculation */
1002 res += ((coor[iterDim]-mat[iterDim].lLbound) *
1003 endOfDim(coor, mat, iterDim+1, dim));
1005 TRACE("SafeArray: calculated displacement is %lu.\n", res);
1009 /************************************************************************
1010 * Recursivity agent for calcDisplacement method. Used within Put and
1013 static INT endOfDim(
1015 SAFEARRAYBOUND *mat,
1022 return (endOfDim(coor, mat, dim+1, realDim) * mat[dim].cElements);
1026 /************************************************************************
1027 * Method used to validate the coordinate received in Put and Get
1030 static BOOL validCoordinate(
1039 if (!psa->cDims) return FALSE;
1040 for(; iter<psa->cDims; iter++) {
1041 TRACE("coor[%d]=%ld\n", iter, coor[iter]);
1042 if((hRes = SafeArrayGetLBound(psa, (iter+1), &lLBound)) != S_OK)
1044 if((hRes = SafeArrayGetUBound(psa, (iter+1), &lUBound)) != S_OK)
1047 if(lLBound > lUBound)
1050 if((coor[iter] < lLBound) || (coor[iter] > lUBound))
1056 /************************************************************************
1057 * Method used to calculate the number of cells of the SA
1059 static ULONG getArraySize(
1063 ULONG ulWholeArraySize = 1;
1065 for(cCount=0; cCount < psa->cDims; cCount++) /* foreach dimensions... */
1066 ulWholeArraySize *= psa->rgsabound[cCount].cElements;
1068 return ulWholeArraySize;
1072 /************************************************************************
1073 * Method used to handle data space dupplication for Copy32 and CopyData32
1075 static HRESULT duplicateData(
1077 SAFEARRAY **ppsaOut)
1079 ULONG ulWholeArraySize; /* size of the thing */
1082 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
1084 SafeArrayLock(*ppsaOut);
1086 if( isPointer(psa->fFeatures) ) { /* If datatype is object increment
1087 object's reference count */
1090 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1091 punk = *(IUnknown**)((char *) psa->pvData+(lDelta * psa->cbElements));
1094 IUnknown_AddRef(punk);
1097 /* Copy the source array data into target array */
1098 memcpy((*ppsaOut)->pvData, psa->pvData,
1099 ulWholeArraySize*psa->cbElements);
1102 else if( psa->fFeatures & FADF_BSTR ) { /* if datatype is BSTR allocate
1103 the BSTR in the new array */
1104 BSTR pbstrReAllocStr = NULL;
1106 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1107 if(( pbstrReAllocStr = SYSDUPSTRING(
1108 *(BSTR*)((char *) psa->pvData+(lDelta * psa->cbElements)))) == NULL) {
1110 SafeArrayUnlock(*ppsaOut);
1111 return E_OUTOFMEMORY;
1114 *((BSTR*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements))) =
1119 else if( psa->fFeatures & FADF_VARIANT ) {
1121 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1122 VariantCopy((VARIANT*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements)),
1123 (VARIANT*)((char *) psa->pvData+(lDelta * psa->cbElements)));
1127 else { /* Simply copy the source array data into target array */
1129 memcpy((*ppsaOut)->pvData, psa->pvData,
1130 ulWholeArraySize*psa->cbElements);
1133 SafeArrayUnlock(*ppsaOut);
1139 /************************************************************************
1140 * SafeArrayGetVartype (OLEAUT32.77)
1141 * Returns the VARTYPE stored in the given safearray
1143 HRESULT WINAPI SafeArrayGetVartype(
1147 HRESULT hr = E_INVALIDARG;
1148 VARTYPE vt = VT_EMPTY;
1150 /* const short VARTYPE_OFFSET = -4; */
1152 if (psa->fFeatures & FADF_HAVEVARTYPE)
1154 /* VT tag @ negative offset 4 in the array descriptor */
1155 FIXME("Returning VT_BSTR instead of VT_...\n");
1158 else if (psa->fFeatures & FADF_RECORD)
1162 else if (psa->fFeatures & FADF_BSTR)
1166 else if (psa->fFeatures & FADF_UNKNOWN)
1170 else if (psa->fFeatures & FADF_DISPATCH)
1174 else if (psa->fFeatures & FADF_VARIANT)
1185 TRACE("HRESULT = %08lx\n", hr);