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/obj_base.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
35 #define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
37 /* Locally used methods */
39 endOfDim(LONG
*coor
, SAFEARRAYBOUND
*mat
, LONG dim
, LONG realDim
);
42 calcDisplacement(LONG
*coor
, SAFEARRAYBOUND
*mat
, LONG dim
);
45 isPointer(USHORT feature
);
48 getFeatures(VARTYPE vt
);
51 validCoordinate(LONG
*coor
, SAFEARRAY
*psa
);
54 resizeSafeArray(SAFEARRAY
*psa
, LONG lDelta
);
57 validArg(SAFEARRAY
*psa
);
60 getArraySize(SAFEARRAY
*psa
);
63 duplicateData(SAFEARRAY
*psa
, SAFEARRAY
**ppsaOut
);
65 /* Association between VARTYPE and their size.
66 A size of zero is defined for the unsupported types. */
68 #define VARTYPE_NOT_SUPPORTED 0
69 static const ULONG VARTYPE_SIZE
[] =
71 /* this is taken from wtypes.h. Only [S]es are supported by the SafeArray */
72 VARTYPE_NOT_SUPPORTED
, /* VT_EMPTY [V] [P] nothing */
73 VARTYPE_NOT_SUPPORTED
, /* VT_NULL [V] [P] SQL style Nul */
74 2, /* VT_I2 [V][T][P][S] 2 byte signed int */
75 4, /* VT_I4 [V][T][P][S] 4 byte signed int */
76 4, /* VT_R4 [V][T][P][S] 4 byte real */
77 8, /* VT_R8 [V][T][P][S] 8 byte real */
78 8, /* VT_CY [V][T][P][S] currency */
79 8, /* VT_DATE [V][T][P][S] date */
80 sizeof(BSTR
), /* VT_BSTR [V][T][P][S] OLE Automation string*/
81 sizeof(LPDISPATCH
), /* VT_DISPATCH [V][T][P][S] IDispatch * */
82 4, /* VT_ERROR [V][T] [S] SCODE */
83 4, /* VT_BOOL [V][T][P][S] True=-1, False=0*/
84 sizeof(VARIANT
), /* VT_VARIANT [V][T][P][S] VARIANT * */
85 sizeof(LPUNKNOWN
), /* VT_UNKNOWN [V][T] [S] IUnknown * */
86 sizeof(DECIMAL
), /* VT_DECIMAL [V][T] [S] 16 byte fixed point */
87 VARTYPE_NOT_SUPPORTED
, /* no VARTYPE here..... */
88 VARTYPE_NOT_SUPPORTED
, /* VT_I1 [T] signed char */
89 1, /* VT_UI1 [V][T][P][S] unsigned char */
90 VARTYPE_NOT_SUPPORTED
, /* VT_UI2 [T][P] unsigned short */
91 VARTYPE_NOT_SUPPORTED
, /* VT_UI4 [T][P] unsigned short */
92 VARTYPE_NOT_SUPPORTED
, /* VT_I8 [T][P] signed 64-bit int */
93 VARTYPE_NOT_SUPPORTED
, /* VT_UI8 [T][P] unsigned 64-bit int */
94 VARTYPE_NOT_SUPPORTED
, /* VT_INT [T] signed machine int */
95 VARTYPE_NOT_SUPPORTED
, /* VT_UINT [T] unsigned machine int */
96 VARTYPE_NOT_SUPPORTED
, /* VT_VOID [T] C style void */
97 VARTYPE_NOT_SUPPORTED
, /* VT_HRESULT [T] Standard return type */
98 VARTYPE_NOT_SUPPORTED
, /* VT_PTR [T] pointer type */
99 VARTYPE_NOT_SUPPORTED
, /* VT_SAFEARRAY [T] (use VT_ARRAY in VARIANT)*/
100 VARTYPE_NOT_SUPPORTED
, /* VT_CARRAY [T] C style array */
101 VARTYPE_NOT_SUPPORTED
, /* VT_USERDEFINED [T] user defined type */
102 VARTYPE_NOT_SUPPORTED
, /* VT_LPSTR [T][P] null terminated string */
103 VARTYPE_NOT_SUPPORTED
, /* VT_LPWSTR [T][P] wide null term string */
104 VARTYPE_NOT_SUPPORTED
, /* VT_FILETIME [P] FILETIME */
105 VARTYPE_NOT_SUPPORTED
, /* VT_BLOB [P] Length prefixed bytes */
106 VARTYPE_NOT_SUPPORTED
, /* VT_STREAM [P] Name of stream follows */
107 VARTYPE_NOT_SUPPORTED
, /* VT_STORAGE [P] Name of storage follows */
108 VARTYPE_NOT_SUPPORTED
, /* VT_STREAMED_OBJECT[P] Stream contains an object*/
109 VARTYPE_NOT_SUPPORTED
, /* VT_STORED_OBJECT [P] Storage contains object*/
110 VARTYPE_NOT_SUPPORTED
, /* VT_BLOB_OBJECT [P] Blob contains an object*/
111 VARTYPE_NOT_SUPPORTED
, /* VT_CF [P] Clipboard format */
112 VARTYPE_NOT_SUPPORTED
, /* VT_CLSID [P] A Class ID */
113 VARTYPE_NOT_SUPPORTED
, /* VT_VECTOR [P] simple counted array */
114 VARTYPE_NOT_SUPPORTED
, /* VT_ARRAY [V] SAFEARRAY* */
115 VARTYPE_NOT_SUPPORTED
/* VT_BYREF [V] void* for local use */
118 static const int LAST_VARTYPE
= sizeof(VARTYPE_SIZE
)/sizeof(VARTYPE_SIZE
[0]);
121 /*************************************************************************
122 * SafeArrayAllocDescriptor (OLEAUT32.36)
123 * Allocate the appropriate amount of memory for the SafeArray descriptor
125 HRESULT WINAPI
SafeArrayAllocDescriptor(
132 /* SAFEARRAY + SAFEARRAYBOUND * (cDims -1) ( -1 because there is already one
133 ( in SAFEARRAY struct */
134 allocSize
= sizeof(**ppsaOut
) + (sizeof(*sab
) * (cDims
-1));
136 /* Allocate memory for SAFEARRAY struc */
137 if(( (*ppsaOut
)=HeapAlloc(
138 GetProcessHeap(), HEAP_ZERO_MEMORY
, allocSize
)) == NULL
){
139 return(E_UNEXPECTED
);
141 TRACE("SafeArray: %lu bytes allocated for descriptor.\n", allocSize
);
146 /*************************************************************************
147 * SafeArrayAllocDescriptorEx (OLEAUT32.41)
148 * Allocate the appropriate amount of memory for the SafeArray descriptor
150 * This is a minimal implementation just to get things moving.
152 * The MSDN documentation on this doesn't tell us much.
154 HRESULT WINAPI
SafeArrayAllocDescriptorEx(
159 if ( (vt
>= LAST_VARTYPE
) ||
160 ( VARTYPE_SIZE
[vt
] == VARTYPE_NOT_SUPPORTED
) )
163 return SafeArrayAllocDescriptor (cDims
, ppsaOut
);
166 /*************************************************************************
167 * SafeArrayAllocData (OLEAUT32.37)
168 * Allocate the appropriate amount of data for the SafeArray data
170 HRESULT WINAPI
SafeArrayAllocData(
173 ULONG ulWholeArraySize
; /* to store the size of the whole thing */
178 ulWholeArraySize
= getArraySize(psa
);
180 /* Allocate memory for the data itself */
181 if((psa
->pvData
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
182 psa
->cbElements
*ulWholeArraySize
)) == NULL
)
183 return(E_UNEXPECTED
);
185 TRACE("SafeArray: %lu bytes allocated for data at %p (%lu objects).\n",
186 psa
->cbElements
*ulWholeArraySize
, psa
->pvData
, ulWholeArraySize
);
191 /*************************************************************************
192 * SafeArrayCreate (OLEAUT32.15)
193 * Create a SafeArray object by encapsulating AllocDescriptor and AllocData
195 SAFEARRAY
* WINAPI
SafeArrayCreate(
198 SAFEARRAYBOUND
*rgsabound
)
204 /* Validate supported VARTYPE */
205 if ( (vt
>= LAST_VARTYPE
) ||
206 ( VARTYPE_SIZE
[vt
] == VARTYPE_NOT_SUPPORTED
) )
209 /* Allocate memory for the array descriptor */
210 if( FAILED( hRes
= SafeArrayAllocDescriptor(cDims
, &psa
)))
213 /* setup data members... */
215 psa
->fFeatures
= getFeatures(vt
);
218 psa
->cbElements
= VARTYPE_SIZE
[vt
];
220 /* Invert the bounds ... */
221 for(cDim
=0; cDim
< psa
->cDims
; cDim
++) {
222 psa
->rgsabound
[cDim
].cElements
= rgsabound
[psa
->cDims
-cDim
-1].cElements
;
223 psa
->rgsabound
[cDim
].lLbound
= rgsabound
[psa
->cDims
-cDim
-1].lLbound
;
226 /* allocate memory for the data... */
227 if( FAILED( hRes
= SafeArrayAllocData(psa
))) {
228 SafeArrayDestroyDescriptor(psa
);
229 ERR("() : Failed to allocate the Safe Array data\n");
236 /*************************************************************************
237 * SafeArrayDestroyDescriptor (OLEAUT32.38)
238 * Frees the memory associated with the descriptor.
240 HRESULT WINAPI
SafeArrayDestroyDescriptor(
243 /* Check for lockness before to free... */
245 return DISP_E_ARRAYISLOCKED
;
247 /* The array is unlocked, then, deallocate memory */
248 if(HeapFree( GetProcessHeap(), 0, psa
) == FALSE
)
255 /*************************************************************************
256 * SafeArrayLock (OLEAUT32.21)
257 * Increment the lock counter
259 * Doc says (MSDN Library ) that psa->pvData should be made available (!= NULL)
260 * only when psa->cLocks is > 0... I don't get it since pvData is allocated
261 * before the array is locked, therefore
263 HRESULT WINAPI
SafeArrayLock(
274 /*************************************************************************
275 * SafeArrayUnlock (OLEAUT32.22)
276 * Decrement the lock counter
278 HRESULT WINAPI
SafeArrayUnlock(
291 /*************************************************************************
292 * SafeArrayPutElement (OLEAUT32.26)
293 * Set the data at the given coordinate
295 HRESULT WINAPI
SafeArrayPutElement(
300 ULONG stepCountInSAData
= 0; /* Number of array item to skip to get to
301 the desired one... */
302 PVOID elementStorageAddress
= NULL
; /* Adress to store the data */
304 /* Validate the index given */
305 if(! validCoordinate(rgIndices
, psa
))
306 return DISP_E_BADINDEX
;
310 if( SafeArrayLock(psa
) == S_OK
) {
312 /* Figure out the number of items to skip */
313 stepCountInSAData
= calcDisplacement(rgIndices
, psa
->rgsabound
, psa
->cDims
);
315 /* Figure out the number of byte to skip ... */
316 elementStorageAddress
= (char *) psa
->pvData
+(stepCountInSAData
*psa
->cbElements
);
318 if(isPointer(psa
->fFeatures
)) { /* increment ref count for this pointer */
320 *((PVOID
*)elementStorageAddress
) = *(PVOID
*)pv
;
321 IUnknown_AddRef( *(IUnknown
**)pv
);
325 if(psa
->fFeatures
== FADF_BSTR
) { /* Create a new object */
326 BSTR pbstrReAllocStr
= NULL
;
328 ((pbstrReAllocStr
= SYSDUPSTRING( (OLECHAR
*)pv
)) == NULL
)) {
329 SafeArrayUnlock(psa
);
330 return E_OUTOFMEMORY
;
332 *((BSTR
*)elementStorageAddress
) = pbstrReAllocStr
;
334 else if(psa
->fFeatures
== FADF_VARIANT
) {
335 HRESULT hr
= VariantCopy(elementStorageAddress
, pv
);
337 SafeArrayUnlock(psa
);
341 else /* duplicate the memory */
342 memcpy(elementStorageAddress
, pv
, SafeArrayGetElemsize(psa
) );
346 ERR("SafeArray: Cannot lock array....\n");
347 return E_UNEXPECTED
; /* UNDOC error condition */
350 TRACE("SafeArray: item put at adress %p.\n",elementStorageAddress
);
351 return SafeArrayUnlock(psa
);
355 /*************************************************************************
356 * SafeArrayGetElement (OLEAUT32.25)
357 * Return the data element corresponding the the given coordinate
359 HRESULT WINAPI
SafeArrayGetElement(
364 ULONG stepCountInSAData
= 0; /* Number of array item to skip to get to
365 the desired one... */
366 PVOID elementStorageAddress
= NULL
; /* Adress to store the data */
371 if(! validCoordinate(rgIndices
, psa
)) /* Validate the index given */
372 return(DISP_E_BADINDEX
);
374 if( SafeArrayLock(psa
) == S_OK
) {
376 /* Figure out the number of items to skip */
377 stepCountInSAData
= calcDisplacement(rgIndices
, psa
->rgsabound
, psa
->cDims
);
379 /* Figure out the number of byte to skip ... */
380 elementStorageAddress
= (char *) psa
->pvData
+(stepCountInSAData
*psa
->cbElements
);
382 if( psa
->fFeatures
== FADF_BSTR
) { /* reallocate the obj */
383 BSTR pbstrStoredStr
= *(OLECHAR
**)elementStorageAddress
;
384 BSTR pbstrReturnedStr
= NULL
;
385 if( pbstrStoredStr
&&
386 ((pbstrReturnedStr
= SYSDUPSTRING( pbstrStoredStr
)) == NULL
) ) {
387 SafeArrayUnlock(psa
);
388 return E_OUTOFMEMORY
;
390 *((BSTR
*)pv
) = pbstrReturnedStr
;
392 else if( psa
->fFeatures
== FADF_VARIANT
) {
395 hr
= VariantCopy(pv
, elementStorageAddress
);
397 SafeArrayUnlock(psa
);
401 else if( isPointer(psa
->fFeatures
) ) /* simply copy the pointer */
402 *(PVOID
*)pv
= *((PVOID
*)elementStorageAddress
);
403 else /* copy the bytes */
404 memcpy(pv
, elementStorageAddress
, psa
->cbElements
);
407 ERR("SafeArray: Cannot lock array....\n");
408 return E_UNEXPECTED
; /* UNDOC error condition */
411 return( SafeArrayUnlock(psa
) );
414 /*************************************************************************
415 * SafeArrayGetUBound (OLEAUT32.19)
416 * return the UP bound for a given array dimension
418 HRESULT WINAPI
SafeArrayGetUBound(
426 if(nDim
> psa
->cDims
)
427 return DISP_E_BADINDEX
;
430 return DISP_E_BADINDEX
;
432 *plUbound
= psa
->rgsabound
[nDim
-1].lLbound
+
433 psa
->rgsabound
[nDim
-1].cElements
- 1;
438 /*************************************************************************
439 * SafeArrayGetLBound (OLEAUT32.20)
440 * Return the LO bound for a given array dimension
442 HRESULT WINAPI
SafeArrayGetLBound(
450 if(nDim
> psa
->cDims
)
451 return DISP_E_BADINDEX
;
454 return DISP_E_BADINDEX
;
456 *plLbound
= psa
->rgsabound
[nDim
-1].lLbound
;
460 /*************************************************************************
461 * SafeArrayGetDim (OLEAUT32.17)
462 * returns the number of dimension in the array
464 UINT WINAPI
SafeArrayGetDim(
468 * A quick test in Windows shows that the behavior here for an invalid
469 * pointer is to return 0.
477 /*************************************************************************
478 * SafeArrayGetElemsize (OLEAUT32.18)
479 * Return the size of the element in the array
481 UINT WINAPI
SafeArrayGetElemsize(
485 * A quick test in Windows shows that the behavior here for an invalid
486 * pointer is to return 0.
491 return psa
->cbElements
;
494 /*************************************************************************
495 * SafeArrayAccessData (OLEAUT32.23)
496 * increment the access count and return the data
498 HRESULT WINAPI
SafeArrayAccessData(
507 hRes
= SafeArrayLock(psa
);
511 (*ppvData
) = psa
->pvData
;
522 /*************************************************************************
523 * SafeArrayUnaccessData (OLEAUT32.24)
524 * Decrement the access count
526 HRESULT WINAPI
SafeArrayUnaccessData(
532 return(SafeArrayUnlock(psa
));
535 /************************************************************************
536 * SafeArrayPtrOfIndex (OLEAUT32.148)
537 * Return a pointer to the element at rgIndices
539 HRESULT WINAPI
SafeArrayPtrOfIndex(
544 ULONG stepCountInSAData
= 0; /* Number of array item to skip to get to
545 the desired one... */
550 if(! validCoordinate(rgIndices
, psa
))
551 return DISP_E_BADINDEX
;
553 /* Although it is dangerous to do this without having a lock, it is not
554 * illegal. Microsoft do warn of the danger.
557 /* Figure out the number of items to skip */
558 stepCountInSAData
= calcDisplacement(rgIndices
, psa
->rgsabound
, psa
->cDims
);
560 *ppvData
= (char *) psa
->pvData
+(stepCountInSAData
*psa
->cbElements
);
565 /************************************************************************
566 * SafeArrayDestroyData (OLEAUT32.39)
567 * Frees the memory data bloc
569 HRESULT WINAPI
SafeArrayDestroyData(
573 ULONG ulWholeArraySize
; /* count spot in array */
574 ULONG ulDataIter
; /* to iterate the data space */
580 return DISP_E_ARRAYISLOCKED
;
582 ulWholeArraySize
= getArraySize(psa
);
584 if(isPointer(psa
->fFeatures
)) { /* release the pointers */
587 for(ulDataIter
=0; ulDataIter
< ulWholeArraySize
; ulDataIter
++) {
588 punk
= *(IUnknown
**)((char *) psa
->pvData
+(ulDataIter
*(psa
->cbElements
)));
591 IUnknown_Release(punk
);
595 else if(psa
->fFeatures
& FADF_BSTR
) { /* deallocate the obj */
598 for(ulDataIter
=0; ulDataIter
< ulWholeArraySize
; ulDataIter
++) {
599 bstr
= *(BSTR
*)((char *) psa
->pvData
+(ulDataIter
*(psa
->cbElements
)));
602 SysFreeString( bstr
);
605 else if(psa
->fFeatures
& FADF_VARIANT
) { /* deallocate the obj */
607 for(ulDataIter
=0; ulDataIter
< ulWholeArraySize
; ulDataIter
++) {
608 VariantClear((VARIANT
*)((char *) psa
->pvData
+(ulDataIter
*(psa
->cbElements
))));
612 /* check if this array is a Vector, in which case do not free the data
613 block since it has been allocated by AllocDescriptor and therefore
614 deserve to be freed by DestroyDescriptor */
615 if(!(psa
->fFeatures
& FADF_CREATEVECTOR
)) { /* Set when we do CreateVector */
617 /* free the whole chunk */
618 if((hRes
= HeapFree( GetProcessHeap(), 0, psa
->pvData
)) == 0) /*falied*/
619 return E_UNEXPECTED
; /* UNDOC error condition */
627 /************************************************************************
628 * SafeArrayCopyData (OLEAUT32.412)
629 * Copy the psaSource's data block into psaTarget if dimension and size
632 HRESULT WINAPI
SafeArrayCopyData(
633 SAFEARRAY
*psaSource
,
634 SAFEARRAY
**psaTarget
)
636 USHORT cDimCount
; /* looper */
637 LONG lDelta
; /* looper */
639 ULONG ulWholeArraySize
; /* Number of item in SA */
642 if(! (validArg(psaSource
) && validArg(*psaTarget
)) )
645 if(SafeArrayGetDim(psaSource
) != SafeArrayGetDim(*psaTarget
))
648 ulWholeArraySize
= getArraySize(psaSource
);
650 /* The two arrays boundaries must be of same lenght */
651 for(cDimCount
=0;cDimCount
< psaSource
->cDims
; cDimCount
++)
652 if( psaSource
->rgsabound
[cDimCount
].cElements
!=
653 (*psaTarget
)->rgsabound
[cDimCount
].cElements
)
656 if( isPointer((*psaTarget
)->fFeatures
) ) { /* the target contains ptr
657 that must be released */
658 for(lDelta
=0;lDelta
< ulWholeArraySize
; lDelta
++) {
660 ((char *) (*psaTarget
)->pvData
+ (lDelta
* (*psaTarget
)->cbElements
));
663 IUnknown_Release(punk
);
667 else if( (*psaTarget
)->fFeatures
& FADF_BSTR
) { /* the target contain BSTR
668 that must be freed */
669 for(lDelta
=0;lDelta
< ulWholeArraySize
; lDelta
++) {
671 *(BSTR
*)((char *) (*psaTarget
)->pvData
+ (lDelta
* (*psaTarget
)->cbElements
));
674 SysFreeString( bstr
);
677 else if( (*psaTarget
)->fFeatures
& FADF_VARIANT
) {
679 for(lDelta
=0;lDelta
< ulWholeArraySize
; lDelta
++) {
680 VariantClear((VARIANT
*)((char *) (*psaTarget
)->pvData
+ (lDelta
* (*psaTarget
)->cbElements
)));
684 return duplicateData(psaSource
, psaTarget
);
687 /************************************************************************
688 * SafeArrayDestroy (OLEAUT32.16)
689 * Deallocates all memory reserved for the SafeArray
691 HRESULT WINAPI
SafeArrayDestroy(
700 return DISP_E_ARRAYISLOCKED
;
702 if((hRes
= SafeArrayDestroyData( psa
)) == S_OK
)
703 if((hRes
= SafeArrayDestroyDescriptor( psa
)) == S_OK
)
706 return E_UNEXPECTED
; /* UNDOC error condition */
709 /************************************************************************
710 * SafeArrayCopy (OLEAUT32.27)
711 * Make a dupplicate of a SafeArray
713 HRESULT WINAPI
SafeArrayCopy(
719 ULONG ulWholeArraySize
; /* size of the thing */
724 if((hRes
=SafeArrayAllocDescriptor(psa
->cDims
, ppsaOut
)) == S_OK
){
726 /* Duplicate the SAFEARRAY struc */
727 memcpy(*ppsaOut
, psa
,
728 sizeof(*psa
)+(sizeof(*(psa
->rgsabound
))*(psa
->cDims
-1)));
730 (*ppsaOut
)->pvData
= NULL
; /* do not point to the same data area */
732 /* make sure the new safe array doesn't have the FADF_CREATEVECTOR flag,
733 because the data has not been allocated with the descriptor. */
734 (*ppsaOut
)->fFeatures
&= ~FADF_CREATEVECTOR
;
736 /* Get the allocated memory size for source and allocate it for target */
737 ulWholeArraySize
= getArraySize(psa
); /* Number of item in SA */
738 dAllocSize
= ulWholeArraySize
*psa
->cbElements
;
741 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dAllocSize
);
742 if( (*ppsaOut
)->pvData
!= NULL
) { /* HeapAlloc succeed */
744 if( (hRes
=duplicateData(psa
, ppsaOut
)) != S_OK
) { /* E_OUTOFMEMORY */
745 HeapFree(GetProcessHeap(), 0, (*ppsaOut
)->pvData
);
746 (*ppsaOut
)->pvData
= NULL
;
747 SafeArrayDestroyDescriptor(*ppsaOut
);
751 } else { /* failed to allocate or dupplicate... */
752 SafeArrayDestroyDescriptor(*ppsaOut
);
753 return E_UNEXPECTED
; /* UNDOC error condition */
755 } else { /* failed to allocate mem for descriptor */
756 return E_OUTOFMEMORY
; /* UNDOC error condiftion */
762 /************************************************************************
763 * SafeArrayCreateVector (OLEAUT32.411)
764 * Creates a one dimension safearray where the data is next to the
765 * SAFEARRAY structure.
767 SAFEARRAY
* WINAPI
SafeArrayCreateVector(
774 /* Validate supported VARTYPE */
775 if ( (vt
>= LAST_VARTYPE
) ||
776 ( VARTYPE_SIZE
[vt
] == VARTYPE_NOT_SUPPORTED
) )
779 /* Allocate memory for the array descriptor and data contiguously */
780 if( FAILED( psa
= HeapAlloc( GetProcessHeap(),
782 (sizeof(*psa
) + (VARTYPE_SIZE
[vt
] * cElements
))))) {
786 /* setup data members... */
787 psa
->cDims
= 1; /* always and forever */
788 psa
->fFeatures
= getFeatures(vt
) | FADF_CREATEVECTOR
; /* undocumented flag used by Microsoft */
790 psa
->pvData
= (BYTE
*)psa
+ sizeof(*psa
);
791 psa
->cbElements
= VARTYPE_SIZE
[vt
];
793 psa
->rgsabound
[0].cElements
= cElements
;
794 psa
->rgsabound
[0].lLbound
= lLbound
;
799 /************************************************************************
800 * SafeArrayRedim (OLEAUT32.40)
801 * Changes the caracteristics of the last dimension of the SafeArray
803 HRESULT WINAPI
SafeArrayRedim(
805 SAFEARRAYBOUND
*psaboundNew
)
807 LONG lDelta
; /* hold difference in size */
808 USHORT cDims
=1; /* dims counter */
813 if( psa
->cLocks
> 0 )
814 return DISP_E_ARRAYISLOCKED
;
816 if( psa
->fFeatures
& FADF_FIXEDSIZE
)
819 if( SafeArrayLock(psa
)==E_UNEXPECTED
)
820 return E_UNEXPECTED
;/* UNDOC error condition */
822 /* find the delta in number of array spot to apply to the new array */
823 lDelta
= psaboundNew
->cElements
- psa
->rgsabound
[0].cElements
;
824 for(; cDims
< psa
->cDims
; cDims
++)
825 /* delta in number of spot implied by modifying the last dimension */
826 lDelta
*= psa
->rgsabound
[cDims
].cElements
;
828 TRACE("elements=%ld, Lbound=%ld (delta=%ld)\n", psaboundNew
->cElements
, psaboundNew
->lLbound
, lDelta
);
830 if (lDelta
== 0) { ;/* same size, maybe a change of lLbound, just set it */
832 } else /* need to enlarge (lDelta +) reduce (lDelta -) */
833 if(! resizeSafeArray(psa
, lDelta
))
834 return E_UNEXPECTED
; /* UNDOC error condition */
836 /* the only modifyable dimension sits in [0] as the dimensions were reversed
837 at array creation time... */
838 psa
->rgsabound
[0].cElements
= psaboundNew
->cElements
;
839 psa
->rgsabound
[0].lLbound
= psaboundNew
->lLbound
;
841 return SafeArrayUnlock(psa
);
844 /************************************************************************
845 * NOT WINDOWS API - SafeArray* Utility functions
846 ************************************************************************/
848 /************************************************************************
849 * Used to validate the SAFEARRAY type of arg
851 static BOOL
validArg(
860 * Let's check for the null pointer just in case.
865 /* Check whether the size of the chunk makes sense... That's the only thing
866 I can think of now... */
868 psaSize
= HeapSize(GetProcessHeap(), 0, psa
);
870 /* uh, foreign heap. Better don't mess with it ! */
873 /* size of the descriptor when the SA is not created with CreateVector */
874 descSize
= sizeof(*psa
) + (sizeof(*sab
) * (psa
->cDims
-1));
876 /* size of the descriptor + data when created with CreateVector */
877 fullSize
= sizeof(*psa
) + (psa
->cbElements
* psa
->rgsabound
[0].cElements
);
879 return((psaSize
>= descSize
) || (psaSize
>= fullSize
));
882 /************************************************************************
883 * Used to reallocate memory
885 static BOOL
resizeSafeArray(
889 ULONG ulWholeArraySize
; /* use as multiplicator */
890 PVOID pvNewBlock
= NULL
;
894 ulWholeArraySize
= getArraySize(psa
);
896 if(lDelta
< 0) { /* array needs to be shorthen */
897 if( isPointer(psa
->fFeatures
)) /* ptr that need to be released */
898 for(;lDelta
< 0; lDelta
++) {
900 ((char *) psa
->pvData
+((ulWholeArraySize
+lDelta
)*psa
->cbElements
));
903 IUnknown_Release(punk
);
906 else if(psa
->fFeatures
& FADF_BSTR
) /* BSTR that need to be freed */
907 for(;lDelta
< 0; lDelta
++) {
909 ((char *) psa
->pvData
+((ulWholeArraySize
+lDelta
)*psa
->cbElements
));
912 SysFreeString( bstr
);
914 else if(psa
->fFeatures
& FADF_VARIANT
)
915 for(;lDelta
< 0; lDelta
++) {
916 VariantClear((VARIANT
*)((char *) psa
->pvData
+((ulWholeArraySize
+lDelta
)*psa
->cbElements
)));
920 if (!(psa
->fFeatures
& FADF_CREATEVECTOR
))
922 /* Ok now, if we are enlarging the array, we *MUST* move the whole block
923 pointed to by pvData. If we are shorthening the array, this move is
924 optional but we do it anyway becuase the benefit is that we are
925 releasing to the system the unused memory */
927 if((pvNewBlock
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, psa
->pvData
,
928 (ulWholeArraySize
+ lDelta
) * psa
->cbElements
)) == NULL
)
929 return FALSE
; /* TODO If we get here it means:
930 SHRINK situation : we've deleted the undesired
931 data and did not release the memory
932 GROWING situation: we've been unable to grow the array
937 /* Allocate a new block, because the previous data has been allocated with
938 the descriptor in SafeArrayCreateVector function. */
940 if((pvNewBlock
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
941 ulWholeArraySize
* psa
->cbElements
)) == NULL
)
944 psa
->fFeatures
&= ~FADF_CREATEVECTOR
;
946 /* reassign to the new block of data */
947 psa
->pvData
= pvNewBlock
;
951 /************************************************************************
952 * Used to set the fFeatures data member of the SAFEARRAY structure.
954 static INT
getFeatures(
958 case VT_BSTR
: return FADF_BSTR
;
959 case VT_UNKNOWN
: return FADF_UNKNOWN
;
960 case VT_DISPATCH
: return FADF_DISPATCH
;
961 case VT_VARIANT
: return FADF_VARIANT
;
966 /************************************************************************
967 * Used to figure out if the fFeatures data member of the SAFEARRAY
968 * structure contain any information about the type of data stored...
970 static BOOL
isPointer(
974 case FADF_UNKNOWN
: return TRUE
; /* those are pointers */
975 case FADF_DISPATCH
: return TRUE
;
980 /************************************************************************
981 * Used to calculate the displacement when accessing or modifying
982 * safearray data set.
984 * Parameters: - LONG *coor is the desired location in the multidimension
985 * table. Ex for a 3 dim table: coor[] = {1,2,3};
986 * - ULONG *mat is the format of the table. Ex for a 3 dim
987 * table mat[] = {4,4,4};
988 * - USHORT dim is the number of dimension of the SafeArray
990 static ULONG
calcDisplacement(
998 for(iterDim
=0; iterDim
<dim
; iterDim
++)
999 /* the -mat[dim] bring coor[dim] relative to 0 for calculation */
1000 res
+= ((coor
[iterDim
]-mat
[iterDim
].lLbound
) *
1001 endOfDim(coor
, mat
, iterDim
+1, dim
));
1003 TRACE("SafeArray: calculated displacement is %lu.\n", res
);
1007 /************************************************************************
1008 * Recursivity agent for calcDisplacement method. Used within Put and
1011 static INT
endOfDim(
1013 SAFEARRAYBOUND
*mat
,
1020 return (endOfDim(coor
, mat
, dim
+1, realDim
) * mat
[dim
].cElements
);
1024 /************************************************************************
1025 * Method used to validate the coordinate received in Put and Get
1028 static BOOL
validCoordinate(
1037 if (!psa
->cDims
) return FALSE
;
1038 for(; iter
<psa
->cDims
; iter
++) {
1039 TRACE("coor[%d]=%ld\n", iter
, coor
[iter
]);
1040 if((hRes
= SafeArrayGetLBound(psa
, (iter
+1), &lLBound
)) != S_OK
)
1042 if((hRes
= SafeArrayGetUBound(psa
, (iter
+1), &lUBound
)) != S_OK
)
1045 if(lLBound
> lUBound
)
1048 if((coor
[iter
] < lLBound
) || (coor
[iter
] > lUBound
))
1054 /************************************************************************
1055 * Method used to calculate the number of cells of the SA
1057 static ULONG
getArraySize(
1061 ULONG ulWholeArraySize
= 1;
1063 for(cCount
=0; cCount
< psa
->cDims
; cCount
++) /* foreach dimensions... */
1064 ulWholeArraySize
*= psa
->rgsabound
[cCount
].cElements
;
1066 return ulWholeArraySize
;
1070 /************************************************************************
1071 * Method used to handle data space dupplication for Copy32 and CopyData32
1073 static HRESULT
duplicateData(
1075 SAFEARRAY
**ppsaOut
)
1077 ULONG ulWholeArraySize
; /* size of the thing */
1080 ulWholeArraySize
= getArraySize(psa
); /* Number of item in SA */
1082 SafeArrayLock(*ppsaOut
);
1084 if( isPointer(psa
->fFeatures
) ) { /* If datatype is object increment
1085 object's reference count */
1088 for(lDelta
=0; lDelta
< ulWholeArraySize
; lDelta
++) {
1089 punk
= *(IUnknown
**)((char *) psa
->pvData
+(lDelta
* psa
->cbElements
));
1092 IUnknown_AddRef(punk
);
1095 /* Copy the source array data into target array */
1096 memcpy((*ppsaOut
)->pvData
, psa
->pvData
,
1097 ulWholeArraySize
*psa
->cbElements
);
1100 else if( psa
->fFeatures
& FADF_BSTR
) { /* if datatype is BSTR allocate
1101 the BSTR in the new array */
1102 BSTR pbstrReAllocStr
= NULL
;
1104 for(lDelta
=0; lDelta
< ulWholeArraySize
; lDelta
++) {
1105 if(( pbstrReAllocStr
= SYSDUPSTRING(
1106 *(BSTR
*)((char *) psa
->pvData
+(lDelta
* psa
->cbElements
)))) == NULL
) {
1108 SafeArrayUnlock(*ppsaOut
);
1109 return E_OUTOFMEMORY
;
1112 *((BSTR
*)((char *) (*ppsaOut
)->pvData
+(lDelta
* psa
->cbElements
))) =
1117 else if( psa
->fFeatures
& FADF_VARIANT
) {
1119 for(lDelta
=0; lDelta
< ulWholeArraySize
; lDelta
++) {
1120 VariantCopy((VARIANT
*)((char *) (*ppsaOut
)->pvData
+(lDelta
* psa
->cbElements
)),
1121 (VARIANT
*)((char *) psa
->pvData
+(lDelta
* psa
->cbElements
)));
1125 else { /* Simply copy the source array data into target array */
1127 memcpy((*ppsaOut
)->pvData
, psa
->pvData
,
1128 ulWholeArraySize
*psa
->cbElements
);
1131 SafeArrayUnlock(*ppsaOut
);
1137 /************************************************************************
1138 * SafeArrayGetVartype (OLEAUT32.77)
1139 * Returns the VARTYPE stored in the given safearray
1141 HRESULT WINAPI
SafeArrayGetVartype(
1145 HRESULT hr
= E_INVALIDARG
;
1146 VARTYPE vt
= VT_EMPTY
;
1148 /* const short VARTYPE_OFFSET = -4; */
1150 if (psa
->fFeatures
& FADF_HAVEVARTYPE
)
1152 /* VT tag @ negative offset 4 in the array descriptor */
1153 FIXME("Returning VT_BSTR instead of VT_...\n");
1156 else if (psa
->fFeatures
& FADF_RECORD
)
1160 else if (psa
->fFeatures
& FADF_BSTR
)
1164 else if (psa
->fFeatures
& FADF_UNKNOWN
)
1168 else if (psa
->fFeatures
& FADF_DISPATCH
)
1172 else if (psa
->fFeatures
& FADF_VARIANT
)
1183 TRACE("HRESULT = %08lx\n", hr
);