1 /*************************************************************************
3 * SafeArray Implementation
5 * This file contains the implementation of the SafeArray interface.
7 * Copyright 1999 Sylvain St-Germain
16 #include "wine/obj_base.h"
17 #include "debugtools.h"
19 DEFAULT_DEBUG_CHANNEL(ole
)
21 /* Localy used methods */
23 endOfDim(LONG
*coor
, SAFEARRAYBOUND
*mat
, LONG dim
, LONG realDim
);
26 calcDisplacement(LONG
*coor
, SAFEARRAYBOUND
*mat
, LONG dim
);
29 isPointer(USHORT feature
);
32 getFeatures(VARTYPE vt
);
35 validCoordinate(LONG
*coor
, SAFEARRAY
*psa
);
38 resizeSafeArray(SAFEARRAY
*psa
, LONG lDelta
);
41 validArg(SAFEARRAY
*psa
);
44 getArraySize(SAFEARRAY
*psa
);
47 duplicateData(SAFEARRAY
*psa
, SAFEARRAY
**ppsaOut
);
49 /* Association between VARTYPE and their size.
50 A size of zero is defined for the unsupported types. */
52 #define VARTYPE_NOT_SUPPORTED 0
53 const static ULONG VARTYPE_SIZE
[] =
55 /* this is taken from wtypes.h. Only [S]es are supported by the SafeArray */
56 VARTYPE_NOT_SUPPORTED
, /* VT_EMPTY [V] [P] nothing */
57 VARTYPE_NOT_SUPPORTED
, /* VT_NULL [V] [P] SQL style Nul */
58 2, /* VT_I2 [V][T][P][S] 2 byte signed int */
59 4, /* VT_I4 [V][T][P][S] 4 byte signed int */
60 4, /* VT_R4 [V][T][P][S] 4 byte real */
61 8, /* VT_R8 [V][T][P][S] 8 byte real */
62 8, /* VT_CY [V][T][P][S] currency */
63 8, /* VT_DATE [V][T][P][S] date */
64 4, /* VT_BSTR [V][T][P][S] OLE Automation string*/
65 4, /* VT_DISPATCH [V][T][P][S] IDispatch * */
66 4, /* VT_ERROR [V][T] [S] SCODE */
67 4, /* VT_BOOL [V][T][P][S] True=-1, False=0*/
68 24, /* VT_VARIANT [V][T][P][S] VARIANT * */
69 4, /* VT_UNKNOWN [V][T] [S] IUnknown * */
70 16, /* VT_DECIMAL [V][T] [S] 16 byte fixed point */
71 VARTYPE_NOT_SUPPORTED
, /* no VARTYPE here..... */
72 VARTYPE_NOT_SUPPORTED
, /* VT_I1 [T] signed char */
73 1, /* VT_UI1 [V][T][P][S] unsigned char */
74 VARTYPE_NOT_SUPPORTED
, /* VT_UI2 [T][P] unsigned short */
75 VARTYPE_NOT_SUPPORTED
, /* VT_UI4 [T][P] unsigned short */
76 VARTYPE_NOT_SUPPORTED
, /* VT_I8 [T][P] signed 64-bit int */
77 VARTYPE_NOT_SUPPORTED
, /* VT_UI8 [T][P] unsigned 64-bit int */
78 VARTYPE_NOT_SUPPORTED
, /* VT_INT [T] signed machine int */
79 VARTYPE_NOT_SUPPORTED
, /* VT_UINT [T] unsigned machine int */
80 VARTYPE_NOT_SUPPORTED
, /* VT_VOID [T] C style void */
81 VARTYPE_NOT_SUPPORTED
, /* VT_HRESULT [T] Standard return type */
82 VARTYPE_NOT_SUPPORTED
, /* VT_PTR [T] pointer type */
83 VARTYPE_NOT_SUPPORTED
, /* VT_SAFEARRAY [T] (use VT_ARRAY in VARIANT)*/
84 VARTYPE_NOT_SUPPORTED
, /* VT_CARRAY [T] C style array */
85 VARTYPE_NOT_SUPPORTED
, /* VT_USERDEFINED [T] user defined type */
86 VARTYPE_NOT_SUPPORTED
, /* VT_LPSTR [T][P] null terminated string */
87 VARTYPE_NOT_SUPPORTED
, /* VT_LPWSTR [T][P] wide null term string */
88 VARTYPE_NOT_SUPPORTED
, /* VT_FILETIME [P] FILETIME */
89 VARTYPE_NOT_SUPPORTED
, /* VT_BLOB [P] Length prefixed bytes */
90 VARTYPE_NOT_SUPPORTED
, /* VT_STREAM [P] Name of stream follows */
91 VARTYPE_NOT_SUPPORTED
, /* VT_STORAGE [P] Name of storage follows */
92 VARTYPE_NOT_SUPPORTED
, /* VT_STREAMED_OBJECT[P] Stream contains an object*/
93 VARTYPE_NOT_SUPPORTED
, /* VT_STORED_OBJECT [P] Storage contains object*/
94 VARTYPE_NOT_SUPPORTED
, /* VT_BLOB_OBJECT [P] Blob contains an object*/
95 VARTYPE_NOT_SUPPORTED
, /* VT_CF [P] Clipboard format */
96 VARTYPE_NOT_SUPPORTED
, /* VT_CLSID [P] A Class ID */
97 VARTYPE_NOT_SUPPORTED
, /* VT_VECTOR [P] simple counted array */
98 VARTYPE_NOT_SUPPORTED
, /* VT_ARRAY [V] SAFEARRAY* */
99 VARTYPE_NOT_SUPPORTED
/* VT_BYREF [V] void* for local use */
102 const static int LAST_VARTYPE
= sizeof(VARTYPE_SIZE
)/sizeof(ULONG
);
105 /*************************************************************************
106 * Allocate the appropriate amount of memory for the SafeArray descriptor
108 HRESULT WINAPI
SafeArrayAllocDescriptor(
115 /* SAFEARRAY + SAFEARRAYBOUND * (cDims -1) ( -1 because there is already one
116 ( in SAFEARRAY struct */
117 allocSize
= sizeof(**ppsaOut
) + (sizeof(*sab
) * (cDims
-1));
119 /* Allocate memory for SAFEARRAY struc */
120 if(( (*ppsaOut
)=HeapAlloc(
121 GetProcessHeap(), HEAP_ZERO_MEMORY
, allocSize
)) == NULL
){
122 return(E_UNEXPECTED
);
124 TRACE("SafeArray: %lu bytes allocated for descriptor.\n", allocSize
);
129 /*************************************************************************
130 * Allocate the appropriate amount of data for the SafeArray data
132 HRESULT WINAPI
SafeArrayAllocData(
135 ULONG ulWholeArraySize
; /* to store the size of the whole thing */
140 ulWholeArraySize
= getArraySize(psa
);
142 /* Allocate memory for the data itself */
143 if((psa
->pvData
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
144 psa
->cbElements
*ulWholeArraySize
)) == NULL
)
145 return(E_UNEXPECTED
);
147 TRACE("SafeArray: %lu bytes allocated for data at %p (%lu objects).\n",
148 psa
->cbElements
*ulWholeArraySize
, psa
->pvData
, ulWholeArraySize
);
153 /*************************************************************************
154 * Create a SafeArray object by encapsulating AllocDescriptor and AllocData
156 SAFEARRAY
* WINAPI
SafeArrayCreate(
159 SAFEARRAYBOUND
*rgsabound
)
165 /* Validate supported VARTYPE */
166 if ( (vt
>= LAST_VARTYPE
) ||
167 ( VARTYPE_SIZE
[vt
] == VARTYPE_NOT_SUPPORTED
) )
170 /* Allocate memory for the array descriptor */
171 if( FAILED( hRes
= SafeArrayAllocDescriptor(cDims
, &psa
)))
174 /* setup data members... */
176 psa
->fFeatures
= getFeatures(vt
);
179 psa
->cbElements
= VARTYPE_SIZE
[vt
];
181 /* Invert the bounds ... */
182 for(cDim
=0; cDim
< psa
->cDims
; cDim
++) {
183 psa
->rgsabound
[cDim
].cElements
= rgsabound
[psa
->cDims
-cDim
-1].cElements
;
184 psa
->rgsabound
[cDim
].lLbound
= rgsabound
[psa
->cDims
-cDim
-1].lLbound
;
187 /* allocate memory for the data... */
188 if( FAILED( hRes
= SafeArrayAllocData(psa
))) {
189 SafeArrayDestroyDescriptor(psa
);
190 ERR("() : Failed to allocate the Safe Array data\n");
197 /*************************************************************************
198 * Frees the memory associated with the descriptor.
200 HRESULT WINAPI
SafeArrayDestroyDescriptor(
203 /* Check for lockness before to free... */
205 return DISP_E_ARRAYISLOCKED
;
207 /* The array is unlocked, then, deallocate memory */
208 if(HeapFree( GetProcessHeap(), 0, psa
) == FALSE
)
215 /*************************************************************************
216 * Increment the lock counter
218 * Doc says (MSDN Library ) that psa->pvData should be made available (!= NULL)
219 * only when psa->cLocks is > 0... I don't get it since pvData is allocated
220 * before the array is locked, therefore
222 HRESULT WINAPI
SafeArrayLock(
233 /*************************************************************************
234 * Decrement the lock counter
236 HRESULT WINAPI
SafeArrayUnlock(
249 /*************************************************************************
250 * Set the data at the given coordinate
252 HRESULT WINAPI
SafeArrayPutElement(
257 ULONG stepCountInSAData
= 0; /* Number of array item to skip to get to
258 the desired one... */
259 PVOID elementStorageAddress
= NULL
; /* Adress to store the data */
260 BSTR pbstrReAllocStr
= NULL
; /* BSTR reallocated */
262 /* Validate the index given */
263 if(! validCoordinate(rgIndices
, psa
))
264 return DISP_E_BADINDEX
;
268 if( SafeArrayLock(psa
) == S_OK
) {
270 /* Figure out the number of items to skip */
271 stepCountInSAData
= calcDisplacement(rgIndices
, psa
->rgsabound
, psa
->cDims
);
273 /* Figure out the number of byte to skip ... */
274 elementStorageAddress
= (char *) psa
->pvData
+(stepCountInSAData
*psa
->cbElements
);
276 if(isPointer(psa
->fFeatures
)) { /* increment ref count for this pointer */
278 *((VOID
**)elementStorageAddress
) = *(VOID
**)pv
;
279 IUnknown_AddRef( *(IUnknown
**)pv
);
283 if(psa
->fFeatures
== FADF_BSTR
) { /* Create a new object */
285 if((pbstrReAllocStr
= SysAllocString( (OLECHAR
*)pv
)) == NULL
) {
286 SafeArrayUnlock(psa
);
287 return E_OUTOFMEMORY
;
289 *((BSTR
*)elementStorageAddress
) = pbstrReAllocStr
;
291 } else /* dupplicate the memory */
292 memcpy(elementStorageAddress
, pv
, SafeArrayGetElemsize(psa
) );
296 ERR("SafeArray: Cannot lock array....\n");
297 return E_UNEXPECTED
; /* UNDOC error condition */
300 TRACE("SafeArray: item put at adress %p.\n",elementStorageAddress
);
301 return SafeArrayUnlock(psa
);
305 /*************************************************************************
306 * Return the data element corresponding the the given coordinate
308 HRESULT WINAPI
SafeArrayGetElement(
313 ULONG stepCountInSAData
= 0; /* Number of array item to skip to get to
314 the desired one... */
315 PVOID elementStorageAddress
= NULL
; /* Adress to store the data */
316 BSTR pbstrReturnedStr
= NULL
; /* BSTR reallocated */
321 if(! validCoordinate(rgIndices
, psa
)) /* Validate the index given */
322 return(DISP_E_BADINDEX
);
324 if( SafeArrayLock(psa
) == S_OK
) {
326 /* Figure out the number of items to skip */
327 stepCountInSAData
= calcDisplacement(rgIndices
, psa
->rgsabound
, psa
->cDims
);
329 /* Figure out the number of byte to skip ... */
330 elementStorageAddress
= (char *) psa
->pvData
+(stepCountInSAData
*psa
->cbElements
);
332 if( psa
->fFeatures
== FADF_BSTR
) { /* reallocate the obj */
333 if( (pbstrReturnedStr
=
334 SysAllocString( *(OLECHAR
**)elementStorageAddress
)) == NULL
) {
335 SafeArrayUnlock(psa
);
336 return E_OUTOFMEMORY
;
338 *((BSTR
*)pv
) = pbstrReturnedStr
;
340 } else if( isPointer(psa
->fFeatures
) ) /* simply copy the pointer */
341 pv
= *((PVOID
*)elementStorageAddress
);
342 else /* copy the bytes */
343 memcpy(pv
, elementStorageAddress
, SafeArrayGetElemsize(psa
) );
346 ERR("SafeArray: Cannot lock array....\n");
347 return E_UNEXPECTED
; /* UNDOC error condition */
350 return( SafeArrayUnlock(psa
) );
353 /*************************************************************************
354 * return the UP bound for a given array dimension
356 HRESULT WINAPI
SafeArrayGetUBound(
364 if(nDim
> psa
->cDims
)
365 return DISP_E_BADINDEX
;
367 *plUbound
= psa
->rgsabound
[nDim
-1].lLbound
+
368 psa
->rgsabound
[nDim
-1].cElements
- 1;
373 /*************************************************************************
374 * Return the LO bound for a given array dimension
376 HRESULT WINAPI
SafeArrayGetLBound(
384 if(nDim
> psa
->cDims
)
385 return DISP_E_BADINDEX
;
387 *plLbound
= psa
->rgsabound
[nDim
-1].lLbound
;
391 /*************************************************************************
392 * returns the number of dimension in the array
394 UINT WINAPI
SafeArrayGetDim(
398 * A quick test in Windows shows that the behavior here for an invalid
399 * pointer is to return 0.
407 /*************************************************************************
408 * Return the size of the element in the array
410 UINT WINAPI
SafeArrayGetElemsize(
414 * A quick test in Windows shows that the behavior here for an invalid
415 * pointer is to return 0.
420 return psa
->cbElements
;
423 /*************************************************************************
424 * increment the access count and return the data
426 HRESULT WINAPI
SafeArrayAccessData(
435 hRes
= SafeArrayLock(psa
);
439 (*ppvData
) = psa
->pvData
;
450 /*************************************************************************
451 * Decrement the access count
453 HRESULT WINAPI
SafeArrayUnaccessData(
459 return(SafeArrayUnlock(psa
));
462 /************************************************************************
463 * Return a pointer to the element at rgIndices
465 HRESULT WINAPI
SafeArrayPtrOfIndex(
470 ULONG stepCountInSAData
= 0; /* Number of array item to skip to get to
471 the desired one... */
476 if(! validCoordinate(rgIndices
, psa
))
477 return DISP_E_BADINDEX
;
479 /* Figure out the number of items to skip */
480 stepCountInSAData
= calcDisplacement(rgIndices
, psa
->rgsabound
, psa
->cDims
);
482 *ppvData
= (char *) psa
->pvData
+(stepCountInSAData
*psa
->cbElements
);
487 /************************************************************************
488 * Frees the memory data bloc
490 HRESULT WINAPI
SafeArrayDestroyData(
494 ULONG ulWholeArraySize
; /* count spot in array */
495 ULONG ulDataIter
; /* to iterate the data space */
503 return DISP_E_ARRAYISLOCKED
;
505 ulWholeArraySize
= getArraySize(psa
);
507 if(isPointer(psa
->fFeatures
)) { /* release the pointers */
509 for(ulDataIter
=0; ulDataIter
< ulWholeArraySize
; ulDataIter
++) {
510 punk
= *(IUnknown
**)((char *) psa
->pvData
+(ulDataIter
*(psa
->cbElements
)));
513 IUnknown_Release(punk
);
516 } else if(psa
->fFeatures
& FADF_BSTR
) { /* deallocate the obj */
518 for(ulDataIter
=0; ulDataIter
< ulWholeArraySize
; ulDataIter
++) {
519 bstr
= *(BSTR
*)((char *) psa
->pvData
+(ulDataIter
*(psa
->cbElements
)));
522 SysFreeString( bstr
);
526 /* check if this array is a Vector, in which case do not free the data
527 block since it has been allocated by AllocDescriptor and therefore
528 deserve to be freed by DestroyDescriptor */
529 if(!(psa
->fFeatures
& FADF_FIXEDSIZE
)) { /* Set when we do CreateVector */
531 /* free the whole chunk */
532 if((hRes
= HeapFree( GetProcessHeap(), 0, psa
->pvData
)) == 0) /*falied*/
533 return E_UNEXPECTED
; /* UNDOC error condition */
541 /************************************************************************
542 * Copy the psaSource's data block into psaTarget if dimension and size
545 HRESULT WINAPI
SafeArrayCopyData(
546 SAFEARRAY
*psaSource
,
547 SAFEARRAY
**psaTarget
)
549 USHORT cDimCount
; /* looper */
550 LONG lDelta
; /* looper */
552 ULONG ulWholeArraySize
; /* Number of item in SA */
555 if(! (validArg(psaSource
) && validArg(*psaTarget
)) )
558 if(SafeArrayGetDim(psaSource
) != SafeArrayGetDim(*psaTarget
))
561 ulWholeArraySize
= getArraySize(psaSource
);
563 /* The two arrays boundaries must be of same lenght */
564 for(cDimCount
=0;cDimCount
< psaSource
->cDims
; cDimCount
++)
565 if( psaSource
->rgsabound
[cDimCount
].cElements
!=
566 (*psaTarget
)->rgsabound
[cDimCount
].cElements
)
569 if( isPointer((*psaTarget
)->fFeatures
) ) { /* the target contains ptr
570 that must be released */
571 for(lDelta
=0;lDelta
< ulWholeArraySize
; lDelta
++) {
573 ((char *) (*psaTarget
)->pvData
+ (lDelta
* (*psaTarget
)->cbElements
));
576 IUnknown_Release(punk
);
579 } else if( (*psaTarget
)->fFeatures
& FADF_BSTR
) { /* the target contain BSTR
580 that must be freed */
581 for(lDelta
=0;lDelta
< ulWholeArraySize
; lDelta
++) {
583 *(BSTR
*)((char *) (*psaTarget
)->pvData
+ (lDelta
* (*psaTarget
)->cbElements
));
586 SysFreeString( bstr
);
590 return duplicateData(psaSource
, psaTarget
);
593 /************************************************************************
594 * Deallocates all memory reserved for the SafeArray
596 HRESULT WINAPI
SafeArrayDestroy(
605 return DISP_E_ARRAYISLOCKED
;
607 if((hRes
= SafeArrayDestroyData( psa
)) == S_OK
)
608 if((hRes
= SafeArrayDestroyDescriptor( psa
)) == S_OK
)
611 return E_UNEXPECTED
; /* UNDOC error condition */
614 /************************************************************************
615 * Make a dupplicate of a SafeArray
617 HRESULT WINAPI
SafeArrayCopy(
627 if((hRes
=SafeArrayAllocDescriptor(psa
->cDims
, ppsaOut
)) == S_OK
){
629 /* Duplicate the SAFEARRAY struc */
630 memcpy(*ppsaOut
, psa
,
631 sizeof(*psa
)+(sizeof(*(psa
->rgsabound
))*(psa
->cDims
-1)));
633 (*ppsaOut
)->pvData
= NULL
; /* do not point to the same data area */
635 /* Get the allocated memory size for source and allocate it for target */
636 dAllocSize
= HeapSize(GetProcessHeap(), 0, psa
->pvData
);
638 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dAllocSize
);
640 if( (*ppsaOut
)->pvData
!= NULL
) { /* HeapAlloc succeed */
642 if( (hRes
=duplicateData(psa
, ppsaOut
)) != S_OK
) { /* E_OUTOFMEMORY */
643 HeapFree(GetProcessHeap(), 0, (*ppsaOut
)->pvData
);
644 (*ppsaOut
)->pvData
= NULL
;
645 SafeArrayDestroyDescriptor(*ppsaOut
);
649 } else { /* failed to allocate or dupplicate... */
650 SafeArrayDestroyDescriptor(*ppsaOut
);
651 return E_UNEXPECTED
; /* UNDOC error condition */
653 } else { /* failed to allocate mem for descriptor */
654 return E_OUTOFMEMORY
; /* UNDOC error condiftion */
660 /************************************************************************
661 * Creates a one dimension safearray where the data is next to the
662 * SAFEARRAY structure.
664 SAFEARRAY
* WINAPI
SafeArrayCreateVector(
671 /* Validate supported VARTYPE */
672 if ( (vt
>= LAST_VARTYPE
) ||
673 ( VARTYPE_SIZE
[vt
] == VARTYPE_NOT_SUPPORTED
) )
676 /* Allocate memory for the array descriptor and data contiguously */
677 if( FAILED( psa
= HeapAlloc( GetProcessHeap(),
679 (sizeof(*psa
) + (VARTYPE_SIZE
[vt
] * cElements
))))) {
683 /* setup data members... */
684 psa
->cDims
= 1; /* always and forever */
685 psa
->fFeatures
= getFeatures(vt
) | FADF_FIXEDSIZE
;
687 psa
->pvData
= psa
+sizeof(*psa
);
688 psa
->cbElements
= VARTYPE_SIZE
[vt
];
690 psa
->rgsabound
[0].cElements
= cElements
;
691 psa
->rgsabound
[0].lLbound
= lLbound
;
696 /************************************************************************
697 * Changes the caracteristics of the last dimension of the SafeArray
699 HRESULT WINAPI
SafeArrayRedim(
701 SAFEARRAYBOUND
*psaboundNew
)
703 LONG lDelta
; /* hold difference in size */
704 USHORT cDims
=1; /* dims counter */
709 if( psa
->cLocks
> 0 )
710 return DISP_E_ARRAYISLOCKED
;
712 if( psa
->fFeatures
& FADF_FIXEDSIZE
)
715 if( SafeArrayLock(psa
)==E_UNEXPECTED
)
716 return E_UNEXPECTED
;/* UNDOC error condition */
718 /* find the delta in number of array spot to apply to the new array */
719 lDelta
= psaboundNew
->cElements
- psa
->rgsabound
[0].cElements
;
720 for(; cDims
< psa
->cDims
; cDims
++)
721 /* delta in number of spot implied by modifying the last dimension */
722 lDelta
*= psa
->rgsabound
[cDims
].cElements
;
724 if (lDelta
== 0) { ;/* same size, maybe a change of lLbound, just set it */
726 } else /* need to enlarge (lDelta +) reduce (lDelta -) */
727 if(! resizeSafeArray(psa
, lDelta
))
728 return E_UNEXPECTED
; /* UNDOC error condition */
730 /* the only modifyable dimension sits in [0] as the dimensions were reversed
731 at array creation time... */
732 psa
->rgsabound
[0].cElements
= psaboundNew
->cElements
;
733 psa
->rgsabound
[0].lLbound
= psaboundNew
->lLbound
;
735 return SafeArrayUnlock(psa
);
738 /************************************************************************
739 * NOT WINDOWS API - SafeArray* Utility functions
740 ************************************************************************/
742 /************************************************************************
743 * Used to validate the SAFEARRAY type of arg
745 static BOOL
validArg(
754 * Let's check for the null pointer just in case.
759 /* Check whether the size of the chunk make sens... That's the only thing
760 I can think of now... */
762 psaSize
= HeapSize(GetProcessHeap(), 0, psa
);
764 /* size of the descriptor when the SA is not created with CreateVector */
765 descSize
= sizeof(*psa
) + (sizeof(*sab
) * (psa
->cDims
-1));
767 /* size of the descriptor + data when created with CreateVector */
768 fullSize
= sizeof(*psa
) + (psa
->cbElements
* psa
->rgsabound
[0].cElements
);
770 return((psaSize
>= descSize
) || (psaSize
>= fullSize
));
773 /************************************************************************
774 * Used to reallocate memory
776 static BOOL
resizeSafeArray(
780 ULONG ulWholeArraySize
; /* use as multiplicator */
781 PVOID pvNewBlock
= NULL
;
785 ulWholeArraySize
= getArraySize(psa
);
787 if(lDelta
< 0) { /* array needs to be shorthen */
788 if( isPointer(psa
->fFeatures
)) /* ptr that need to be released */
789 for(;lDelta
< 0; lDelta
++) {
791 ((char *) psa
->pvData
+((ulWholeArraySize
+lDelta
)*psa
->cbElements
));
794 IUnknown_Release(punk
);
797 else if(psa
->fFeatures
& FADF_BSTR
) /* BSTR that need to be freed */
798 for(;lDelta
< 0; lDelta
++) {
800 ((char *) psa
->pvData
+((ulWholeArraySize
+lDelta
)*psa
->cbElements
));
803 SysFreeString( bstr
);
807 /* Ok now, if we are enlarging the array, we *MUST* move the whole block
808 pointed to by pvData. If we are shorthening the array, this move is
809 optional but we do it anyway becuase the benefit is that we are
810 releasing to the system the unused memory */
812 if((pvNewBlock
= HeapReAlloc(GetProcessHeap(), 0, psa
->pvData
,
813 (ulWholeArraySize
+ lDelta
) * psa
->cbElements
)) == NULL
)
814 return FALSE
; /* TODO If we get here it means:
815 SHRINK situation : we've deleted the undesired
816 data and did not release the memory
817 GROWING situation: we've been unable to grow the array
820 /* reassign to the new block of data */
821 psa
->pvData
= pvNewBlock
;
825 /************************************************************************
826 * Used to set the fFeatures data member of the SAFEARRAY structure.
828 static INT
getFeatures(
832 case VT_UNKNOWN
: return FADF_UNKNOWN
;
833 case VT_DISPATCH
: return FADF_DISPATCH
;
834 case VT_BSTR
: return FADF_BSTR
;
839 /************************************************************************
840 * Used to figure out if the fFeatures data member of the SAFEARRAY
841 * structure contain any information about the type of data stored...
843 static BOOL
isPointer(
847 case FADF_UNKNOWN
: return TRUE
; /* those are pointers */
848 case FADF_DISPATCH
: return TRUE
;
853 /************************************************************************
854 * Used to calculate the displacement when accessing or modifying
855 * safearray data set.
857 * Parameters: - LONG *coor is the desired location in the multidimension
858 * table. Ex for a 3 dim table: coor[] = {1,2,3};
859 * - ULONG *mat is the format of the table. Ex for a 3 dim
860 * table mat[] = {4,4,4};
861 * - USHORT dim is the number of dimension of the SafeArray
863 static ULONG
calcDisplacement(
871 for(iterDim
=0; iterDim
<dim
; iterDim
++)
872 /* the -mat[dim] bring coor[dim] relative to 0 for calculation */
873 res
+= ((coor
[iterDim
]-mat
[iterDim
].lLbound
) *
874 endOfDim(coor
, mat
, iterDim
+1, dim
));
876 TRACE("SafeArray: calculated displacement is %lu.\n", res
);
880 /************************************************************************
881 * Recursivity agent for calcDisplacement method. Used within Put and
893 return (endOfDim(coor
, mat
, dim
+1, realDim
) * mat
[dim
].cElements
);
897 /************************************************************************
898 * Method used to validate the coordinate received in Put and Get
901 static BOOL
validCoordinate(
910 for(; iter
<psa
->cDims
; iter
++) {
911 if((hRes
= SafeArrayGetLBound(psa
, iter
, &lLBound
)) != S_OK
)
913 if((hRes
= SafeArrayGetUBound(psa
, iter
, &lUBound
)) != S_OK
)
916 if(lLBound
== lUBound
)
919 if((coor
[iter
] >= lLBound
) && (coor
[iter
] <= lUBound
))
927 /************************************************************************
928 * Method used to calculate the number of cells of the SA
930 static ULONG
getArraySize(
934 ULONG ulWholeArraySize
= 1;
936 for(cCount
=0; cCount
< psa
->cDims
; cCount
++) /* foreach dimensions... */
937 ulWholeArraySize
*= psa
->rgsabound
[cCount
].cElements
;
939 return ulWholeArraySize
;
943 /************************************************************************
944 * Method used to handle data space dupplication for Copy32 and CopyData32
946 static HRESULT
duplicateData(
950 ULONG ulWholeArraySize
; /* size of the thing */
953 BSTR pbstrReAllocStr
= NULL
; /* BSTR reallocated */
955 ulWholeArraySize
= getArraySize(psa
); /* Number of item in SA */
957 SafeArrayLock(*ppsaOut
);
959 if( isPointer(psa
->fFeatures
) ) { /* If datatype is object increment
960 object's reference count */
962 for(lDelta
=0; lDelta
< ulWholeArraySize
; lDelta
++) {
963 punk
= *(IUnknown
**)((char *) psa
->pvData
+(lDelta
* psa
->cbElements
));
966 IUnknown_AddRef(punk
);
969 /* Copy the source array data into target array */
970 memcpy((*ppsaOut
)->pvData
, psa
->pvData
,
971 ulWholeArraySize
*psa
->cbElements
);
973 } else if( psa
->fFeatures
& FADF_BSTR
) { /* if datatype is BSTR allocate
974 the BSTR in the new array */
976 for(lDelta
=0; lDelta
< ulWholeArraySize
; lDelta
++) {
977 if(( pbstrReAllocStr
= SysAllocString(
978 *(BSTR
*)((char *) psa
->pvData
+(lDelta
* psa
->cbElements
)))) == NULL
) {
980 SafeArrayUnlock(*ppsaOut
);
981 return E_OUTOFMEMORY
;
984 *((BSTR
*)((char *) (*ppsaOut
)->pvData
+(lDelta
* psa
->cbElements
))) =
988 } else { /* Simply copy the source array data into target array */
990 memcpy((*ppsaOut
)->pvData
, psa
->pvData
,
991 ulWholeArraySize
*psa
->cbElements
);
994 SafeArrayUnlock(*ppsaOut
);