Only call TOOLBAR_CalcToolbar when parameters change.
[wine/gsoc_dplay.git] / dlls / oleaut32 / safearray.c
blob7a8527d899183cdcd41c8e2fb0d944cf00cc2523
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 "debugtools.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 static const 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 static const int LAST_VARTYPE = sizeof(VARTYPE_SIZE)/sizeof(ULONG);
105 /*************************************************************************
106 * SafeArrayAllocDescriptor
107 * Allocate the appropriate amount of memory for the SafeArray descriptor
109 HRESULT WINAPI SafeArrayAllocDescriptor(
110 UINT cDims,
111 SAFEARRAY **ppsaOut)
113 SAFEARRAYBOUND *sab;
114 LONG allocSize = 0;
116 /* SAFEARRAY + SAFEARRAYBOUND * (cDims -1) ( -1 because there is already one
117 ( in SAFEARRAY struct */
118 allocSize = sizeof(**ppsaOut) + (sizeof(*sab) * (cDims-1));
120 /* Allocate memory for SAFEARRAY struc */
121 if(( (*ppsaOut)=HeapAlloc(
122 GetProcessHeap(), HEAP_ZERO_MEMORY, allocSize)) == NULL){
123 return(E_UNEXPECTED);
125 TRACE("SafeArray: %lu bytes allocated for descriptor.\n", allocSize);
127 return(S_OK);
130 /*************************************************************************
131 * SafeArrayAllocData
132 * Allocate the appropriate amount of data for the SafeArray data
134 HRESULT WINAPI SafeArrayAllocData(
135 SAFEARRAY *psa)
137 ULONG ulWholeArraySize; /* to store the size of the whole thing */
139 if(! validArg(psa))
140 return E_INVALIDARG;
142 ulWholeArraySize = getArraySize(psa);
144 /* Allocate memory for the data itself */
145 if((psa->pvData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
146 psa->cbElements*ulWholeArraySize)) == NULL)
147 return(E_UNEXPECTED);
149 TRACE("SafeArray: %lu bytes allocated for data at %p (%lu objects).\n",
150 psa->cbElements*ulWholeArraySize, psa->pvData, ulWholeArraySize);
152 return(S_OK);
155 /*************************************************************************
156 * SafeArrayCreate
157 * Create a SafeArray object by encapsulating AllocDescriptor and AllocData
159 SAFEARRAY* WINAPI SafeArrayCreate(
160 VARTYPE vt,
161 UINT cDims,
162 SAFEARRAYBOUND *rgsabound)
164 SAFEARRAY *psa;
165 HRESULT hRes;
166 USHORT cDim;
168 /* Validate supported VARTYPE */
169 if ( (vt >= LAST_VARTYPE) ||
170 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
171 return NULL;
173 /* Allocate memory for the array descriptor */
174 if( FAILED( hRes = SafeArrayAllocDescriptor(cDims, &psa)))
175 return NULL;
177 /* setup data members... */
178 psa->cDims = cDims;
179 psa->fFeatures = getFeatures(vt);
180 psa->cLocks = 0;
181 psa->pvData = NULL;
182 psa->cbElements= VARTYPE_SIZE[vt];
184 /* Invert the bounds ... */
185 for(cDim=0; cDim < psa->cDims; cDim++) {
186 psa->rgsabound[cDim].cElements = rgsabound[psa->cDims-cDim-1].cElements;
187 psa->rgsabound[cDim].lLbound = rgsabound[psa->cDims-cDim-1].lLbound;
190 /* allocate memory for the data... */
191 if( FAILED( hRes = SafeArrayAllocData(psa))) {
192 SafeArrayDestroyDescriptor(psa);
193 ERR("() : Failed to allocate the Safe Array data\n");
194 return NULL;
197 return(psa);
200 /*************************************************************************
201 * SafeArrayDestroyDescriptor
202 * Frees the memory associated with the descriptor.
204 HRESULT WINAPI SafeArrayDestroyDescriptor(
205 SAFEARRAY *psa)
207 /* Check for lockness before to free... */
208 if(psa->cLocks > 0)
209 return DISP_E_ARRAYISLOCKED;
211 /* The array is unlocked, then, deallocate memory */
212 if(HeapFree( GetProcessHeap(), 0, psa) == FALSE)
213 return E_UNEXPECTED;
215 return(S_OK);
219 /*************************************************************************
220 * SafeArrayLock
221 * Increment the lock counter
223 * Doc says (MSDN Library ) that psa->pvData should be made available (!= NULL)
224 * only when psa->cLocks is > 0... I don't get it since pvData is allocated
225 * before the array is locked, therefore
227 HRESULT WINAPI SafeArrayLock(
228 SAFEARRAY *psa)
230 if(! validArg(psa))
231 return E_INVALIDARG;
233 psa->cLocks++;
235 return(S_OK);
238 /*************************************************************************
239 * SafeArrayUnlock
240 * Decrement the lock counter
242 HRESULT WINAPI SafeArrayUnlock(
243 SAFEARRAY *psa)
245 if(! validArg(psa))
246 return E_INVALIDARG;
248 if (psa->cLocks > 0)
249 psa->cLocks--;
251 return(S_OK);
255 /*************************************************************************
256 * SafeArrayPutElement
257 * Set the data at the given coordinate
259 HRESULT WINAPI SafeArrayPutElement(
260 SAFEARRAY *psa,
261 LONG *rgIndices,
262 void *pv)
264 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
265 the desired one... */
266 PVOID elementStorageAddress = NULL; /* Adress to store the data */
267 BSTR pbstrReAllocStr = NULL; /* BSTR reallocated */
269 /* Validate the index given */
270 if(! validCoordinate(rgIndices, psa))
271 return DISP_E_BADINDEX;
272 if(! validArg(psa))
273 return E_INVALIDARG;
275 if( SafeArrayLock(psa) == S_OK) {
277 /* Figure out the number of items to skip */
278 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
280 /* Figure out the number of byte to skip ... */
281 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
283 if(isPointer(psa->fFeatures)) { /* increment ref count for this pointer */
285 *((VOID**)elementStorageAddress) = *(VOID**)pv;
286 IUnknown_AddRef( *(IUnknown**)pv);
288 } else {
290 if(psa->fFeatures == FADF_BSTR) { /* Create a new object */
292 if((pbstrReAllocStr = SysAllocString( (OLECHAR*)pv )) == NULL) {
293 SafeArrayUnlock(psa);
294 return E_OUTOFMEMORY;
295 } else
296 *((BSTR*)elementStorageAddress) = pbstrReAllocStr;
298 } else /* dupplicate the memory */
299 memcpy(elementStorageAddress, pv, SafeArrayGetElemsize(psa) );
302 } else {
303 ERR("SafeArray: Cannot lock array....\n");
304 return E_UNEXPECTED; /* UNDOC error condition */
307 TRACE("SafeArray: item put at adress %p.\n",elementStorageAddress);
308 return SafeArrayUnlock(psa);
312 /*************************************************************************
313 * SafeArrayGetElement
314 * Return the data element corresponding the the given coordinate
316 HRESULT WINAPI SafeArrayGetElement(
317 SAFEARRAY *psa,
318 LONG *rgIndices,
319 void *pv)
321 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
322 the desired one... */
323 PVOID elementStorageAddress = NULL; /* Adress to store the data */
324 BSTR pbstrReturnedStr = NULL; /* BSTR reallocated */
326 if(! validArg(psa))
327 return E_INVALIDARG;
329 if(! validCoordinate(rgIndices, psa)) /* Validate the index given */
330 return(DISP_E_BADINDEX);
332 if( SafeArrayLock(psa) == S_OK) {
334 /* Figure out the number of items to skip */
335 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
337 /* Figure out the number of byte to skip ... */
338 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
340 if( psa->fFeatures == FADF_BSTR) { /* reallocate the obj */
341 if( (pbstrReturnedStr =
342 SysAllocString( *(OLECHAR**)elementStorageAddress )) == NULL) {
343 SafeArrayUnlock(psa);
344 return E_OUTOFMEMORY;
345 } else
346 *((BSTR*)pv) = pbstrReturnedStr;
348 } else if( isPointer(psa->fFeatures) ) /* simply copy the pointer */
349 pv = *((PVOID*)elementStorageAddress);
350 else /* copy the bytes */
351 memcpy(pv, elementStorageAddress, SafeArrayGetElemsize(psa) );
353 } else {
354 ERR("SafeArray: Cannot lock array....\n");
355 return E_UNEXPECTED; /* UNDOC error condition */
358 return( SafeArrayUnlock(psa) );
361 /*************************************************************************
362 * SafeArrayGetUBound
363 * return the UP bound for a given array dimension
365 HRESULT WINAPI SafeArrayGetUBound(
366 SAFEARRAY *psa,
367 UINT nDim,
368 LONG *plUbound)
370 if(! validArg(psa))
371 return E_INVALIDARG;
373 if(nDim > psa->cDims)
374 return DISP_E_BADINDEX;
376 if(0 == nDim)
377 return DISP_E_BADINDEX;
379 *plUbound = psa->rgsabound[nDim-1].lLbound +
380 psa->rgsabound[nDim-1].cElements - 1;
382 return S_OK;
385 /*************************************************************************
386 * SafeArrayGetLBound
387 * Return the LO bound for a given array dimension
389 HRESULT WINAPI SafeArrayGetLBound(
390 SAFEARRAY *psa,
391 UINT nDim,
392 LONG *plLbound)
394 if(! validArg(psa))
395 return E_INVALIDARG;
397 if(nDim > psa->cDims)
398 return DISP_E_BADINDEX;
400 if(0 == nDim)
401 return DISP_E_BADINDEX;
403 *plLbound = psa->rgsabound[nDim-1].lLbound;
404 return S_OK;
407 /*************************************************************************
408 * SafeArrayGetDim
409 * returns the number of dimension in the array
411 UINT WINAPI SafeArrayGetDim(
412 SAFEARRAY * psa)
415 * A quick test in Windows shows that the behavior here for an invalid
416 * pointer is to return 0.
418 if(! validArg(psa))
419 return 0;
421 return psa->cDims;
424 /*************************************************************************
425 * SafeArrayGetElemsize
426 * Return the size of the element in the array
428 UINT WINAPI SafeArrayGetElemsize(
429 SAFEARRAY * psa)
432 * A quick test in Windows shows that the behavior here for an invalid
433 * pointer is to return 0.
435 if(! validArg(psa))
436 return 0;
438 return psa->cbElements;
441 /*************************************************************************
442 * SafeArrayAccessData
443 * increment the access count and return the data
445 HRESULT WINAPI SafeArrayAccessData(
446 SAFEARRAY *psa,
447 void **ppvData)
449 HRESULT hRes;
451 if(! validArg(psa))
452 return E_INVALIDARG;
454 hRes = SafeArrayLock(psa);
456 switch (hRes) {
457 case S_OK:
458 (*ppvData) = psa->pvData;
459 break;
460 case E_INVALIDARG:
461 (*ppvData) = NULL;
462 return E_INVALIDARG;
465 return S_OK;
469 /*************************************************************************
470 * SafeArrayUnaccessData
471 * Decrement the access count
473 HRESULT WINAPI SafeArrayUnaccessData(
474 SAFEARRAY * psa)
476 if(! validArg(psa))
477 return E_INVALIDARG;
479 return(SafeArrayUnlock(psa));
482 /************************************************************************
483 * SafeArrayPtrOfIndex
484 * Return a pointer to the element at rgIndices
486 HRESULT WINAPI SafeArrayPtrOfIndex(
487 SAFEARRAY *psa,
488 LONG *rgIndices,
489 void **ppvData)
491 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
492 the desired one... */
494 if(! validArg(psa))
495 return E_INVALIDARG;
497 if(! validCoordinate(rgIndices, psa))
498 return DISP_E_BADINDEX;
500 /* Figure out the number of items to skip */
501 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
503 *ppvData = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
505 return S_OK;
508 /************************************************************************
509 * SafeArrayDestroyData
510 * Frees the memory data bloc
512 HRESULT WINAPI SafeArrayDestroyData(
513 SAFEARRAY *psa)
515 HRESULT hRes;
516 ULONG ulWholeArraySize; /* count spot in array */
517 ULONG ulDataIter; /* to iterate the data space */
518 IUnknown *punk;
519 BSTR bstr;
521 if(! validArg(psa))
522 return E_INVALIDARG;
524 if(psa->cLocks > 0)
525 return DISP_E_ARRAYISLOCKED;
527 ulWholeArraySize = getArraySize(psa);
529 if(isPointer(psa->fFeatures)) { /* release the pointers */
531 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
532 punk = *(IUnknown**)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
534 if( punk != NULL)
535 IUnknown_Release(punk);
538 } else if(psa->fFeatures & FADF_BSTR) { /* deallocate the obj */
540 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
541 bstr = *(BSTR*)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
543 if( bstr != NULL)
544 SysFreeString( bstr );
548 /* check if this array is a Vector, in which case do not free the data
549 block since it has been allocated by AllocDescriptor and therefore
550 deserve to be freed by DestroyDescriptor */
551 if(!(psa->fFeatures & FADF_CREATEVECTOR)) { /* Set when we do CreateVector */
553 /* free the whole chunk */
554 if((hRes = HeapFree( GetProcessHeap(), 0, psa->pvData)) == 0) /*falied*/
555 return E_UNEXPECTED; /* UNDOC error condition */
557 psa->pvData = NULL;
560 return S_OK;
563 /************************************************************************
564 * SafeArrayCopyData
565 * Copy the psaSource's data block into psaTarget if dimension and size
566 * permits it.
568 HRESULT WINAPI SafeArrayCopyData(
569 SAFEARRAY *psaSource,
570 SAFEARRAY **psaTarget)
572 USHORT cDimCount; /* looper */
573 LONG lDelta; /* looper */
574 IUnknown *punk;
575 ULONG ulWholeArraySize; /* Number of item in SA */
576 BSTR bstr;
578 if(! (validArg(psaSource) && validArg(*psaTarget)) )
579 return E_INVALIDARG;
581 if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(*psaTarget))
582 return E_INVALIDARG;
584 ulWholeArraySize = getArraySize(psaSource);
586 /* The two arrays boundaries must be of same lenght */
587 for(cDimCount=0;cDimCount < psaSource->cDims; cDimCount++)
588 if( psaSource->rgsabound[cDimCount].cElements !=
589 (*psaTarget)->rgsabound[cDimCount].cElements)
590 return E_INVALIDARG;
592 if( isPointer((*psaTarget)->fFeatures) ) { /* the target contains ptr
593 that must be released */
594 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
595 punk = *(IUnknown**)
596 ((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
598 if( punk != NULL)
599 IUnknown_Release(punk);
602 } else if( (*psaTarget)->fFeatures & FADF_BSTR) { /* the target contain BSTR
603 that must be freed */
604 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
605 bstr =
606 *(BSTR*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
608 if( bstr != NULL)
609 SysFreeString( bstr );
613 return duplicateData(psaSource, psaTarget);
616 /************************************************************************
617 * SafeArrayDestroy
618 * Deallocates all memory reserved for the SafeArray
620 HRESULT WINAPI SafeArrayDestroy(
621 SAFEARRAY * psa)
623 HRESULT hRes;
625 if(! validArg(psa))
626 return E_INVALIDARG;
628 if(psa->cLocks > 0)
629 return DISP_E_ARRAYISLOCKED;
631 if((hRes = SafeArrayDestroyData( psa )) == S_OK)
632 if((hRes = SafeArrayDestroyDescriptor( psa )) == S_OK)
633 return S_OK;
635 return E_UNEXPECTED; /* UNDOC error condition */
638 /************************************************************************
639 * SafeArrayCopy
640 * Make a dupplicate of a SafeArray
642 HRESULT WINAPI SafeArrayCopy(
643 SAFEARRAY *psa,
644 SAFEARRAY **ppsaOut)
646 HRESULT hRes;
647 DWORD dAllocSize;
648 ULONG ulWholeArraySize; /* size of the thing */
650 if(! validArg(psa))
651 return E_INVALIDARG;
653 if((hRes=SafeArrayAllocDescriptor(psa->cDims, ppsaOut)) == S_OK){
655 /* Duplicate the SAFEARRAY struc */
656 memcpy(*ppsaOut, psa,
657 sizeof(*psa)+(sizeof(*(psa->rgsabound))*(psa->cDims-1)));
659 (*ppsaOut)->pvData = NULL; /* do not point to the same data area */
661 /* make sure the new safe array doesn't have the FADF_CREATEVECTOR flag,
662 because the data has not been allocated with the descriptor. */
663 (*ppsaOut)->fFeatures &= ~FADF_CREATEVECTOR;
665 /* Get the allocated memory size for source and allocate it for target */
666 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
667 dAllocSize = ulWholeArraySize*psa->cbElements;
669 (*ppsaOut)->pvData =
670 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dAllocSize);
671 if( (*ppsaOut)->pvData != NULL) { /* HeapAlloc succeed */
673 if( (hRes=duplicateData(psa, ppsaOut)) != S_OK) { /* E_OUTOFMEMORY */
674 HeapFree(GetProcessHeap(), 0, (*ppsaOut)->pvData);
675 (*ppsaOut)->pvData = NULL;
676 SafeArrayDestroyDescriptor(*ppsaOut);
677 return hRes;
680 } else { /* failed to allocate or dupplicate... */
681 SafeArrayDestroyDescriptor(*ppsaOut);
682 return E_UNEXPECTED; /* UNDOC error condition */
684 } else { /* failed to allocate mem for descriptor */
685 return E_OUTOFMEMORY; /* UNDOC error condiftion */
688 return S_OK;
691 /************************************************************************
692 * SafeArrayCreateVector
693 * Creates a one dimension safearray where the data is next to the
694 * SAFEARRAY structure.
696 SAFEARRAY* WINAPI SafeArrayCreateVector(
697 VARTYPE vt,
698 LONG lLbound,
699 ULONG cElements)
701 SAFEARRAY *psa;
703 /* Validate supported VARTYPE */
704 if ( (vt >= LAST_VARTYPE) ||
705 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
706 return NULL;
708 /* Allocate memory for the array descriptor and data contiguously */
709 if( FAILED( psa = HeapAlloc( GetProcessHeap(),
710 HEAP_ZERO_MEMORY,
711 (sizeof(*psa) + (VARTYPE_SIZE[vt] * cElements))))) {
712 return NULL;
715 /* setup data members... */
716 psa->cDims = 1; /* always and forever */
717 psa->fFeatures = getFeatures(vt) | FADF_CREATEVECTOR; /* undocumented flag used by Microsoft */
718 psa->cLocks = 0;
719 psa->pvData = (BYTE*)psa + sizeof(*psa);
720 psa->cbElements = VARTYPE_SIZE[vt];
722 psa->rgsabound[0].cElements = cElements;
723 psa->rgsabound[0].lLbound = lLbound;
725 return(psa);
728 /************************************************************************
729 * SafeArrayRedim
730 * Changes the caracteristics of the last dimension of the SafeArray
732 HRESULT WINAPI SafeArrayRedim(
733 SAFEARRAY *psa,
734 SAFEARRAYBOUND *psaboundNew)
736 LONG lDelta; /* hold difference in size */
737 USHORT cDims=1; /* dims counter */
739 if( !validArg(psa) )
740 return E_INVALIDARG;
742 if( psa->cLocks > 0 )
743 return DISP_E_ARRAYISLOCKED;
745 if( psa->fFeatures & FADF_FIXEDSIZE )
746 return E_INVALIDARG;
748 if( SafeArrayLock(psa)==E_UNEXPECTED )
749 return E_UNEXPECTED;/* UNDOC error condition */
751 /* find the delta in number of array spot to apply to the new array */
752 lDelta = psaboundNew->cElements - psa->rgsabound[0].cElements;
753 for(; cDims < psa->cDims; cDims++)
754 /* delta in number of spot implied by modifying the last dimension */
755 lDelta *= psa->rgsabound[cDims].cElements;
757 if (lDelta == 0) { ;/* same size, maybe a change of lLbound, just set it */
759 } else /* need to enlarge (lDelta +) reduce (lDelta -) */
760 if(! resizeSafeArray(psa, lDelta))
761 return E_UNEXPECTED; /* UNDOC error condition */
763 /* the only modifyable dimension sits in [0] as the dimensions were reversed
764 at array creation time... */
765 psa->rgsabound[0].cElements = psaboundNew->cElements;
766 psa->rgsabound[0].lLbound = psaboundNew->lLbound;
768 return SafeArrayUnlock(psa);
771 /************************************************************************
772 * NOT WINDOWS API - SafeArray* Utility functions
773 ************************************************************************/
775 /************************************************************************
776 * Used to validate the SAFEARRAY type of arg
778 static BOOL validArg(
779 SAFEARRAY *psa)
781 SAFEARRAYBOUND *sab;
782 LONG psaSize = 0;
783 LONG descSize = 0;
784 LONG fullSize = 0;
787 * Let's check for the null pointer just in case.
789 if (psa == NULL)
790 return FALSE;
792 /* Check whether the size of the chunk makes sense... That's the only thing
793 I can think of now... */
795 psaSize = HeapSize(GetProcessHeap(), 0, psa);
796 if (psaSize == -1)
797 /* uh, foreign heap. Better don't mess with it ! */
798 return TRUE;
800 /* size of the descriptor when the SA is not created with CreateVector */
801 descSize = sizeof(*psa) + (sizeof(*sab) * (psa->cDims-1));
803 /* size of the descriptor + data when created with CreateVector */
804 fullSize = sizeof(*psa) + (psa->cbElements * psa->rgsabound[0].cElements);
806 return((psaSize >= descSize) || (psaSize >= fullSize));
809 /************************************************************************
810 * Used to reallocate memory
812 static BOOL resizeSafeArray(
813 SAFEARRAY *psa,
814 LONG lDelta)
816 ULONG ulWholeArraySize; /* use as multiplicator */
817 PVOID pvNewBlock = NULL;
818 IUnknown *punk;
819 BSTR bstr;
821 ulWholeArraySize = getArraySize(psa);
823 if(lDelta < 0) { /* array needs to be shorthen */
824 if( isPointer(psa->fFeatures)) /* ptr that need to be released */
825 for(;lDelta < 0; lDelta++) {
826 punk = *(IUnknown**)
827 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
829 if( punk != NULL )
830 IUnknown_Release(punk);
833 else if(psa->fFeatures & FADF_BSTR) /* BSTR that need to be freed */
834 for(;lDelta < 0; lDelta++) {
835 bstr = *(BSTR*)
836 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
838 if( bstr != NULL )
839 SysFreeString( bstr );
843 if (!(psa->fFeatures & FADF_CREATEVECTOR))
845 /* Ok now, if we are enlarging the array, we *MUST* move the whole block
846 pointed to by pvData. If we are shorthening the array, this move is
847 optional but we do it anyway becuase the benefit is that we are
848 releasing to the system the unused memory */
850 if((pvNewBlock = HeapReAlloc(GetProcessHeap(), 0, psa->pvData,
851 (ulWholeArraySize + lDelta) * psa->cbElements)) == NULL)
852 return FALSE; /* TODO If we get here it means:
853 SHRINK situation : we've deleted the undesired
854 data and did not release the memory
855 GROWING situation: we've been unable to grow the array
858 else
860 /* Allocate a new block, because the previous data has been allocated with
861 the descriptor in SafeArrayCreateVector function. */
863 if((pvNewBlock = HeapAlloc(GetProcessHeap(), 0,
864 ulWholeArraySize * psa->cbElements)) == NULL)
865 return FALSE;
867 psa->fFeatures &= ~FADF_CREATEVECTOR;
869 /* reassign to the new block of data */
870 psa->pvData = pvNewBlock;
871 return TRUE;
874 /************************************************************************
875 * Used to set the fFeatures data member of the SAFEARRAY structure.
877 static INT getFeatures(
878 VARTYPE vt)
880 switch(vt) {
881 case VT_UNKNOWN: return FADF_UNKNOWN;
882 case VT_DISPATCH: return FADF_DISPATCH;
883 case VT_BSTR: return FADF_BSTR;
885 return 0;
888 /************************************************************************
889 * Used to figure out if the fFeatures data member of the SAFEARRAY
890 * structure contain any information about the type of data stored...
892 static BOOL isPointer(
893 USHORT feature)
895 switch(feature) {
896 case FADF_UNKNOWN: return TRUE; /* those are pointers */
897 case FADF_DISPATCH: return TRUE;
899 return FALSE;
902 /************************************************************************
903 * Used to calculate the displacement when accessing or modifying
904 * safearray data set.
906 * Parameters: - LONG *coor is the desired location in the multidimension
907 * table. Ex for a 3 dim table: coor[] = {1,2,3};
908 * - ULONG *mat is the format of the table. Ex for a 3 dim
909 * table mat[] = {4,4,4};
910 * - USHORT dim is the number of dimension of the SafeArray
912 static ULONG calcDisplacement(
913 LONG *coor,
914 SAFEARRAYBOUND *mat,
915 LONG dim)
917 ULONG res = 0;
918 LONG iterDim;
920 for(iterDim=0; iterDim<dim; iterDim++)
921 /* the -mat[dim] bring coor[dim] relative to 0 for calculation */
922 res += ((coor[iterDim]-mat[iterDim].lLbound) *
923 endOfDim(coor, mat, iterDim+1, dim));
925 TRACE("SafeArray: calculated displacement is %lu.\n", res);
926 return(res);
929 /************************************************************************
930 * Recursivity agent for calcDisplacement method. Used within Put and
931 * Get methods.
933 static INT endOfDim(
934 LONG *coor,
935 SAFEARRAYBOUND *mat,
936 LONG dim,
937 LONG realDim)
939 if(dim==realDim)
940 return 1;
941 else
942 return (endOfDim(coor, mat, dim+1, realDim) * mat[dim].cElements);
946 /************************************************************************
947 * Method used to validate the coordinate received in Put and Get
948 * methods.
950 static BOOL validCoordinate(
951 LONG *coor,
952 SAFEARRAY *psa)
954 INT iter=0;
955 LONG lUBound;
956 LONG lLBound;
957 HRESULT hRes;
959 for(; iter<psa->cDims; iter++) {
960 if((hRes = SafeArrayGetLBound(psa, (iter+1), &lLBound)) != S_OK)
961 return FALSE;
962 if((hRes = SafeArrayGetUBound(psa, (iter+1), &lUBound)) != S_OK)
963 return FALSE;
965 if(lLBound == lUBound)
966 return FALSE;
968 if((coor[iter] >= lLBound) && (coor[iter] <= lUBound))
969 return TRUE;
970 else
971 return FALSE;
973 return FALSE;
976 /************************************************************************
977 * Method used to calculate the number of cells of the SA
979 static ULONG getArraySize(
980 SAFEARRAY *psa)
982 USHORT cCount;
983 ULONG ulWholeArraySize = 1;
985 for(cCount=0; cCount < psa->cDims; cCount++) /* foreach dimensions... */
986 ulWholeArraySize *= psa->rgsabound[cCount].cElements;
988 return ulWholeArraySize;
992 /************************************************************************
993 * Method used to handle data space dupplication for Copy32 and CopyData32
995 static HRESULT duplicateData(
996 SAFEARRAY *psa,
997 SAFEARRAY **ppsaOut)
999 ULONG ulWholeArraySize; /* size of the thing */
1000 LONG lDelta;
1001 IUnknown *punk;
1002 BSTR pbstrReAllocStr = NULL; /* BSTR reallocated */
1004 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
1006 SafeArrayLock(*ppsaOut);
1008 if( isPointer(psa->fFeatures) ) { /* If datatype is object increment
1009 object's reference count */
1011 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1012 punk = *(IUnknown**)((char *) psa->pvData+(lDelta * psa->cbElements));
1014 if( punk != NULL)
1015 IUnknown_AddRef(punk);
1018 /* Copy the source array data into target array */
1019 memcpy((*ppsaOut)->pvData, psa->pvData,
1020 ulWholeArraySize*psa->cbElements);
1022 } else if( psa->fFeatures & FADF_BSTR ) { /* if datatype is BSTR allocate
1023 the BSTR in the new array */
1025 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1026 if(( pbstrReAllocStr = SysAllocString(
1027 *(BSTR*)((char *) psa->pvData+(lDelta * psa->cbElements)))) == NULL) {
1029 SafeArrayUnlock(*ppsaOut);
1030 return E_OUTOFMEMORY;
1033 *((BSTR*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements))) =
1034 pbstrReAllocStr;
1037 } else { /* Simply copy the source array data into target array */
1039 memcpy((*ppsaOut)->pvData, psa->pvData,
1040 ulWholeArraySize*psa->cbElements);
1043 SafeArrayUnlock(*ppsaOut);
1045 return S_OK;
1049 /************************************************************************
1050 * SafeArrayGetVarType
1051 * Returns the VARTYPE stored in the given safearray
1053 HRESULT WINAPI SafeArrayGetVarType(
1054 SAFEARRAY* psa,
1055 VARTYPE* pvt)
1057 HRESULT hr = E_INVALIDARG;
1058 VARTYPE vt = VT_EMPTY;
1060 /* const short VARTYPE_OFFSET = -4; */
1062 if (psa->fFeatures & FADF_HAVEVARTYPE)
1064 /* VT tag @ negative offset 4 in the array descriptor */
1065 FIXME("Returning VT_BSTR instead of VT_...");
1066 vt = VT_BSTR;
1068 else if (psa->fFeatures & FADF_RECORD)
1070 vt = VT_RECORD;
1072 else if (psa->fFeatures & FADF_DISPATCH)
1074 vt = VT_DISPATCH;
1076 else if (psa->fFeatures & FADF_UNKNOWN)
1078 vt = VT_UNKNOWN;
1081 if (vt != VT_EMPTY)
1083 *pvt = vt;
1084 hr = S_OK;
1087 TRACE("HRESULT = %08lx", hr);
1088 return hr;