enhmetafile added
[wine/multimedia.git] / ole / safearray.c
bloba5c8288831b1f843a946f533eca239d587dfd2ef
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 <string.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 DEFAULT_DEBUG_CHANNEL(ole)
21 /* Localy used methods */
22 static INT
23 endOfDim(LONG *coor, SAFEARRAYBOUND *mat, LONG dim, LONG realDim);
25 static ULONG
26 calcDisplacement(LONG *coor, SAFEARRAYBOUND *mat, LONG dim);
28 static BOOL
29 isPointer(USHORT feature);
31 static INT
32 getFeatures(VARTYPE vt);
34 static BOOL
35 validCoordinate(LONG *coor, SAFEARRAY *psa);
37 static BOOL
38 resizeSafeArray(SAFEARRAY *psa, LONG lDelta);
40 static BOOL
41 validArg(SAFEARRAY *psa);
43 static ULONG
44 getArraySize(SAFEARRAY *psa);
46 static HRESULT
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(
109 UINT cDims,
110 SAFEARRAY **ppsaOut)
112 SAFEARRAYBOUND *sab;
113 LONG allocSize = 0;
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(ole,"SafeArray: %lu bytes allocated for descriptor.\n", allocSize);
126 return(S_OK);
129 /*************************************************************************
130 * Allocate the appropriate amount of data for the SafeArray data
132 HRESULT WINAPI SafeArrayAllocData(
133 SAFEARRAY *psa)
135 ULONG ulWholeArraySize; /* to store the size of the whole thing */
137 if(! validArg(psa))
138 return E_INVALIDARG;
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(ole, "SafeArray: %lu bytes allocated for data at %p (%lu objects).\n",
148 psa->cbElements*ulWholeArraySize, psa->pvData, ulWholeArraySize);
150 return(S_OK);
153 /*************************************************************************
154 * Create a SafeArray object by encapsulating AllocDescriptor and AllocData
156 SAFEARRAY* WINAPI SafeArrayCreate(
157 VARTYPE vt,
158 UINT cDims,
159 SAFEARRAYBOUND *rgsabound)
161 SAFEARRAY *psa;
162 HRESULT hRes;
163 USHORT cDim;
165 /* Validate supported VARTYPE */
166 if ( (vt >= LAST_VARTYPE) ||
167 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
168 return NULL;
170 /* Allocate memory for the array descriptor */
171 if( FAILED( hRes = SafeArrayAllocDescriptor(cDims, &psa)))
172 return NULL;
174 /* setup data members... */
175 psa->cDims = cDims;
176 psa->fFeatures = getFeatures(vt);
177 psa->cLocks = 0;
178 psa->pvData = NULL;
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(ole,"() : Failed to allocate the Safe Array data\n");
191 return NULL;
194 return(psa);
197 /*************************************************************************
198 * Frees the memory associated with the descriptor.
200 HRESULT WINAPI SafeArrayDestroyDescriptor(
201 SAFEARRAY *psa)
203 /* Check for lockness before to free... */
204 if(psa->cLocks > 0)
205 return DISP_E_ARRAYISLOCKED;
207 /* The array is unlocked, then, deallocate memory */
208 if(HeapFree( GetProcessHeap(), 0, psa) == FALSE)
209 return E_UNEXPECTED;
211 return(S_OK);
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(
223 SAFEARRAY *psa)
225 if(! validArg(psa))
226 return E_INVALIDARG;
228 psa->cLocks++;
230 return(S_OK);
233 /*************************************************************************
234 * Decrement the lock counter
236 HRESULT WINAPI SafeArrayUnlock(
237 SAFEARRAY *psa)
239 if(! validArg(psa))
240 return E_INVALIDARG;
242 if (psa->cLocks > 0)
243 psa->cLocks--;
245 return(S_OK);
249 /*************************************************************************
250 * Set the data at the given coordinate
252 HRESULT WINAPI SafeArrayPutElement(
253 SAFEARRAY *psa,
254 LONG *rgIndices,
255 void *pv)
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;
265 if(! validArg(psa))
266 return E_INVALIDARG;
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);
281 } else {
283 if(psa->fFeatures == FADF_BSTR) { /* Create a new object */
285 if((pbstrReAllocStr = SysAllocString( (OLECHAR*)pv )) == NULL) {
286 SafeArrayUnlock(psa);
287 return E_OUTOFMEMORY;
288 } else
289 *((BSTR*)elementStorageAddress) = pbstrReAllocStr;
291 } else /* dupplicate the memory */
292 memcpy(elementStorageAddress, pv, SafeArrayGetElemsize(psa) );
295 } else {
296 ERR(ole, "SafeArray: Cannot lock array....\n");
297 return E_UNEXPECTED; /* UNDOC error condition */
300 TRACE(ole,"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(
309 SAFEARRAY *psa,
310 LONG *rgIndices,
311 void *pv)
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 */
318 if(! validArg(psa))
319 return E_INVALIDARG;
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;
337 } else
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) );
345 } else {
346 ERR(ole, "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(
357 SAFEARRAY *psa,
358 UINT nDim,
359 LONG *plUbound)
361 if(! validArg(psa))
362 return E_INVALIDARG;
364 if(nDim > psa->cDims)
365 return DISP_E_BADINDEX;
367 *plUbound = psa->rgsabound[nDim-1].lLbound +
368 psa->rgsabound[nDim-1].cElements - 1;
370 return S_OK;
373 /*************************************************************************
374 * Return the LO bound for a given array dimension
376 HRESULT WINAPI SafeArrayGetLBound(
377 SAFEARRAY *psa,
378 UINT nDim,
379 LONG *plLbound)
381 if(! validArg(psa))
382 return E_INVALIDARG;
384 if(nDim > psa->cDims)
385 return DISP_E_BADINDEX;
387 *plLbound = psa->rgsabound[nDim-1].lLbound;
388 return S_OK;
391 /*************************************************************************
392 * returns the number of dimension in the array
394 UINT WINAPI SafeArrayGetDim(
395 SAFEARRAY * psa)
398 * A quick test in Windows shows that the behavior here for an invalid
399 * pointer is to return 0.
401 if(! validArg(psa))
402 return 0;
404 return psa->cDims;
407 /*************************************************************************
408 * Return the size of the element in the array
410 UINT WINAPI SafeArrayGetElemsize(
411 SAFEARRAY * psa)
414 * A quick test in Windows shows that the behavior here for an invalid
415 * pointer is to return 0.
417 if(! validArg(psa))
418 return 0;
420 return psa->cbElements;
423 /*************************************************************************
424 * increment the access count and return the data
426 HRESULT WINAPI SafeArrayAccessData(
427 SAFEARRAY *psa,
428 void **ppvData)
430 HRESULT hRes;
432 if(! validArg(psa))
433 return E_INVALIDARG;
435 hRes = SafeArrayLock(psa);
437 switch (hRes) {
438 case S_OK:
439 (*ppvData) = psa->pvData;
440 break;
441 case E_INVALIDARG:
442 (*ppvData) = NULL;
443 return E_INVALIDARG;
446 return S_OK;
450 /*************************************************************************
451 * Decrement the access count
453 HRESULT WINAPI SafeArrayUnaccessData(
454 SAFEARRAY * psa)
456 if(! validArg(psa))
457 return E_INVALIDARG;
459 return(SafeArrayUnlock(psa));
462 /************************************************************************
463 * Return a pointer to the element at rgIndices
465 HRESULT WINAPI SafeArrayPtrOfIndex(
466 SAFEARRAY *psa,
467 LONG *rgIndices,
468 void **ppvData)
470 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
471 the desired one... */
473 if(! validArg(psa))
474 return E_INVALIDARG;
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);
484 return S_OK;
487 /************************************************************************
488 * Frees the memory data bloc
490 HRESULT WINAPI SafeArrayDestroyData(
491 SAFEARRAY *psa)
493 HRESULT hRes;
494 ULONG ulWholeArraySize; /* count spot in array */
495 ULONG ulDataIter; /* to iterate the data space */
496 IUnknown *punk;
497 BSTR bstr;
499 if(! validArg(psa))
500 return E_INVALIDARG;
502 if(psa->cLocks > 0)
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)));
512 if( punk != NULL)
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)));
521 if( bstr != NULL)
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 */
535 psa->pvData = NULL;
538 return S_OK;
541 /************************************************************************
542 * Copy the psaSource's data block into psaTarget if dimension and size
543 * permits it.
545 HRESULT WINAPI SafeArrayCopyData(
546 SAFEARRAY *psaSource,
547 SAFEARRAY **psaTarget)
549 USHORT cDimCount; /* looper */
550 LONG lDelta; /* looper */
551 IUnknown *punk;
552 ULONG ulWholeArraySize; /* Number of item in SA */
553 BSTR bstr;
555 if(! (validArg(psaSource) && validArg(*psaTarget)) )
556 return E_INVALIDARG;
558 if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(*psaTarget))
559 return E_INVALIDARG;
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)
567 return E_INVALIDARG;
569 if( isPointer((*psaTarget)->fFeatures) ) { /* the target contains ptr
570 that must be released */
571 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
572 punk = *(IUnknown**)
573 ((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
575 if( punk != NULL)
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++) {
582 bstr =
583 *(BSTR*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
585 if( bstr != NULL)
586 SysFreeString( bstr );
590 return duplicateData(psaSource, psaTarget);
593 /************************************************************************
594 * Deallocates all memory reserved for the SafeArray
596 HRESULT WINAPI SafeArrayDestroy(
597 SAFEARRAY * psa)
599 HRESULT hRes;
601 if(! validArg(psa))
602 return E_INVALIDARG;
604 if(psa->cLocks > 0)
605 return DISP_E_ARRAYISLOCKED;
607 if((hRes = SafeArrayDestroyData( psa )) == S_OK)
608 if((hRes = SafeArrayDestroyDescriptor( psa )) == S_OK)
609 return S_OK;
611 return E_UNEXPECTED; /* UNDOC error condition */
614 /************************************************************************
615 * Make a dupplicate of a SafeArray
617 HRESULT WINAPI SafeArrayCopy(
618 SAFEARRAY *psa,
619 SAFEARRAY **ppsaOut)
621 HRESULT hRes;
622 DWORD dAllocSize;
624 if(! validArg(psa))
625 return E_INVALIDARG;
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);
637 (*ppsaOut)->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);
646 return hRes;
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 */
657 return S_OK;
660 /************************************************************************
661 * Creates a one dimension safearray where the data is next to the
662 * SAFEARRAY structure.
664 SAFEARRAY* WINAPI SafeArrayCreateVector(
665 VARTYPE vt,
666 LONG lLbound,
667 ULONG cElements)
669 SAFEARRAY *psa;
671 /* Validate supported VARTYPE */
672 if ( (vt >= LAST_VARTYPE) ||
673 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
674 return NULL;
676 /* Allocate memory for the array descriptor and data contiguously */
677 if( FAILED( psa = HeapAlloc( GetProcessHeap(),
678 HEAP_ZERO_MEMORY,
679 (sizeof(*psa) + (VARTYPE_SIZE[vt] * cElements))))) {
680 return NULL;
683 /* setup data members... */
684 psa->cDims = 1; /* always and forever */
685 psa->fFeatures = getFeatures(vt) | FADF_FIXEDSIZE;
686 psa->cLocks = 0;
687 psa->pvData = psa+sizeof(*psa);
688 psa->cbElements = VARTYPE_SIZE[vt];
690 psa->rgsabound[0].cElements = cElements;
691 psa->rgsabound[0].lLbound = lLbound;
693 return(psa);
696 /************************************************************************
697 * Changes the caracteristics of the last dimension of the SafeArray
699 HRESULT WINAPI SafeArrayRedim(
700 SAFEARRAY *psa,
701 SAFEARRAYBOUND *psaboundNew)
703 LONG lDelta; /* hold difference in size */
704 USHORT cDims=1; /* dims counter */
706 if( !validArg(psa) )
707 return E_INVALIDARG;
709 if( psa->cLocks > 0 )
710 return DISP_E_ARRAYISLOCKED;
712 if( psa->fFeatures & FADF_FIXEDSIZE )
713 return E_INVALIDARG;
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(
746 SAFEARRAY *psa)
748 SAFEARRAYBOUND *sab;
749 LONG psaSize = 0;
750 LONG descSize = 0;
751 LONG fullSize = 0;
754 * Let's check for the null pointer just in case.
756 if (psa == NULL)
757 return FALSE;
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(
777 SAFEARRAY *psa,
778 LONG lDelta)
780 ULONG ulWholeArraySize; /* use as multiplicator */
781 PVOID pvNewBlock = NULL;
782 IUnknown *punk;
783 BSTR bstr;
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++) {
790 punk = *(IUnknown**)
791 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
793 if( punk != NULL )
794 IUnknown_Release(punk);
797 else if(psa->fFeatures & FADF_BSTR) /* BSTR that need to be freed */
798 for(;lDelta < 0; lDelta++) {
799 bstr = *(BSTR*)
800 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
802 if( bstr != NULL )
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;
822 return TRUE;
825 /************************************************************************
826 * Used to set the fFeatures data member of the SAFEARRAY structure.
828 static INT getFeatures(
829 VARTYPE vt)
831 switch(vt) {
832 case VT_UNKNOWN: return FADF_UNKNOWN;
833 case VT_DISPATCH: return FADF_DISPATCH;
834 case VT_BSTR: return FADF_BSTR;
836 return 0;
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(
844 USHORT feature)
846 switch(feature) {
847 case FADF_UNKNOWN: return TRUE; /* those are pointers */
848 case FADF_DISPATCH: return TRUE;
850 return FALSE;
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(
864 LONG *coor,
865 SAFEARRAYBOUND *mat,
866 LONG dim)
868 ULONG res = 0;
869 LONG iterDim;
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(ole, "SafeArray: calculated displacement is %lu.\n", res);
877 return(res);
880 /************************************************************************
881 * Recursivity agent for calcDisplacement method. Used within Put and
882 * Get methods.
884 static INT endOfDim(
885 LONG *coor,
886 SAFEARRAYBOUND *mat,
887 LONG dim,
888 LONG realDim)
890 if(dim==realDim)
891 return 1;
892 else
893 return (endOfDim(coor, mat, dim+1, realDim) * mat[dim].cElements);
897 /************************************************************************
898 * Method used to validate the coordinate received in Put and Get
899 * methods.
901 static BOOL validCoordinate(
902 LONG *coor,
903 SAFEARRAY *psa)
905 INT iter=0;
906 LONG lUBound;
907 LONG lLBound;
908 HRESULT hRes;
910 for(; iter<psa->cDims; iter++) {
911 if((hRes = SafeArrayGetLBound(psa, iter, &lLBound)) != S_OK)
912 return FALSE;
913 if((hRes = SafeArrayGetUBound(psa, iter, &lUBound)) != S_OK)
914 return FALSE;
916 if(lLBound == lUBound)
917 return FALSE;
919 if((coor[iter] >= lLBound) && (coor[iter] <= lUBound))
920 return TRUE;
921 else
922 return FALSE;
924 return FALSE;
927 /************************************************************************
928 * Method used to calculate the number of cells of the SA
930 static ULONG getArraySize(
931 SAFEARRAY *psa)
933 USHORT cCount;
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(
947 SAFEARRAY *psa,
948 SAFEARRAY **ppsaOut)
950 ULONG ulWholeArraySize; /* size of the thing */
951 LONG lDelta;
952 IUnknown *punk;
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));
965 if( punk != NULL)
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))) =
985 pbstrReAllocStr;
988 } else { /* Simply copy the source array data into target array */
990 memcpy((*ppsaOut)->pvData, psa->pvData,
991 ulWholeArraySize*psa->cbElements);
994 SafeArrayUnlock(*ppsaOut);
996 return S_OK;