Cosmetics.
[wine.git] / ole / safearray.c
blob6b3e62a134ac4d7f9775e31f3a39c3c7696f4a63
1 /*************************************************************************
2 * OLE Automation
3 * SafeArray Implementation
5 * This file contains the implementation of the SafeArray interface.
7 * Copyright 1999 Sylvain St-Germain
8 */
10 #include <stdio.h>
11 #include <strings.h>
12 #include "windef.h"
13 #include "winerror.h"
14 #include "winbase.h"
15 #include "oleauto.h"
16 #include "wine/obj_base.h"
17 #include "debug.h"
19 /* Localy used methods */
20 static INT
21 endOfDim(LONG *coor, SAFEARRAYBOUND *mat, LONG dim, LONG realDim);
23 static ULONG
24 calcDisplacement(LONG *coor, SAFEARRAYBOUND *mat, LONG dim);
26 static BOOL
27 isPointer(USHORT feature);
29 static INT
30 getFeatures(VARTYPE vt);
32 static BOOL
33 validCoordinate(LONG *coor, SAFEARRAY *psa);
35 static BOOL
36 resizeSafeArray(SAFEARRAY *psa, LONG lDelta);
38 static BOOL
39 validArg(SAFEARRAY *psa);
41 static ULONG
42 getArraySize(SAFEARRAY *psa);
44 static HRESULT
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(
107 UINT cDims,
108 SAFEARRAY **ppsaOut)
110 SAFEARRAYBOUND *sab;
111 LONG allocSize = 0;
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);
124 return(S_OK);
127 /*************************************************************************
128 * Allocate the appropriate amount of data for the SafeArray data
130 HRESULT WINAPI SafeArrayAllocData(
131 SAFEARRAY *psa)
133 ULONG ulWholeArraySize; /* to store the size of the whole thing */
135 if(! validArg(psa))
136 return E_INVALIDARG;
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);
148 return(S_OK);
151 /*************************************************************************
152 * Create a SafeArray object by encapsulating AllocDescriptor and AllocData
154 SAFEARRAY* WINAPI SafeArrayCreate(
155 VARTYPE vt,
156 UINT cDims,
157 SAFEARRAYBOUND *rgsabound)
159 SAFEARRAY *psa;
160 HRESULT hRes;
161 USHORT cDim;
163 /* Validate supported VARTYPE */
164 if ( (vt >= LAST_VARTYPE) ||
165 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
166 return NULL;
168 /* Allocate memory for the array descriptor */
169 if( FAILED( hRes = SafeArrayAllocDescriptor(cDims, &psa)))
170 return NULL;
172 /* setup data members... */
173 psa->cDims = cDims;
174 psa->fFeatures = getFeatures(vt);
175 psa->cLocks = 0;
176 psa->pvData = NULL;
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");
189 return NULL;
192 return(psa);
195 /*************************************************************************
196 * Frees the memory associated with the descriptor.
198 HRESULT WINAPI SafeArrayDestroyDescriptor(
199 SAFEARRAY *psa)
201 /* Check for lockness before to free... */
202 if(psa->cLocks > 0)
203 return DISP_E_ARRAYISLOCKED;
205 /* The array is unlocked, then, deallocate memory */
206 if(HeapFree( GetProcessHeap(), 0, psa) == FALSE)
207 return E_UNEXPECTED;
209 return(S_OK);
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(
221 SAFEARRAY *psa)
223 if(! validArg(psa))
224 return E_INVALIDARG;
226 psa->cLocks++;
228 return(S_OK);
231 /*************************************************************************
232 * Decrement the lock counter
234 HRESULT WINAPI SafeArrayUnlock(
235 SAFEARRAY *psa)
237 if(! validArg(psa))
238 return E_INVALIDARG;
240 if (psa->cLocks > 0)
241 psa->cLocks--;
243 return(S_OK);
247 /*************************************************************************
248 * Set the data at the given coordinate
250 HRESULT WINAPI SafeArrayPutElement(
251 SAFEARRAY *psa,
252 LONG *rgIndices,
253 void *pv)
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;
263 if(! validArg(psa))
264 return E_INVALIDARG;
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);
279 } else {
281 if(psa->fFeatures == FADF_BSTR) { /* Create a new object */
283 if((pbstrReAllocStr = SysAllocString( (OLECHAR*)pv )) == NULL) {
284 SafeArrayUnlock(psa);
285 return E_OUTOFMEMORY;
286 } else
287 *((BSTR*)elementStorageAddress) = pbstrReAllocStr;
289 } else /* dupplicate the memory */
290 memcpy(elementStorageAddress, pv, SafeArrayGetElemsize(psa) );
293 } else {
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(
307 SAFEARRAY *psa,
308 LONG *rgIndices,
309 void *pv)
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 */
316 if(! validArg(psa))
317 return E_INVALIDARG;
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;
335 } else
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) );
343 } else {
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(
355 SAFEARRAY *psa,
356 UINT nDim,
357 LONG *plUbound)
359 if(! validArg(psa))
360 return E_INVALIDARG;
362 if(nDim > psa->cDims)
363 return DISP_E_BADINDEX;
365 *plUbound = psa->rgsabound[nDim-1].lLbound +
366 psa->rgsabound[nDim-1].cElements - 1;
368 return S_OK;
371 /*************************************************************************
372 * Return the LO bound for a given array dimension
374 HRESULT WINAPI SafeArrayGetLBound(
375 SAFEARRAY *psa,
376 UINT nDim,
377 LONG *plLbound)
379 if(! validArg(psa))
380 return E_INVALIDARG;
382 if(nDim > psa->cDims)
383 return DISP_E_BADINDEX;
385 *plLbound = psa->rgsabound[nDim-1].lLbound;
386 return S_OK;
389 /*************************************************************************
390 * returns the number of dimension in the array
392 UINT WINAPI SafeArrayGetDim(
393 SAFEARRAY * psa)
396 * A quick test in Windows shows that the behavior here for an invalid
397 * pointer is to return 0.
399 if(! validArg(psa))
400 return 0;
402 return psa->cDims;
405 /*************************************************************************
406 * Return the size of the element in the array
408 UINT WINAPI SafeArrayGetElemsize(
409 SAFEARRAY * psa)
412 * A quick test in Windows shows that the behavior here for an invalid
413 * pointer is to return 0.
415 if(! validArg(psa))
416 return 0;
418 return psa->cbElements;
421 /*************************************************************************
422 * increment the access count and return the data
424 HRESULT WINAPI SafeArrayAccessData(
425 SAFEARRAY *psa,
426 void **ppvData)
428 HRESULT hRes;
430 if(! validArg(psa))
431 return E_INVALIDARG;
433 hRes = SafeArrayLock(psa);
435 switch (hRes) {
436 case S_OK:
437 (*ppvData) = psa->pvData;
438 break;
439 case E_INVALIDARG:
440 (*ppvData) = NULL;
441 return E_INVALIDARG;
444 return S_OK;
448 /*************************************************************************
449 * Decrement the access count
451 HRESULT WINAPI SafeArrayUnaccessData(
452 SAFEARRAY * psa)
454 if(! validArg(psa))
455 return E_INVALIDARG;
457 return(SafeArrayUnlock(psa));
460 /************************************************************************
461 * Return a pointer to the element at rgIndices
463 HRESULT WINAPI SafeArrayPtrOfIndex(
464 SAFEARRAY *psa,
465 LONG *rgIndices,
466 void **ppvData)
468 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
469 the desired one... */
471 if(! validArg(psa))
472 return E_INVALIDARG;
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);
482 return S_OK;
485 /************************************************************************
486 * Frees the memory data bloc
488 HRESULT WINAPI SafeArrayDestroyData(
489 SAFEARRAY *psa)
491 HRESULT hRes;
492 ULONG ulWholeArraySize; /* count spot in array */
493 ULONG ulDataIter; /* to iterate the data space */
494 IUnknown *punk;
495 BSTR bstr;
497 if(! validArg(psa))
498 return E_INVALIDARG;
500 if(psa->cLocks > 0)
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)));
510 if( punk != NULL)
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)));
519 if( bstr != NULL)
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 */
533 psa->pvData = NULL;
536 return S_OK;
539 /************************************************************************
540 * Copy the psaSource's data block into psaTarget if dimension and size
541 * permits it.
543 HRESULT WINAPI SafeArrayCopyData(
544 SAFEARRAY *psaSource,
545 SAFEARRAY **psaTarget)
547 USHORT cDimCount; /* looper */
548 LONG lDelta; /* looper */
549 IUnknown *punk;
550 ULONG ulWholeArraySize; /* Number of item in SA */
551 BSTR bstr;
553 if(! (validArg(psaSource) && validArg(*psaTarget)) )
554 return E_INVALIDARG;
556 if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(*psaTarget))
557 return E_INVALIDARG;
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)
565 return E_INVALIDARG;
567 if( isPointer((*psaTarget)->fFeatures) ) { /* the target contains ptr
568 that must be released */
569 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
570 punk = *(IUnknown**)
571 ((*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
573 if( punk != NULL)
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++) {
580 bstr =
581 *(BSTR*)((*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
583 if( bstr != NULL)
584 SysFreeString( bstr );
588 return duplicateData(psaSource, psaTarget);
591 /************************************************************************
592 * Deallocates all memory reserved for the SafeArray
594 HRESULT WINAPI SafeArrayDestroy(
595 SAFEARRAY * psa)
597 HRESULT hRes;
599 if(! validArg(psa))
600 return E_INVALIDARG;
602 if(psa->cLocks > 0)
603 return DISP_E_ARRAYISLOCKED;
605 if((hRes = SafeArrayDestroyData( psa )) == S_OK)
606 if((hRes = SafeArrayDestroyDescriptor( psa )) == S_OK)
607 return S_OK;
609 return E_UNEXPECTED; /* UNDOC error condition */
612 /************************************************************************
613 * Make a dupplicate of a SafeArray
615 HRESULT WINAPI SafeArrayCopy(
616 SAFEARRAY *psa,
617 SAFEARRAY **ppsaOut)
619 HRESULT hRes;
620 DWORD dAllocSize;
622 if(! validArg(psa))
623 return E_INVALIDARG;
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);
635 (*ppsaOut)->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);
644 return hRes;
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 */
655 return S_OK;
658 /************************************************************************
659 * Creates a one dimension safearray where the data is next to the
660 * SAFEARRAY structure.
662 SAFEARRAY* WINAPI SafeArrayCreateVector(
663 VARTYPE vt,
664 LONG lLbound,
665 ULONG cElements)
667 SAFEARRAY *psa;
669 /* Validate supported VARTYPE */
670 if ( (vt >= LAST_VARTYPE) ||
671 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
672 return NULL;
674 /* Allocate memory for the array descriptor and data contiguously */
675 if( FAILED( psa = HeapAlloc( GetProcessHeap(),
676 HEAP_ZERO_MEMORY,
677 (sizeof(*psa) + (VARTYPE_SIZE[vt] * cElements))))) {
678 return NULL;
681 /* setup data members... */
682 psa->cDims = 1; /* always and forever */
683 psa->fFeatures = getFeatures(vt) | FADF_FIXEDSIZE;
684 psa->cLocks = 0;
685 psa->pvData = psa+sizeof(*psa);
686 psa->cbElements = VARTYPE_SIZE[vt];
688 psa->rgsabound[0].cElements = cElements;
689 psa->rgsabound[0].lLbound = lLbound;
691 return(psa);
694 /************************************************************************
695 * Changes the caracteristics of the last dimension of the SafeArray
697 HRESULT WINAPI SafeArrayRedim(
698 SAFEARRAY *psa,
699 SAFEARRAYBOUND *psaboundNew)
701 LONG lDelta; /* hold difference in size */
702 USHORT cDims=1; /* dims counter */
704 if( !validArg(psa) )
705 return E_INVALIDARG;
707 if( psa->cLocks > 0 )
708 return DISP_E_ARRAYISLOCKED;
710 if( psa->fFeatures & FADF_FIXEDSIZE )
711 return E_INVALIDARG;
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(
744 SAFEARRAY *psa)
746 SAFEARRAYBOUND *sab;
747 LONG psaSize = 0;
748 LONG descSize = 0;
749 LONG fullSize = 0;
752 * Let's check for the null pointer just in case.
754 if (psa == NULL)
755 return FALSE;
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(
775 SAFEARRAY *psa,
776 LONG lDelta)
778 ULONG ulWholeArraySize; /* use as multiplicator */
779 PVOID pvNewBlock = NULL;
780 IUnknown *punk;
781 BSTR bstr;
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++) {
788 punk = *(IUnknown**)
789 (psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
791 if( punk != NULL )
792 IUnknown_Release(punk);
795 else if(psa->fFeatures & FADF_BSTR) /* BSTR that need to be freed */
796 for(;lDelta < 0; lDelta++) {
797 bstr = *(BSTR*)
798 (psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
800 if( bstr != NULL )
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;
820 return TRUE;
823 /************************************************************************
824 * Used to set the fFeatures data member of the SAFEARRAY structure.
826 static INT getFeatures(
827 VARTYPE vt)
829 switch(vt) {
830 case VT_UNKNOWN: return FADF_UNKNOWN;
831 case VT_DISPATCH: return FADF_DISPATCH;
832 case VT_BSTR: return FADF_BSTR;
834 return 0;
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(
842 USHORT feature)
844 switch(feature) {
845 case FADF_UNKNOWN: return TRUE; /* those are pointers */
846 case FADF_DISPATCH: return TRUE;
848 return FALSE;
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(
862 LONG *coor,
863 SAFEARRAYBOUND *mat,
864 LONG dim)
866 ULONG res = 0;
867 LONG iterDim;
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);
875 return(res);
878 /************************************************************************
879 * Recursivity agent for calcDisplacement method. Used within Put and
880 * Get methods.
882 static INT endOfDim(
883 LONG *coor,
884 SAFEARRAYBOUND *mat,
885 LONG dim,
886 LONG realDim)
888 if(dim==realDim)
889 return 1;
890 else
891 return (endOfDim(coor, mat, dim+1, realDim) * mat[dim].cElements);
895 /************************************************************************
896 * Method used to validate the coordinate received in Put and Get
897 * methods.
899 static BOOL validCoordinate(
900 LONG *coor,
901 SAFEARRAY *psa)
903 INT iter=0;
904 LONG lUBound;
905 LONG lLBound;
906 HRESULT hRes;
908 for(; iter<psa->cDims; iter++) {
909 if((hRes = SafeArrayGetLBound(psa, iter, &lLBound)) != S_OK)
910 return FALSE;
911 if((hRes = SafeArrayGetUBound(psa, iter, &lUBound)) != S_OK)
912 return FALSE;
914 if(lLBound == lUBound)
915 return FALSE;
917 if((coor[iter] >= lLBound) && (coor[iter] <= lUBound))
918 return TRUE;
919 else
920 return FALSE;
922 return FALSE;
925 /************************************************************************
926 * Method used to calculate the number of cells of the SA
928 static ULONG getArraySize(
929 SAFEARRAY *psa)
931 USHORT cCount;
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(
945 SAFEARRAY *psa,
946 SAFEARRAY **ppsaOut)
948 ULONG ulWholeArraySize; /* size of the thing */
949 LONG lDelta;
950 IUnknown *punk;
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));
963 if( punk != NULL)
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))) =
983 pbstrReAllocStr;
986 } else { /* Simply copy the source array data into target array */
988 memcpy((*ppsaOut)->pvData, psa->pvData,
989 ulWholeArraySize*psa->cbElements);
992 SafeArrayUnlock(*ppsaOut);
994 return S_OK;