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
23 /* Memory Layout of a SafeArray:
25 * -0x10: start of memory.
26 * -0x10: GUID for VT_DISPATCH and VT_UNKNOWN safearrays (if FADF_HAVEIID)
27 * -0x04: DWORD varianttype; (for all others, except VT_RECORD) (if FADF_HAVEVARTYPE)
28 * -0x4: IRecordInfo* iface; (if FADF_RECORD, for VT_RECORD (can be NULL))
30 * 0x10: SAFEARRAYBOUNDS[0...]
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(ole);
44 #define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
46 /* Locally used methods */
48 calcDisplacement(LONG *coor, SAFEARRAYBOUND *mat, LONG dim);
51 isPointer(USHORT feature);
54 getFeatures(VARTYPE vt);
57 validCoordinate(LONG *coor, SAFEARRAY *psa);
60 resizeSafeArray(SAFEARRAY *psa, LONG lDelta);
63 validArg(SAFEARRAY *psa);
66 getArraySize(SAFEARRAY *psa);
69 duplicateData(SAFEARRAY *psa, SAFEARRAY *ppsaOut);
71 /* Association between VARTYPE and their size.
72 A size of zero is defined for the unsupported types. */
74 #define VARTYPE_NOT_SUPPORTED 0
75 static const ULONG VARTYPE_SIZE[] =
77 /* this is taken from wtypes.h. Only [S]es are supported by the SafeArray */
78 VARTYPE_NOT_SUPPORTED, /* VT_EMPTY [V] [P] nothing */
79 VARTYPE_NOT_SUPPORTED, /* VT_NULL [V] [P] SQL style Nul */
80 2, /* VT_I2 [V][T][P][S] 2 byte signed int */
81 4, /* VT_I4 [V][T][P][S] 4 byte signed int */
82 4, /* VT_R4 [V][T][P][S] 4 byte real */
83 8, /* VT_R8 [V][T][P][S] 8 byte real */
84 8, /* VT_CY [V][T][P][S] currency */
85 8, /* VT_DATE [V][T][P][S] date */
86 sizeof(BSTR), /* VT_BSTR [V][T][P][S] OLE Automation string*/
87 sizeof(LPDISPATCH), /* VT_DISPATCH [V][T][P][S] IDispatch * */
88 4, /* VT_ERROR [V][T] [S] SCODE */
89 2, /* VT_BOOL [V][T][P][S] True=-1, False=0*/
90 sizeof(VARIANT), /* VT_VARIANT [V][T][P][S] VARIANT * */
91 sizeof(LPUNKNOWN), /* VT_UNKNOWN [V][T] [S] IUnknown * */
92 sizeof(DECIMAL), /* VT_DECIMAL [V][T] [S] 16 byte fixed point */
93 VARTYPE_NOT_SUPPORTED, /* no VARTYPE here..... */
94 1, /* VT_I1 [T] [S] signed char */
95 1, /* VT_UI1 [V][T][P][S] unsigned char */
96 2, /* VT_UI2 [T][P][S] unsigned short */
97 4, /* VT_UI4 [T][P][S] unsigned int */
98 VARTYPE_NOT_SUPPORTED, /* VT_I8 [T][P] signed 64-bit int */
99 VARTYPE_NOT_SUPPORTED, /* VT_UI8 [T][P] unsigned 64-bit int */
100 sizeof(INT), /* VT_INT [T] signed machine int */
101 sizeof(UINT), /* VT_UINT [T] unsigned machine int */
102 VARTYPE_NOT_SUPPORTED, /* VT_VOID [T] C style void */
103 VARTYPE_NOT_SUPPORTED, /* VT_HRESULT [T] Standard return type */
104 VARTYPE_NOT_SUPPORTED, /* VT_PTR [T] pointer type */
105 VARTYPE_NOT_SUPPORTED, /* VT_SAFEARRAY [T] (use VT_ARRAY in VARIANT)*/
106 VARTYPE_NOT_SUPPORTED, /* VT_CARRAY [T] C style array */
107 VARTYPE_NOT_SUPPORTED, /* VT_USERDEFINED [T] user defined type */
108 VARTYPE_NOT_SUPPORTED, /* VT_LPSTR [T][P] null terminated string */
109 VARTYPE_NOT_SUPPORTED, /* VT_LPWSTR [T][P] wide null term string */
110 VARTYPE_NOT_SUPPORTED, /* 32 */
111 VARTYPE_NOT_SUPPORTED, /* 33 */
112 VARTYPE_NOT_SUPPORTED, /* 34 */
113 VARTYPE_NOT_SUPPORTED, /* 35 */
114 VARTYPE_NOT_SUPPORTED, /* VT_RECORD record */
115 VARTYPE_NOT_SUPPORTED, /* 37 */
116 VARTYPE_NOT_SUPPORTED, /* 38 */
117 VARTYPE_NOT_SUPPORTED, /* 39 */
118 VARTYPE_NOT_SUPPORTED, /* 40 */
119 VARTYPE_NOT_SUPPORTED, /* 41 */
120 VARTYPE_NOT_SUPPORTED, /* 42 */
121 VARTYPE_NOT_SUPPORTED, /* 43 */
122 VARTYPE_NOT_SUPPORTED, /* 44 */
123 VARTYPE_NOT_SUPPORTED, /* 45 */
124 VARTYPE_NOT_SUPPORTED, /* 46 */
125 VARTYPE_NOT_SUPPORTED, /* 47 */
126 VARTYPE_NOT_SUPPORTED, /* 48 */
127 VARTYPE_NOT_SUPPORTED, /* 49 */
128 VARTYPE_NOT_SUPPORTED, /* 50 */
129 VARTYPE_NOT_SUPPORTED, /* 51 */
130 VARTYPE_NOT_SUPPORTED, /* 52 */
131 VARTYPE_NOT_SUPPORTED, /* 53 */
132 VARTYPE_NOT_SUPPORTED, /* 54 */
133 VARTYPE_NOT_SUPPORTED, /* 55 */
134 VARTYPE_NOT_SUPPORTED, /* 56 */
135 VARTYPE_NOT_SUPPORTED, /* 57 */
136 VARTYPE_NOT_SUPPORTED, /* 58 */
137 VARTYPE_NOT_SUPPORTED, /* 59 */
138 VARTYPE_NOT_SUPPORTED, /* 60 */
139 VARTYPE_NOT_SUPPORTED, /* 61 */
140 VARTYPE_NOT_SUPPORTED, /* 62 */
141 VARTYPE_NOT_SUPPORTED, /* 63 */
142 VARTYPE_NOT_SUPPORTED, /* VT_FILETIME [P] FILETIME */
143 VARTYPE_NOT_SUPPORTED, /* VT_BLOB [P] Length prefixed bytes */
144 VARTYPE_NOT_SUPPORTED, /* VT_STREAM [P] Name of stream follows */
145 VARTYPE_NOT_SUPPORTED, /* VT_STORAGE [P] Name of storage follows */
146 VARTYPE_NOT_SUPPORTED, /* VT_STREAMED_OBJECT[P] Stream contains an object*/
147 VARTYPE_NOT_SUPPORTED, /* VT_STORED_OBJECT [P] Storage contains object*/
148 VARTYPE_NOT_SUPPORTED, /* VT_BLOB_OBJECT [P] Blob contains an object*/
149 VARTYPE_NOT_SUPPORTED, /* VT_CF [P] Clipboard format */
150 VARTYPE_NOT_SUPPORTED, /* VT_CLSID [P] A Class ID */
153 static const int LAST_VARTYPE = sizeof(VARTYPE_SIZE)/sizeof(VARTYPE_SIZE[0]);
156 /*************************************************************************
157 * SafeArrayAllocDescriptor (OLEAUT32.36)
158 * Allocate the appropriate amount of memory for the SafeArray descriptor
160 HRESULT WINAPI SafeArrayAllocDescriptor(
168 if (!cDims || cDims >= 0x10000) /* 65536 appears to be the limit */
173 /* GUID + SAFEARRAY + SAFEARRAYBOUND * (cDims -1)
174 * ( -1 because there is already one ( in SAFEARRAY struct
176 allocSize = sizeof(GUID) + sizeof(**ppsaOut) + (sizeof(*sab) * (cDims-1));
178 /* Allocate memory for SAFEARRAY struc */
179 ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, allocSize);
181 return E_OUTOFMEMORY;
182 *ppsaOut = (SAFEARRAY *)(ptr + sizeof(GUID));
183 (*ppsaOut)->cDims = cDims;
184 TRACE("(%d): %lu bytes allocated for descriptor.\n", cDims, allocSize);
189 /*************************************************************************
190 * SafeArrayAllocDescriptorEx (OLEAUT32.41)
191 * Allocate the appropriate amount of memory for the SafeArray descriptor
192 * and also store information about the vartype before the returned pointer.
194 HRESULT WINAPI SafeArrayAllocDescriptorEx(
201 hres = SafeArrayAllocDescriptor (cDims, ppsaOut);
207 (*ppsaOut)->fFeatures = FADF_HAVEIID;
208 SafeArraySetIID( *ppsaOut, &IID_IDispatch);
211 (*ppsaOut)->fFeatures = FADF_HAVEIID;
212 SafeArraySetIID( *ppsaOut, &IID_IUnknown);
215 (*ppsaOut)->fFeatures = FADF_RECORD;
218 (*ppsaOut)->fFeatures = FADF_HAVEVARTYPE;
219 ((DWORD*)*ppsaOut)[-1] = vt;
225 /*************************************************************************
226 * SafeArrayAllocData (OLEAUT32.37)
227 * Allocate the appropriate amount of data for the SafeArray data
229 HRESULT WINAPI SafeArrayAllocData(
232 ULONG ulWholeArraySize; /* to store the size of the whole thing */
237 ulWholeArraySize = getArraySize(psa);
239 /* Allocate memory for the data itself */
240 if((psa->pvData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
241 psa->cbElements*ulWholeArraySize)) == NULL)
242 return(E_UNEXPECTED);
244 TRACE("SafeArray: %lu bytes allocated for data at %p (%lu objects).\n",
245 psa->cbElements*ulWholeArraySize, psa->pvData, ulWholeArraySize);
250 /*************************************************************************
251 * SafeArrayCreate (OLEAUT32.15)
252 * Create a SafeArray object by encapsulating AllocDescriptor and AllocData
254 SAFEARRAY* WINAPI SafeArrayCreate(
257 SAFEARRAYBOUND *rgsabound)
263 TRACE("(%d, %d, %p)\n", vt, cDims, rgsabound);
265 /* Validate supported VARTYPE */
266 if ( (vt >= LAST_VARTYPE) ||
267 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
270 /* Allocate memory for the array descriptor */
271 if( FAILED( hRes = SafeArrayAllocDescriptorEx(vt, cDims, &psa)))
274 /* setup data members... */
277 case VT_BSTR: psa->fFeatures |= FADF_BSTR;break;
278 case VT_UNKNOWN: psa->fFeatures |= FADF_UNKNOWN;break;
279 case VT_DISPATCH: psa->fFeatures |= FADF_DISPATCH;break;
280 case VT_VARIANT: psa->fFeatures |= FADF_VARIANT;break;
285 psa->cbElements= VARTYPE_SIZE[vt];
287 /* Invert the bounds ... */
288 for(cDim=0; cDim < psa->cDims; cDim++) {
289 psa->rgsabound[cDim].cElements = rgsabound[psa->cDims-cDim-1].cElements;
290 psa->rgsabound[cDim].lLbound = rgsabound[psa->cDims-cDim-1].lLbound;
293 /* allocate memory for the data... */
294 if( FAILED( hRes = SafeArrayAllocData(psa))) {
295 SafeArrayDestroyDescriptor(psa);
296 ERR("() : Failed to allocate the Safe Array data\n");
303 /*************************************************************************
304 * SafeArrayDestroyDescriptor (OLEAUT32.38)
305 * Frees the memory associated with the descriptor.
307 HRESULT WINAPI SafeArrayDestroyDescriptor(
312 /* Check for lockness before to free... */
314 return DISP_E_ARRAYISLOCKED;
316 /* The array is unlocked, then, deallocate memory */
318 if(HeapFree( GetProcessHeap(), 0, ptr) == FALSE)
324 /*************************************************************************
325 * SafeArrayLock (OLEAUT32.21)
326 * Increment the lock counter
328 * Doc says (MSDN Library ) that psa->pvData should be made available (!= NULL)
329 * only when psa->cLocks is > 0... I don't get it since pvData is allocated
330 * before the array is locked, therefore
332 HRESULT WINAPI SafeArrayLock(
343 /*************************************************************************
344 * SafeArrayUnlock (OLEAUT32.22)
345 * Decrement the lock counter
347 HRESULT WINAPI SafeArrayUnlock(
360 /*************************************************************************
361 * SafeArrayPutElement (OLEAUT32.26)
362 * Set the data at the given coordinate
364 HRESULT WINAPI SafeArrayPutElement(
369 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
370 the desired one... */
371 PVOID elementStorageAddress = NULL; /* Address to store the data */
373 /* Validate the index given */
374 if(! validCoordinate(rgIndices, psa))
375 return DISP_E_BADINDEX;
379 if( SafeArrayLock(psa) == S_OK) {
381 /* Figure out the number of items to skip */
382 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
384 /* Figure out the number of byte to skip ... */
385 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
387 if(isPointer(psa->fFeatures)) { /* increment ref count for this pointer */
389 *((PVOID*)elementStorageAddress) = *(PVOID*)pv;
390 IUnknown_AddRef( *(IUnknown**)pv);
394 if(psa->fFeatures & FADF_BSTR) { /* Create a new object */
395 BSTR pbstrReAllocStr = NULL;
397 ((pbstrReAllocStr = SYSDUPSTRING( (OLECHAR*)pv )) == NULL)) {
398 SafeArrayUnlock(psa);
399 return E_OUTOFMEMORY;
401 *((BSTR*)elementStorageAddress) = pbstrReAllocStr;
403 else if(psa->fFeatures & FADF_VARIANT) {
404 HRESULT hr = VariantCopy(elementStorageAddress, pv);
406 SafeArrayUnlock(psa);
410 else /* duplicate the memory */
411 memcpy(elementStorageAddress, pv, SafeArrayGetElemsize(psa) );
415 ERR("SafeArray: Cannot lock array....\n");
416 return E_UNEXPECTED; /* UNDOC error condition */
419 TRACE("SafeArray: item put at address %p.\n",elementStorageAddress);
420 return SafeArrayUnlock(psa);
424 /*************************************************************************
425 * SafeArrayGetElement (OLEAUT32.25)
426 * Return the data element corresponding the the given coordinate
428 HRESULT WINAPI SafeArrayGetElement(
433 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
434 the desired one... */
435 PVOID elementStorageAddress = NULL; /* Address to store the data */
440 if(! validCoordinate(rgIndices, psa)) /* Validate the index given */
441 return(DISP_E_BADINDEX);
443 if( SafeArrayLock(psa) == S_OK) {
445 /* Figure out the number of items to skip */
446 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
448 /* Figure out the number of byte to skip ... */
449 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
451 if( psa->fFeatures & FADF_BSTR) { /* reallocate the obj */
452 BSTR pbstrStoredStr = *(OLECHAR**)elementStorageAddress;
453 BSTR pbstrReturnedStr = NULL;
454 if( pbstrStoredStr &&
455 ((pbstrReturnedStr = SYSDUPSTRING( pbstrStoredStr )) == NULL) ) {
456 SafeArrayUnlock(psa);
457 return E_OUTOFMEMORY;
459 *((BSTR*)pv) = pbstrReturnedStr;
461 else if( psa->fFeatures & FADF_VARIANT) {
464 hr = VariantCopy(pv, elementStorageAddress);
466 SafeArrayUnlock(psa);
470 else if( isPointer(psa->fFeatures) ) /* simply copy the pointer */
471 *(PVOID*)pv = *((PVOID*)elementStorageAddress);
472 else /* copy the bytes */
473 memcpy(pv, elementStorageAddress, psa->cbElements );
476 ERR("SafeArray: Cannot lock array....\n");
477 return E_UNEXPECTED; /* UNDOC error condition */
480 return( SafeArrayUnlock(psa) );
483 /*************************************************************************
484 * SafeArrayGetUBound (OLEAUT32.19)
485 * return the UP bound for a given array dimension
486 * Note: [0] is the right most (least significant) array index!
488 HRESULT WINAPI SafeArrayGetUBound(
496 if(nDim > psa->cDims)
497 return DISP_E_BADINDEX;
500 return DISP_E_BADINDEX;
502 *plUbound = psa->rgsabound[psa->cDims - nDim].lLbound +
503 psa->rgsabound[psa->cDims - nDim].cElements - 1;
508 /*************************************************************************
509 * SafeArrayGetLBound (OLEAUT32.20)
510 * Return the LO bound for a given array dimension
511 * Note: [0] is the right most (least significant) array index!
513 HRESULT WINAPI SafeArrayGetLBound(
521 if(nDim > psa->cDims)
522 return DISP_E_BADINDEX;
525 return DISP_E_BADINDEX;
527 *plLbound = psa->rgsabound[psa->cDims - nDim].lLbound;
531 /*************************************************************************
532 * SafeArrayGetDim (OLEAUT32.17)
533 * returns the number of dimension in the array
535 UINT WINAPI SafeArrayGetDim(
539 * A quick test in Windows shows that the behavior here for an invalid
540 * pointer is to return 0.
548 /*************************************************************************
549 * SafeArrayGetElemsize (OLEAUT32.18)
550 * Return the size of the element in the array
552 UINT WINAPI SafeArrayGetElemsize(
556 * A quick test in Windows shows that the behavior here for an invalid
557 * pointer is to return 0.
562 return psa->cbElements;
565 /*************************************************************************
566 * SafeArrayAccessData (OLEAUT32.23)
567 * increment the access count and return the data
569 HRESULT WINAPI SafeArrayAccessData(
578 hRes = SafeArrayLock(psa);
582 (*ppvData) = psa->pvData;
593 /*************************************************************************
594 * SafeArrayUnaccessData (OLEAUT32.24)
595 * Decrement the access count
597 HRESULT WINAPI SafeArrayUnaccessData(
603 return(SafeArrayUnlock(psa));
606 /************************************************************************
607 * SafeArrayPtrOfIndex (OLEAUT32.148)
608 * Return a pointer to the element at rgIndices
610 HRESULT WINAPI SafeArrayPtrOfIndex(
615 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
616 the desired one... */
621 if(! validCoordinate(rgIndices, psa))
622 return DISP_E_BADINDEX;
624 /* Although it is dangerous to do this without having a lock, it is not
625 * illegal. Microsoft do warn of the danger.
628 /* Figure out the number of items to skip */
629 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
631 *ppvData = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
636 /************************************************************************
637 * SafeArrayDestroyData (OLEAUT32.39)
638 * Frees the memory data bloc
640 HRESULT WINAPI SafeArrayDestroyData(
644 ULONG ulWholeArraySize; /* count spot in array */
645 ULONG ulDataIter; /* to iterate the data space */
651 return DISP_E_ARRAYISLOCKED;
653 if(psa->pvData==NULL)
656 ulWholeArraySize = getArraySize(psa);
658 if(isPointer(psa->fFeatures)) { /* release the pointers */
661 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
662 punk = *(IUnknown**)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
665 IUnknown_Release(punk);
669 else if(psa->fFeatures & FADF_BSTR) { /* deallocate the obj */
672 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
673 bstr = *(BSTR*)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
676 SysFreeString( bstr );
679 else if(psa->fFeatures & FADF_VARIANT) { /* deallocate the obj */
681 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
682 VariantClear((VARIANT*)((char *) psa->pvData+(ulDataIter*(psa->cbElements))));
686 /* check if this array is a Vector, in which case do not free the data
687 block since it has been allocated by AllocDescriptor and therefore
688 deserve to be freed by DestroyDescriptor */
689 if(!(psa->fFeatures & FADF_CREATEVECTOR)) { /* Set when we do CreateVector */
691 /* free the whole chunk */
692 if((hRes = HeapFree( GetProcessHeap(), 0, psa->pvData)) == 0) /*failed*/
693 return E_UNEXPECTED; /* UNDOC error condition */
701 /************************************************************************
702 * SafeArrayCopyData (OLEAUT32.412)
703 * Copy the psaSource's data block into psaTarget if dimension and size
706 HRESULT WINAPI SafeArrayCopyData(
707 SAFEARRAY *psaSource,
708 SAFEARRAY *psaTarget)
710 USHORT cDimCount; /* looper */
711 LONG lDelta; /* looper */
713 ULONG ulWholeArraySize; /* Number of item in SA */
716 if(! (validArg(psaSource) && validArg(psaTarget)) )
719 if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(psaTarget))
722 ulWholeArraySize = getArraySize(psaSource);
724 /* The two arrays boundaries must be of same length */
725 for(cDimCount=0;cDimCount < psaSource->cDims; cDimCount++)
726 if( psaSource->rgsabound[cDimCount].cElements !=
727 psaTarget->rgsabound[cDimCount].cElements)
730 if( isPointer(psaTarget->fFeatures) ) { /* the target contains ptr
731 that must be released */
732 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
734 ((char *) psaTarget->pvData + (lDelta * psaTarget->cbElements));
737 IUnknown_Release(punk);
741 else if( psaTarget->fFeatures & FADF_BSTR) { /* the target contain BSTR
742 that must be freed */
743 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
745 *(BSTR*)((char *) psaTarget->pvData + (lDelta * psaTarget->cbElements));
748 SysFreeString( bstr );
751 else if( psaTarget->fFeatures & FADF_VARIANT) {
753 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
754 VariantClear((VARIANT*)((char *) psaTarget->pvData + (lDelta * psaTarget->cbElements)));
758 return duplicateData(psaSource, psaTarget);
761 /************************************************************************
762 * SafeArrayDestroy (OLEAUT32.16)
763 * Deallocates all memory reserved for the SafeArray
765 HRESULT WINAPI SafeArrayDestroy(
774 return DISP_E_ARRAYISLOCKED;
776 if((hRes = SafeArrayDestroyData( psa )) == S_OK)
777 if((hRes = SafeArrayDestroyDescriptor( psa )) == S_OK)
780 return E_UNEXPECTED; /* UNDOC error condition */
783 /************************************************************************
784 * SafeArrayCopy (OLEAUT32.27)
785 * Make a dupplicate of a SafeArray
787 HRESULT WINAPI SafeArrayCopy(
793 ULONG ulWholeArraySize; /* size of the thing */
798 if((hRes=SafeArrayAllocDescriptor(psa->cDims, ppsaOut)) == S_OK){
800 /* Duplicate the SAFEARRAY struct */
801 memcpy(*ppsaOut, psa,
802 sizeof(*psa)+(sizeof(*(psa->rgsabound))*(psa->cDims-1)));
804 /* If the features that use storage before the SAFEARRAY struct are
805 * enabled, also copy this memory range. Flags have been copied already.
807 if (psa->fFeatures & (FADF_HAVEIID | FADF_HAVEVARTYPE))
808 memcpy(((GUID*)*ppsaOut)-1, ((GUID*)psa)-1, sizeof(GUID));
810 /* Copy the IRecordInfo* reference */
811 if (psa->fFeatures & FADF_RECORD) {
814 ri = ((IRecordInfo**)psa)[-1];
816 ((IRecordInfo**)*ppsaOut)[-1] = ri;
817 IRecordInfo_AddRef(ri);
821 (*ppsaOut)->pvData = NULL; /* do not point to the same data area */
823 /* make sure the new safe array doesn't have the FADF_CREATEVECTOR flag,
824 because the data has not been allocated with the descriptor. */
825 (*ppsaOut)->fFeatures &= ~FADF_CREATEVECTOR;
827 /* Get the allocated memory size for source and allocate it for target */
828 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
829 dAllocSize = ulWholeArraySize*psa->cbElements;
832 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dAllocSize);
833 if( (*ppsaOut)->pvData != NULL) { /* HeapAlloc succeed */
835 if( (hRes=duplicateData(psa, *ppsaOut)) != S_OK) { /* E_OUTOFMEMORY */
836 HeapFree(GetProcessHeap(), 0, (*ppsaOut)->pvData);
837 (*ppsaOut)->pvData = NULL;
838 SafeArrayDestroyDescriptor(*ppsaOut);
842 } else { /* failed to allocate or dupplicate... */
843 SafeArrayDestroyDescriptor(*ppsaOut);
844 return E_UNEXPECTED; /* UNDOC error condition */
846 } else { /* failed to allocate mem for descriptor */
847 return E_OUTOFMEMORY; /* UNDOC error condiftion */
853 /************************************************************************
854 * SafeArrayCreateVector (OLEAUT32.411)
855 * Creates a one dimension safearray where the data is next to the
856 * SAFEARRAY structure.
858 SAFEARRAY* WINAPI SafeArrayCreateVector(
866 TRACE("%d, %ld, %ld\n", vt, lLbound, cElements);
868 /* Validate supported VARTYPE */
869 if ( (vt >= LAST_VARTYPE) ||
870 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
873 /* Allocate memory for the array descriptor and data contiguously */
874 ptr = HeapAlloc( GetProcessHeap(),
876 (sizeof(GUID)+sizeof(*psa)+(VARTYPE_SIZE[vt]*cElements)));
879 psa = (SAFEARRAY*)(ptr+sizeof(GUID));
881 /* setup data members... */
882 psa->cDims = 1; /* always and forever */
883 psa->fFeatures = getFeatures(vt) | FADF_CREATEVECTOR; /* undocumented flag used by Microsoft */
885 psa->pvData = (BYTE*)psa + sizeof(*psa);
886 psa->cbElements = VARTYPE_SIZE[vt];
888 psa->rgsabound[0].cElements = cElements;
889 psa->rgsabound[0].lLbound = lLbound;
894 /************************************************************************
895 * SafeArrayRedim (OLEAUT32.40)
896 * Changes the caracteristics of the last dimension of the SafeArray
898 HRESULT WINAPI SafeArrayRedim(
900 SAFEARRAYBOUND *psaboundNew)
902 LONG lDelta; /* hold difference in size */
903 USHORT cDims=1; /* dims counter */
908 if( psa->cLocks > 0 )
909 return DISP_E_ARRAYISLOCKED;
911 if( psa->fFeatures & FADF_FIXEDSIZE )
914 if( SafeArrayLock(psa)==E_UNEXPECTED )
915 return E_UNEXPECTED;/* UNDOC error condition */
917 /* find the delta in number of array spot to apply to the new array */
918 lDelta = psaboundNew->cElements - psa->rgsabound[0].cElements;
919 for(; cDims < psa->cDims; cDims++)
920 /* delta in number of spot implied by modifying the last dimension */
921 lDelta *= psa->rgsabound[cDims].cElements;
923 TRACE("elements=%ld, Lbound=%ld (delta=%ld)\n", psaboundNew->cElements, psaboundNew->lLbound, lDelta);
925 if (lDelta == 0) { ;/* same size, maybe a change of lLbound, just set it */
927 } else /* need to enlarge (lDelta +) reduce (lDelta -) */
928 if(! resizeSafeArray(psa, lDelta))
929 return E_UNEXPECTED; /* UNDOC error condition */
931 /* the only modifyable dimension sits in [0] as the dimensions were reversed
932 at array creation time... */
933 psa->rgsabound[0].cElements = psaboundNew->cElements;
934 psa->rgsabound[0].lLbound = psaboundNew->lLbound;
936 return SafeArrayUnlock(psa);
939 /************************************************************************
940 * NOT WINDOWS API - SafeArray* Utility functions
941 ************************************************************************/
943 /************************************************************************
944 * Used to validate the SAFEARRAY type of arg
946 static BOOL validArg(
955 * Let's check for the null pointer just in case.
960 /* Check whether the size of the chunk makes sense... That's the only thing
961 I can think of now... */
963 psaSize = HeapSize(GetProcessHeap(), 0, ((IID*)psa)-1);
965 /* uh, foreign heap. Better don't mess with it ! */
968 /* size of the descriptor when the SA is not created with CreateVector */
969 descSize = sizeof(GUID) + sizeof(*psa) + (sizeof(*sab) * (psa->cDims-1));
971 /* size of the descriptor + data when created with CreateVector */
972 fullSize = sizeof(*psa) + (psa->cbElements * psa->rgsabound[0].cElements);
974 return((psaSize >= descSize) || (psaSize >= fullSize));
977 /************************************************************************
978 * Used to reallocate memory
980 static BOOL resizeSafeArray(
984 ULONG ulWholeArraySize; /* use as multiplicator */
985 PVOID pvNewBlock = NULL;
989 ulWholeArraySize = getArraySize(psa);
991 if(lDelta < 0) { /* array needs to be shorthen */
992 if( isPointer(psa->fFeatures)) /* ptr that need to be released */
993 for(;lDelta < 0; lDelta++) {
995 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
998 IUnknown_Release(punk);
1001 else if(psa->fFeatures & FADF_BSTR) /* BSTR that need to be freed */
1002 for(;lDelta < 0; lDelta++) {
1004 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
1007 SysFreeString( bstr );
1009 else if(psa->fFeatures & FADF_VARIANT)
1010 for(;lDelta < 0; lDelta++) {
1011 VariantClear((VARIANT*)((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements)));
1015 if (!(psa->fFeatures & FADF_CREATEVECTOR))
1017 /* Ok now, if we are enlarging the array, we *MUST* move the whole block
1018 pointed to by pvData. If we are shorthening the array, this move is
1019 optional but we do it anyway becuase the benefit is that we are
1020 releasing to the system the unused memory */
1022 if((pvNewBlock = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, psa->pvData,
1023 (ulWholeArraySize + lDelta) * psa->cbElements)) == NULL)
1024 return FALSE; /* TODO If we get here it means:
1025 SHRINK situation : we've deleted the undesired
1026 data and did not release the memory
1027 GROWING situation: we've been unable to grow the array
1032 /* Allocate a new block, because the previous data has been allocated with
1033 the descriptor in SafeArrayCreateVector function. */
1035 if((pvNewBlock = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1036 ulWholeArraySize * psa->cbElements)) == NULL)
1039 psa->fFeatures &= ~FADF_CREATEVECTOR;
1041 /* reassign to the new block of data */
1042 psa->pvData = pvNewBlock;
1046 /************************************************************************
1047 * Used to set the fFeatures data member of the SAFEARRAY structure.
1049 static INT getFeatures(VARTYPE vt) {
1051 case VT_BSTR: return FADF_BSTR;
1052 case VT_UNKNOWN: return FADF_UNKNOWN;
1053 case VT_DISPATCH: return FADF_DISPATCH;
1054 case VT_VARIANT: return FADF_VARIANT;
1059 /************************************************************************
1060 * Used to figure out if the fFeatures data member of the SAFEARRAY
1061 * structure contain any information about the type of data stored...
1063 static BOOL isPointer(
1067 case FADF_UNKNOWN: return TRUE; /* those are pointers */
1068 case FADF_DISPATCH: return TRUE;
1073 /************************************************************************
1074 * Used to calculate the displacement when accessing or modifying
1075 * safearray data set.
1077 * Parameters: - LONG *coor is the desired location in the multidimension
1078 * table. Ex for a 3 dim table: coor[] = {1,2,3};
1079 * - ULONG *mat is the format of the table. Ex for a 3 dim
1080 * table mat[] = {4,4,4};
1081 * - USHORT dim is the number of dimension of the SafeArray
1083 static ULONG calcDisplacement(
1085 SAFEARRAYBOUND *mat,
1091 TRACE("dims is %ld\n", dim);
1093 for (iterDim = dim-1; iterDim >= 0; iterDim--) {
1094 TRACE("%ld: lbound is %ld, adding %ld\n", iterDim, mat[dim-iterDim-1].lLbound,(coor[iterDim] - mat[dim-iterDim-1].lLbound));
1095 res += (coor[iterDim] - mat[dim-iterDim-1].lLbound);
1098 res *= mat[dim-iterDim].cElements;
1101 TRACE("SafeArray: calculated displacement is %lu.\n", res);
1105 /************************************************************************
1106 * Method used to validate the coordinate received in Put and Get
1109 static BOOL validCoordinate(
1118 if (!psa->cDims) { FIXME("no dims?\n");return FALSE; }
1119 for(; iter<psa->cDims; iter++) {
1120 TRACE("coor[%d]=%ld\n", iter, coor[iter]);
1121 if((hRes = SafeArrayGetLBound(psa, (iter+1), &lLBound)) != S_OK) {
1122 FIXME("No lbound?\n");
1125 if((hRes = SafeArrayGetUBound(psa, (iter+1), &lUBound)) != S_OK) {
1126 FIXME("No ubound?\n");
1129 if(lLBound > lUBound) {
1130 FIXME("lbound larger than ubound?\n");
1134 if((coor[iter] < lLBound) || (coor[iter] > lUBound)) {
1135 FIXME("coordinate %ld not within %ld - %ld\n",coor[iter], lLBound, lUBound);
1142 /************************************************************************
1143 * Method used to calculate the number of cells of the SA
1145 static ULONG getArraySize(
1149 ULONG ulWholeArraySize = 1;
1151 for(cCount=0; cCount < psa->cDims; cCount++) /* foreach dimensions... */
1152 ulWholeArraySize *= psa->rgsabound[cCount].cElements;
1154 return ulWholeArraySize;
1158 /************************************************************************
1159 * Method used to handle data space dupplication for Copy32 and CopyData32
1161 static HRESULT duplicateData(
1165 ULONG ulWholeArraySize; /* size of the thing */
1168 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
1170 SafeArrayLock(ppsaOut);
1172 if( isPointer(psa->fFeatures) ) { /* If datatype is object increment
1173 object's reference count */
1176 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1177 punk = *(IUnknown**)((char *) psa->pvData+(lDelta * psa->cbElements));
1180 IUnknown_AddRef(punk);
1183 /* Copy the source array data into target array */
1184 memcpy(ppsaOut->pvData, psa->pvData, ulWholeArraySize*psa->cbElements);
1187 else if( psa->fFeatures & FADF_BSTR ) { /* if datatype is BSTR allocate
1188 the BSTR in the new array */
1189 BSTR pbstrReAllocStr = NULL;
1191 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1192 if(( pbstrReAllocStr = SYSDUPSTRING(
1193 *(BSTR*)((char *) psa->pvData+(lDelta * psa->cbElements)))) == NULL) {
1195 SafeArrayUnlock(ppsaOut);
1196 return E_OUTOFMEMORY;
1199 *((BSTR*)((char *)ppsaOut->pvData+(lDelta * psa->cbElements))) =
1204 else if( psa->fFeatures & FADF_VARIANT ) {
1206 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1207 VariantCopy((VARIANT*)((char *) ppsaOut->pvData+(lDelta * psa->cbElements)),
1208 (VARIANT*)((char *) psa->pvData+(lDelta * psa->cbElements)));
1211 } else { /* Simply copy the source array data into target array */
1212 memcpy(ppsaOut->pvData, psa->pvData, ulWholeArraySize*psa->cbElements);
1214 SafeArrayUnlock(ppsaOut);
1219 /************************************************************************
1220 * SafeArrayGetVartype (OLEAUT32.77)
1221 * Returns the VARTYPE stored in the given safearray
1223 HRESULT WINAPI SafeArrayGetVartype(
1227 if (psa->fFeatures & FADF_HAVEVARTYPE)
1229 /* VT tag @ negative offset 4 in the array descriptor */
1230 *pvt = ((DWORD*)psa)[-1];
1234 if (psa->fFeatures & FADF_RECORD)
1240 if (psa->fFeatures & FADF_BSTR)
1246 if (psa->fFeatures & FADF_UNKNOWN)
1252 if (psa->fFeatures & FADF_DISPATCH)
1254 *pvt = VT_UNKNOWN; /* Yes, checked against windows */
1258 if (psa->fFeatures & FADF_VARIANT)
1263 if (psa->fFeatures & FADF_HAVEIID)
1265 /* We could check the IID here, but Windows apparently does not
1266 * do that and returns VT_UNKNOWN for VT_DISPATCH too.
1272 WARN("No vt found for safearray\n");
1273 return E_INVALIDARG;
1276 /************************************************************************
1277 * SafeArraySetIID (OLEAUT32.57)
1279 HRESULT WINAPI SafeArraySetIID(SAFEARRAY *arr, REFIID riid) {
1280 IID *xiid = ((IID*)arr)-1;
1281 TRACE("(%p, %s).\n",arr,debugstr_guid(riid));
1283 if (!arr || !(arr->fFeatures & FADF_HAVEIID))
1284 return E_INVALIDARG;
1285 memcpy(xiid, riid, sizeof(GUID));
1289 /************************************************************************
1290 * SafeArrayGetIID (OLEAUT32.67)
1292 HRESULT WINAPI SafeArrayGetIID(SAFEARRAY *arr, IID *riid) {
1293 IID *xiid = ((IID*)arr)-1;
1294 TRACE("(%p, %s).\n",arr,debugstr_guid(riid));
1296 if (!arr || !(arr->fFeatures & FADF_HAVEIID))
1297 return E_INVALIDARG;
1298 memcpy(riid, xiid, sizeof(GUID));
1302 /************************************************************************
1303 * SafeArraySetRecordInfo (OLEAUT32.44)
1305 HRESULT WINAPI SafeArraySetRecordInfo(SAFEARRAY *arr, IRecordInfo *iface) {
1306 LPRECORDINFO oldiface;
1308 if (!arr || !(arr->fFeatures & FADF_RECORD))
1309 return E_INVALIDARG;
1310 oldiface = ((IRecordInfo**)arr)[-1];
1312 IRecordInfo_Release(oldiface);
1313 ((IRecordInfo**)arr)[-1] = iface;
1315 IRecordInfo_AddRef(iface);
1319 /************************************************************************
1320 * SafeArrayGetRecordInfo (OLEAUT32.45)
1322 HRESULT WINAPI SafeArrayGetRecordInfo(SAFEARRAY *arr, IRecordInfo** iface) {
1323 if (!arr || !(arr->fFeatures & FADF_RECORD))
1324 return E_INVALIDARG;
1325 *iface = ((IRecordInfo**)arr)[-1];
1327 IRecordInfo_AddRef(*iface);