1 /*************************************************************************
3 * SafeArray Implementation
5 * This file contains the implementation of the SafeArray interface.
7 * Copyright 1999 Sylvain St-Germain
16 #include "wine/obj_base.h"
19 /* Localy used methods */
21 endOfDim(LONG
*coor
, SAFEARRAYBOUND
*mat
, LONG dim
, LONG realDim
);
24 calcDisplacement(LONG
*coor
, SAFEARRAYBOUND
*mat
, LONG dim
);
27 isPointer(USHORT feature
);
30 getFeatures(VARTYPE vt
);
33 validCoordinate(LONG
*coor
, SAFEARRAY
*psa
);
36 resizeSafeArray(SAFEARRAY
*psa
, LONG lDelta
);
39 validArg(SAFEARRAY
*psa
);
42 getArraySize(SAFEARRAY
*psa
);
45 duplicateData(SAFEARRAY
*psa
, SAFEARRAY
**ppsaOut
);
47 /* Association between VARTYPE and their size.
48 A size of zero is defined for the unsupported types. */
50 #define VARTYPE_NOT_SUPPORTED 0
51 const static ULONG VARTYPE_SIZE
[] =
53 /* this is taken from wtypes.h. Only [S]es are supported by the SafeArray */
54 VARTYPE_NOT_SUPPORTED
, /* VT_EMPTY [V] [P] nothing */
55 VARTYPE_NOT_SUPPORTED
, /* VT_NULL [V] [P] SQL style Nul */
56 2, /* VT_I2 [V][T][P][S] 2 byte signed int */
57 4, /* VT_I4 [V][T][P][S] 4 byte signed int */
58 4, /* VT_R4 [V][T][P][S] 4 byte real */
59 8, /* VT_R8 [V][T][P][S] 8 byte real */
60 8, /* VT_CY [V][T][P][S] currency */
61 8, /* VT_DATE [V][T][P][S] date */
62 4, /* VT_BSTR [V][T][P][S] OLE Automation string*/
63 4, /* VT_DISPATCH [V][T][P][S] IDispatch * */
64 4, /* VT_ERROR [V][T] [S] SCODE */
65 4, /* VT_BOOL [V][T][P][S] True=-1, False=0*/
66 24, /* VT_VARIANT [V][T][P][S] VARIANT * */
67 4, /* VT_UNKNOWN [V][T] [S] IUnknown * */
68 16, /* VT_DECIMAL [V][T] [S] 16 byte fixed point */
69 VARTYPE_NOT_SUPPORTED
, /* no VARTYPE here..... */
70 VARTYPE_NOT_SUPPORTED
, /* VT_I1 [T] signed char */
71 1, /* VT_UI1 [V][T][P][S] unsigned char */
72 VARTYPE_NOT_SUPPORTED
, /* VT_UI2 [T][P] unsigned short */
73 VARTYPE_NOT_SUPPORTED
, /* VT_UI4 [T][P] unsigned short */
74 VARTYPE_NOT_SUPPORTED
, /* VT_I8 [T][P] signed 64-bit int */
75 VARTYPE_NOT_SUPPORTED
, /* VT_UI8 [T][P] unsigned 64-bit int */
76 VARTYPE_NOT_SUPPORTED
, /* VT_INT [T] signed machine int */
77 VARTYPE_NOT_SUPPORTED
, /* VT_UINT [T] unsigned machine int */
78 VARTYPE_NOT_SUPPORTED
, /* VT_VOID [T] C style void */
79 VARTYPE_NOT_SUPPORTED
, /* VT_HRESULT [T] Standard return type */
80 VARTYPE_NOT_SUPPORTED
, /* VT_PTR [T] pointer type */
81 VARTYPE_NOT_SUPPORTED
, /* VT_SAFEARRAY [T] (use VT_ARRAY in VARIANT)*/
82 VARTYPE_NOT_SUPPORTED
, /* VT_CARRAY [T] C style array */
83 VARTYPE_NOT_SUPPORTED
, /* VT_USERDEFINED [T] user defined type */
84 VARTYPE_NOT_SUPPORTED
, /* VT_LPSTR [T][P] null terminated string */
85 VARTYPE_NOT_SUPPORTED
, /* VT_LPWSTR [T][P] wide null term string */
86 VARTYPE_NOT_SUPPORTED
, /* VT_FILETIME [P] FILETIME */
87 VARTYPE_NOT_SUPPORTED
, /* VT_BLOB [P] Length prefixed bytes */
88 VARTYPE_NOT_SUPPORTED
, /* VT_STREAM [P] Name of stream follows */
89 VARTYPE_NOT_SUPPORTED
, /* VT_STORAGE [P] Name of storage follows */
90 VARTYPE_NOT_SUPPORTED
, /* VT_STREAMED_OBJECT[P] Stream contains an object*/
91 VARTYPE_NOT_SUPPORTED
, /* VT_STORED_OBJECT [P] Storage contains object*/
92 VARTYPE_NOT_SUPPORTED
, /* VT_BLOB_OBJECT [P] Blob contains an object*/
93 VARTYPE_NOT_SUPPORTED
, /* VT_CF [P] Clipboard format */
94 VARTYPE_NOT_SUPPORTED
, /* VT_CLSID [P] A Class ID */
95 VARTYPE_NOT_SUPPORTED
, /* VT_VECTOR [P] simple counted array */
96 VARTYPE_NOT_SUPPORTED
, /* VT_ARRAY [V] SAFEARRAY* */
97 VARTYPE_NOT_SUPPORTED
/* VT_BYREF [V] void* for local use */
100 const static int LAST_VARTYPE
= sizeof(VARTYPE_SIZE
)/sizeof(ULONG
);
103 /*************************************************************************
104 * Allocate the appropriate amount of memory for the SafeArray descriptor
106 HRESULT WINAPI
SafeArrayAllocDescriptor(
113 /* SAFEARRAY + SAFEARRAYBOUND * (cDims -1) ( -1 because there is already one
114 ( in SAFEARRAY struct */
115 allocSize
= sizeof(**ppsaOut
) + (sizeof(*sab
) * (cDims
-1));
117 /* Allocate memory for SAFEARRAY struc */
118 if(( (*ppsaOut
)=HeapAlloc(
119 GetProcessHeap(), HEAP_ZERO_MEMORY
, allocSize
)) == NULL
){
120 return(E_UNEXPECTED
);
122 TRACE(ole
,"SafeArray: %lu bytes allocated for descriptor.\n", allocSize
);
127 /*************************************************************************
128 * Allocate the appropriate amount of data for the SafeArray data
130 HRESULT WINAPI
SafeArrayAllocData(
133 ULONG ulWholeArraySize
; /* to store the size of the whole thing */
138 ulWholeArraySize
= getArraySize(psa
);
140 /* Allocate memory for the data itself */
141 if((psa
->pvData
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
142 psa
->cbElements
*ulWholeArraySize
)) == NULL
)
143 return(E_UNEXPECTED
);
145 TRACE(ole
, "SafeArray: %lu bytes allocated for data at %p (%lu objects).\n",
146 psa
->cbElements
*ulWholeArraySize
, psa
->pvData
, ulWholeArraySize
);
151 /*************************************************************************
152 * Create a SafeArray object by encapsulating AllocDescriptor and AllocData
154 SAFEARRAY
* WINAPI
SafeArrayCreate(
157 SAFEARRAYBOUND
*rgsabound
)
163 /* Validate supported VARTYPE */
164 if ( (vt
>= LAST_VARTYPE
) ||
165 ( VARTYPE_SIZE
[vt
] == VARTYPE_NOT_SUPPORTED
) )
168 /* Allocate memory for the array descriptor */
169 if( FAILED( hRes
= SafeArrayAllocDescriptor(cDims
, &psa
)))
172 /* setup data members... */
174 psa
->fFeatures
= getFeatures(vt
);
177 psa
->cbElements
= VARTYPE_SIZE
[vt
];
179 /* Invert the bounds ... */
180 for(cDim
=0; cDim
< psa
->cDims
; cDim
++) {
181 psa
->rgsabound
[cDim
].cElements
= rgsabound
[psa
->cDims
-cDim
-1].cElements
;
182 psa
->rgsabound
[cDim
].lLbound
= rgsabound
[psa
->cDims
-cDim
-1].lLbound
;
185 /* allocate memory for the data... */
186 if( FAILED( hRes
= SafeArrayAllocData(psa
))) {
187 SafeArrayDestroyDescriptor(psa
);
188 ERR(ole
,"() : Failed to allocate the Safe Array data\n");
195 /*************************************************************************
196 * Frees the memory associated with the descriptor.
198 HRESULT WINAPI
SafeArrayDestroyDescriptor(
201 /* Check for lockness before to free... */
203 return DISP_E_ARRAYISLOCKED
;
205 /* The array is unlocked, then, deallocate memory */
206 if(HeapFree( GetProcessHeap(), 0, psa
) == FALSE
)
213 /*************************************************************************
214 * Increment the lock counter
216 * Doc says (MSDN Library ) that psa->pvData should be made available (!= NULL)
217 * only when psa->cLocks is > 0... I don't get it since pvData is allocated
218 * before the array is locked, therefore
220 HRESULT WINAPI
SafeArrayLock(
231 /*************************************************************************
232 * Decrement the lock counter
234 HRESULT WINAPI
SafeArrayUnlock(
247 /*************************************************************************
248 * Set the data at the given coordinate
250 HRESULT WINAPI
SafeArrayPutElement(
255 ULONG stepCountInSAData
= 0; /* Number of array item to skip to get to
256 the desired one... */
257 PVOID elementStorageAddress
= NULL
; /* Adress to store the data */
258 BSTR pbstrReAllocStr
= NULL
; /* BSTR reallocated */
260 /* Validate the index given */
261 if(! validCoordinate(rgIndices
, psa
))
262 return DISP_E_BADINDEX
;
266 if( SafeArrayLock(psa
) == S_OK
) {
268 /* Figure out the number of items to skip */
269 stepCountInSAData
= calcDisplacement(rgIndices
, psa
->rgsabound
, psa
->cDims
);
271 /* Figure out the number of byte to skip ... */
272 elementStorageAddress
= psa
->pvData
+(stepCountInSAData
*psa
->cbElements
);
274 if(isPointer(psa
->fFeatures
)) { /* increment ref count for this pointer */
276 *((VOID
**)elementStorageAddress
) = *(VOID
**)pv
;
277 IUnknown_AddRef( *(IUnknown
**)pv
);
281 if(psa
->fFeatures
== FADF_BSTR
) { /* Create a new object */
283 if((pbstrReAllocStr
= SysAllocString( (OLECHAR
*)pv
)) == NULL
) {
284 SafeArrayUnlock(psa
);
285 return E_OUTOFMEMORY
;
287 *((BSTR
*)elementStorageAddress
) = pbstrReAllocStr
;
289 } else /* dupplicate the memory */
290 memcpy(elementStorageAddress
, pv
, SafeArrayGetElemsize(psa
) );
294 ERR(ole
, "SafeArray: Cannot lock array....\n");
295 return E_UNEXPECTED
; /* UNDOC error condition */
298 TRACE(ole
,"SafeArray: item put at adress %p.\n",elementStorageAddress
);
299 return SafeArrayUnlock(psa
);
303 /*************************************************************************
304 * Return the data element corresponding the the given coordinate
306 HRESULT WINAPI
SafeArrayGetElement(
311 ULONG stepCountInSAData
= 0; /* Number of array item to skip to get to
312 the desired one... */
313 PVOID elementStorageAddress
= NULL
; /* Adress to store the data */
314 BSTR pbstrReturnedStr
= NULL
; /* BSTR reallocated */
319 if(! validCoordinate(rgIndices
, psa
)) /* Validate the index given */
320 return(DISP_E_BADINDEX
);
322 if( SafeArrayLock(psa
) == S_OK
) {
324 /* Figure out the number of items to skip */
325 stepCountInSAData
= calcDisplacement(rgIndices
, psa
->rgsabound
, psa
->cDims
);
327 /* Figure out the number of byte to skip ... */
328 elementStorageAddress
= psa
->pvData
+(stepCountInSAData
*psa
->cbElements
);
330 if( psa
->fFeatures
== FADF_BSTR
) { /* reallocate the obj */
331 if( (pbstrReturnedStr
=
332 SysAllocString( *(OLECHAR
**)elementStorageAddress
)) == NULL
) {
333 SafeArrayUnlock(psa
);
334 return E_OUTOFMEMORY
;
336 *((BSTR
*)pv
) = pbstrReturnedStr
;
338 } else if( isPointer(psa
->fFeatures
) ) /* simply copy the pointer */
339 pv
= *((PVOID
*)elementStorageAddress
);
340 else /* copy the bytes */
341 memcpy(pv
, elementStorageAddress
, SafeArrayGetElemsize(psa
) );
344 ERR(ole
, "SafeArray: Cannot lock array....\n");
345 return E_UNEXPECTED
; /* UNDOC error condition */
348 return( SafeArrayUnlock(psa
) );
351 /*************************************************************************
352 * return the UP bound for a given array dimension
354 HRESULT WINAPI
SafeArrayGetUBound(
362 if(nDim
> psa
->cDims
)
363 return DISP_E_BADINDEX
;
365 *plUbound
= psa
->rgsabound
[nDim
-1].lLbound
+
366 psa
->rgsabound
[nDim
-1].cElements
- 1;
371 /*************************************************************************
372 * Return the LO bound for a given array dimension
374 HRESULT WINAPI
SafeArrayGetLBound(
382 if(nDim
> psa
->cDims
)
383 return DISP_E_BADINDEX
;
385 *plLbound
= psa
->rgsabound
[nDim
-1].lLbound
;
389 /*************************************************************************
390 * returns the number of dimension in the array
392 UINT WINAPI
SafeArrayGetDim(
396 * A quick test in Windows shows that the behavior here for an invalid
397 * pointer is to return 0.
405 /*************************************************************************
406 * Return the size of the element in the array
408 UINT WINAPI
SafeArrayGetElemsize(
412 * A quick test in Windows shows that the behavior here for an invalid
413 * pointer is to return 0.
418 return psa
->cbElements
;
421 /*************************************************************************
422 * increment the access count and return the data
424 HRESULT WINAPI
SafeArrayAccessData(
433 hRes
= SafeArrayLock(psa
);
437 (*ppvData
) = psa
->pvData
;
448 /*************************************************************************
449 * Decrement the access count
451 HRESULT WINAPI
SafeArrayUnaccessData(
457 return(SafeArrayUnlock(psa
));
460 /************************************************************************
461 * Return a pointer to the element at rgIndices
463 HRESULT WINAPI
SafeArrayPtrOfIndex(
468 ULONG stepCountInSAData
= 0; /* Number of array item to skip to get to
469 the desired one... */
474 if(! validCoordinate(rgIndices
, psa
))
475 return DISP_E_BADINDEX
;
477 /* Figure out the number of items to skip */
478 stepCountInSAData
= calcDisplacement(rgIndices
, psa
->rgsabound
, psa
->cDims
);
480 *ppvData
= psa
->pvData
+(stepCountInSAData
*psa
->cbElements
);
485 /************************************************************************
486 * Frees the memory data bloc
488 HRESULT WINAPI
SafeArrayDestroyData(
492 ULONG ulWholeArraySize
; /* count spot in array */
493 ULONG ulDataIter
; /* to iterate the data space */
501 return DISP_E_ARRAYISLOCKED
;
503 ulWholeArraySize
= getArraySize(psa
);
505 if(isPointer(psa
->fFeatures
)) { /* release the pointers */
507 for(ulDataIter
=0; ulDataIter
< ulWholeArraySize
; ulDataIter
++) {
508 punk
= *(IUnknown
**)(psa
->pvData
+(ulDataIter
*(psa
->cbElements
)));
511 IUnknown_Release(punk
);
514 } else if(psa
->fFeatures
& FADF_BSTR
) { /* deallocate the obj */
516 for(ulDataIter
=0; ulDataIter
< ulWholeArraySize
; ulDataIter
++) {
517 bstr
= *(BSTR
*)(psa
->pvData
+(ulDataIter
*(psa
->cbElements
)));
520 SysFreeString( bstr
);
524 /* check if this array is a Vector, in which case do not free the data
525 block since it has been allocated by AllocDescriptor and therefore
526 deserve to be freed by DestroyDescriptor */
527 if(!(psa
->fFeatures
& FADF_FIXEDSIZE
)) { /* Set when we do CreateVector */
529 /* free the whole chunk */
530 if((hRes
= HeapFree( GetProcessHeap(), 0, psa
->pvData
)) == 0) /*falied*/
531 return E_UNEXPECTED
; /* UNDOC error condition */
539 /************************************************************************
540 * Copy the psaSource's data block into psaTarget if dimension and size
543 HRESULT WINAPI
SafeArrayCopyData(
544 SAFEARRAY
*psaSource
,
545 SAFEARRAY
**psaTarget
)
547 USHORT cDimCount
; /* looper */
548 LONG lDelta
; /* looper */
550 ULONG ulWholeArraySize
; /* Number of item in SA */
553 if(! (validArg(psaSource
) && validArg(*psaTarget
)) )
556 if(SafeArrayGetDim(psaSource
) != SafeArrayGetDim(*psaTarget
))
559 ulWholeArraySize
= getArraySize(psaSource
);
561 /* The two arrays boundaries must be of same lenght */
562 for(cDimCount
=0;cDimCount
< psaSource
->cDims
; cDimCount
++)
563 if( psaSource
->rgsabound
[cDimCount
].cElements
!=
564 (*psaTarget
)->rgsabound
[cDimCount
].cElements
)
567 if( isPointer((*psaTarget
)->fFeatures
) ) { /* the target contains ptr
568 that must be released */
569 for(lDelta
=0;lDelta
< ulWholeArraySize
; lDelta
++) {
571 ((*psaTarget
)->pvData
+ (lDelta
* (*psaTarget
)->cbElements
));
574 IUnknown_Release(punk
);
577 } else if( (*psaTarget
)->fFeatures
& FADF_BSTR
) { /* the target contain BSTR
578 that must be freed */
579 for(lDelta
=0;lDelta
< ulWholeArraySize
; lDelta
++) {
581 *(BSTR
*)((*psaTarget
)->pvData
+ (lDelta
* (*psaTarget
)->cbElements
));
584 SysFreeString( bstr
);
588 return duplicateData(psaSource
, psaTarget
);
591 /************************************************************************
592 * Deallocates all memory reserved for the SafeArray
594 HRESULT WINAPI
SafeArrayDestroy(
603 return DISP_E_ARRAYISLOCKED
;
605 if((hRes
= SafeArrayDestroyData( psa
)) == S_OK
)
606 if((hRes
= SafeArrayDestroyDescriptor( psa
)) == S_OK
)
609 return E_UNEXPECTED
; /* UNDOC error condition */
612 /************************************************************************
613 * Make a dupplicate of a SafeArray
615 HRESULT WINAPI
SafeArrayCopy(
625 if((hRes
=SafeArrayAllocDescriptor(psa
->cDims
, ppsaOut
)) == S_OK
){
627 /* Duplicate the SAFEARRAY struc */
628 memcpy(*ppsaOut
, psa
,
629 sizeof(*psa
)+(sizeof(*(psa
->rgsabound
))*(psa
->cDims
-1)));
631 (*ppsaOut
)->pvData
= NULL
; /* do not point to the same data area */
633 /* Get the allocated memory size for source and allocate it for target */
634 dAllocSize
= HeapSize(GetProcessHeap(), 0, psa
->pvData
);
636 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dAllocSize
);
638 if( (*ppsaOut
)->pvData
!= NULL
) { /* HeapAlloc succeed */
640 if( (hRes
=duplicateData(psa
, ppsaOut
)) != S_OK
) { /* E_OUTOFMEMORY */
641 HeapFree(GetProcessHeap(), 0, (*ppsaOut
)->pvData
);
642 (*ppsaOut
)->pvData
= NULL
;
643 SafeArrayDestroyDescriptor(*ppsaOut
);
647 } else { /* failed to allocate or dupplicate... */
648 SafeArrayDestroyDescriptor(*ppsaOut
);
649 return E_UNEXPECTED
; /* UNDOC error condition */
651 } else { /* failed to allocate mem for descriptor */
652 return E_OUTOFMEMORY
; /* UNDOC error condiftion */
658 /************************************************************************
659 * Creates a one dimension safearray where the data is next to the
660 * SAFEARRAY structure.
662 SAFEARRAY
* WINAPI
SafeArrayCreateVector(
669 /* Validate supported VARTYPE */
670 if ( (vt
>= LAST_VARTYPE
) ||
671 ( VARTYPE_SIZE
[vt
] == VARTYPE_NOT_SUPPORTED
) )
674 /* Allocate memory for the array descriptor and data contiguously */
675 if( FAILED( psa
= HeapAlloc( GetProcessHeap(),
677 (sizeof(*psa
) + (VARTYPE_SIZE
[vt
] * cElements
))))) {
681 /* setup data members... */
682 psa
->cDims
= 1; /* always and forever */
683 psa
->fFeatures
= getFeatures(vt
) | FADF_FIXEDSIZE
;
685 psa
->pvData
= psa
+sizeof(*psa
);
686 psa
->cbElements
= VARTYPE_SIZE
[vt
];
688 psa
->rgsabound
[0].cElements
= cElements
;
689 psa
->rgsabound
[0].lLbound
= lLbound
;
694 /************************************************************************
695 * Changes the caracteristics of the last dimension of the SafeArray
697 HRESULT WINAPI
SafeArrayRedim(
699 SAFEARRAYBOUND
*psaboundNew
)
701 LONG lDelta
; /* hold difference in size */
702 USHORT cDims
=1; /* dims counter */
707 if( psa
->cLocks
> 0 )
708 return DISP_E_ARRAYISLOCKED
;
710 if( psa
->fFeatures
& FADF_FIXEDSIZE
)
713 if( SafeArrayLock(psa
)==E_UNEXPECTED
)
714 return E_UNEXPECTED
;/* UNDOC error condition */
716 /* find the delta in number of array spot to apply to the new array */
717 lDelta
= psaboundNew
->cElements
- psa
->rgsabound
[0].cElements
;
718 for(; cDims
< psa
->cDims
; cDims
++)
719 /* delta in number of spot implied by modifying the last dimension */
720 lDelta
*= psa
->rgsabound
[cDims
].cElements
;
722 if (lDelta
== 0) { ;/* same size, maybe a change of lLbound, just set it */
724 } else /* need to enlarge (lDelta +) reduce (lDelta -) */
725 if(! resizeSafeArray(psa
, lDelta
))
726 return E_UNEXPECTED
; /* UNDOC error condition */
728 /* the only modifyable dimension sits in [0] as the dimensions were reversed
729 at array creation time... */
730 psa
->rgsabound
[0].cElements
= psaboundNew
->cElements
;
731 psa
->rgsabound
[0].lLbound
= psaboundNew
->lLbound
;
733 return SafeArrayUnlock(psa
);
736 /************************************************************************
737 * NOT WINDOWS API - SafeArray* Utility functions
738 ************************************************************************/
740 /************************************************************************
741 * Used to validate the SAFEARRAY type of arg
743 static BOOL
validArg(
752 * Let's check for the null pointer just in case.
757 /* Check whether the size of the chunk make sens... That's the only thing
758 I can think of now... */
760 psaSize
= HeapSize(GetProcessHeap(), 0, psa
);
762 /* size of the descriptor when the SA is not created with CreateVector */
763 descSize
= sizeof(*psa
) + (sizeof(*sab
) * (psa
->cDims
-1));
765 /* size of the descriptor + data when created with CreateVector */
766 fullSize
= sizeof(*psa
) + (psa
->cbElements
* psa
->rgsabound
[0].cElements
);
768 return((psaSize
>= descSize
) || (psaSize
>= fullSize
));
771 /************************************************************************
772 * Used to reallocate memory
774 static BOOL
resizeSafeArray(
778 ULONG ulWholeArraySize
; /* use as multiplicator */
779 PVOID pvNewBlock
= NULL
;
783 ulWholeArraySize
= getArraySize(psa
);
785 if(lDelta
< 0) { /* array needs to be shorthen */
786 if( isPointer(psa
->fFeatures
)) /* ptr that need to be released */
787 for(;lDelta
< 0; lDelta
++) {
789 (psa
->pvData
+((ulWholeArraySize
+lDelta
)*psa
->cbElements
));
792 IUnknown_Release(punk
);
795 else if(psa
->fFeatures
& FADF_BSTR
) /* BSTR that need to be freed */
796 for(;lDelta
< 0; lDelta
++) {
798 (psa
->pvData
+((ulWholeArraySize
+lDelta
)*psa
->cbElements
));
801 SysFreeString( bstr
);
805 /* Ok now, if we are enlarging the array, we *MUST* move the whole block
806 pointed to by pvData. If we are shorthening the array, this move is
807 optional but we do it anyway becuase the benefit is that we are
808 releasing to the system the unused memory */
810 if((pvNewBlock
= HeapReAlloc(GetProcessHeap(), 0, psa
->pvData
,
811 (ulWholeArraySize
+ lDelta
) * psa
->cbElements
)) == NULL
)
812 return FALSE
; /* TODO If we get here it means:
813 SHRINK situation : we've deleted the undesired
814 data and did not release the memory
815 GROWING situation: we've been unable to grow the array
818 /* reassign to the new block of data */
819 psa
->pvData
= pvNewBlock
;
823 /************************************************************************
824 * Used to set the fFeatures data member of the SAFEARRAY structure.
826 static INT
getFeatures(
830 case VT_UNKNOWN
: return FADF_UNKNOWN
;
831 case VT_DISPATCH
: return FADF_DISPATCH
;
832 case VT_BSTR
: return FADF_BSTR
;
837 /************************************************************************
838 * Used to figure out if the fFeatures data member of the SAFEARRAY
839 * structure contain any information about the type of data stored...
841 static BOOL
isPointer(
845 case FADF_UNKNOWN
: return TRUE
; /* those are pointers */
846 case FADF_DISPATCH
: return TRUE
;
851 /************************************************************************
852 * Used to calculate the displacement when accessing or modifying
853 * safearray data set.
855 * Parameters: - LONG *coor is the desired location in the multidimension
856 * table. Ex for a 3 dim table: coor[] = {1,2,3};
857 * - ULONG *mat is the format of the table. Ex for a 3 dim
858 * table mat[] = {4,4,4};
859 * - USHORT dim is the number of dimension of the SafeArray
861 static ULONG
calcDisplacement(
869 for(iterDim
=0; iterDim
<dim
; iterDim
++)
870 /* the -mat[dim] bring coor[dim] relative to 0 for calculation */
871 res
+= ((coor
[iterDim
]-mat
[iterDim
].lLbound
) *
872 endOfDim(coor
, mat
, iterDim
+1, dim
));
874 TRACE(ole
, "SafeArray: calculated displacement is %lu.\n", res
);
878 /************************************************************************
879 * Recursivity agent for calcDisplacement method. Used within Put and
891 return (endOfDim(coor
, mat
, dim
+1, realDim
) * mat
[dim
].cElements
);
895 /************************************************************************
896 * Method used to validate the coordinate received in Put and Get
899 static BOOL
validCoordinate(
908 for(; iter
<psa
->cDims
; iter
++) {
909 if((hRes
= SafeArrayGetLBound(psa
, iter
, &lLBound
)) != S_OK
)
911 if((hRes
= SafeArrayGetUBound(psa
, iter
, &lUBound
)) != S_OK
)
914 if(lLBound
== lUBound
)
917 if((coor
[iter
] >= lLBound
) && (coor
[iter
] <= lUBound
))
925 /************************************************************************
926 * Method used to calculate the number of cells of the SA
928 static ULONG
getArraySize(
932 ULONG ulWholeArraySize
= 1;
934 for(cCount
=0; cCount
< psa
->cDims
; cCount
++) /* foreach dimensions... */
935 ulWholeArraySize
*= psa
->rgsabound
[cCount
].cElements
;
937 return ulWholeArraySize
;
941 /************************************************************************
942 * Method used to handle data space dupplication for Copy32 and CopyData32
944 static HRESULT
duplicateData(
948 ULONG ulWholeArraySize
; /* size of the thing */
951 BSTR pbstrReAllocStr
= NULL
; /* BSTR reallocated */
953 ulWholeArraySize
= getArraySize(psa
); /* Number of item in SA */
955 SafeArrayLock(*ppsaOut
);
957 if( isPointer(psa
->fFeatures
) ) { /* If datatype is object increment
958 object's reference count */
960 for(lDelta
=0; lDelta
< ulWholeArraySize
; lDelta
++) {
961 punk
= *(IUnknown
**)(psa
->pvData
+(lDelta
* psa
->cbElements
));
964 IUnknown_AddRef(punk
);
967 /* Copy the source array data into target array */
968 memcpy((*ppsaOut
)->pvData
, psa
->pvData
,
969 ulWholeArraySize
*psa
->cbElements
);
971 } else if( psa
->fFeatures
& FADF_BSTR
) { /* if datatype is BSTR allocate
972 the BSTR in the new array */
974 for(lDelta
=0; lDelta
< ulWholeArraySize
; lDelta
++) {
975 if(( pbstrReAllocStr
= SysAllocString(
976 *(BSTR
*)(psa
->pvData
+(lDelta
* psa
->cbElements
)))) == NULL
) {
978 SafeArrayUnlock(*ppsaOut
);
979 return E_OUTOFMEMORY
;
982 *((BSTR
*)((*ppsaOut
)->pvData
+(lDelta
* psa
->cbElements
))) =
986 } else { /* Simply copy the source array data into target array */
988 memcpy((*ppsaOut
)->pvData
, psa
->pvData
,
989 ulWholeArraySize
*psa
->cbElements
);
992 SafeArrayUnlock(*ppsaOut
);