All MCI functions are now cleanly separated.
[wine/hacks.git] / dlls / oleaut32 / safearray.c
blobdd416de69c1a46dcd6911e91a26e2fb9a8f79c85
1 /*************************************************************************
2 * OLE Automation
3 * SafeArray Implementation
5 * This file contains the implementation of the SafeArray interface.
7 * Copyright 1999 Sylvain St-Germain
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include <stdio.h>
25 #include <string.h>
26 #include "windef.h"
27 #include "winerror.h"
28 #include "winbase.h"
29 #include "oleauto.h"
30 #include "wine/obj_base.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(ole);
35 #define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
37 /* Locally used methods */
38 static INT
39 endOfDim(LONG *coor, SAFEARRAYBOUND *mat, LONG dim, LONG realDim);
41 static ULONG
42 calcDisplacement(LONG *coor, SAFEARRAYBOUND *mat, LONG dim);
44 static BOOL
45 isPointer(USHORT feature);
47 static INT
48 getFeatures(VARTYPE vt);
50 static BOOL
51 validCoordinate(LONG *coor, SAFEARRAY *psa);
53 static BOOL
54 resizeSafeArray(SAFEARRAY *psa, LONG lDelta);
56 static BOOL
57 validArg(SAFEARRAY *psa);
59 static ULONG
60 getArraySize(SAFEARRAY *psa);
62 static HRESULT
63 duplicateData(SAFEARRAY *psa, SAFEARRAY **ppsaOut);
65 /* Association between VARTYPE and their size.
66 A size of zero is defined for the unsupported types. */
68 #define VARTYPE_NOT_SUPPORTED 0
69 static const ULONG VARTYPE_SIZE[] =
71 /* this is taken from wtypes.h. Only [S]es are supported by the SafeArray */
72 VARTYPE_NOT_SUPPORTED, /* VT_EMPTY [V] [P] nothing */
73 VARTYPE_NOT_SUPPORTED, /* VT_NULL [V] [P] SQL style Nul */
74 2, /* VT_I2 [V][T][P][S] 2 byte signed int */
75 4, /* VT_I4 [V][T][P][S] 4 byte signed int */
76 4, /* VT_R4 [V][T][P][S] 4 byte real */
77 8, /* VT_R8 [V][T][P][S] 8 byte real */
78 8, /* VT_CY [V][T][P][S] currency */
79 8, /* VT_DATE [V][T][P][S] date */
80 sizeof(BSTR), /* VT_BSTR [V][T][P][S] OLE Automation string*/
81 sizeof(LPDISPATCH), /* VT_DISPATCH [V][T][P][S] IDispatch * */
82 4, /* VT_ERROR [V][T] [S] SCODE */
83 4, /* VT_BOOL [V][T][P][S] True=-1, False=0*/
84 sizeof(VARIANT), /* VT_VARIANT [V][T][P][S] VARIANT * */
85 sizeof(LPUNKNOWN), /* VT_UNKNOWN [V][T] [S] IUnknown * */
86 sizeof(DECIMAL), /* VT_DECIMAL [V][T] [S] 16 byte fixed point */
87 VARTYPE_NOT_SUPPORTED, /* no VARTYPE here..... */
88 VARTYPE_NOT_SUPPORTED, /* VT_I1 [T] signed char */
89 1, /* VT_UI1 [V][T][P][S] unsigned char */
90 VARTYPE_NOT_SUPPORTED, /* VT_UI2 [T][P] unsigned short */
91 VARTYPE_NOT_SUPPORTED, /* VT_UI4 [T][P] unsigned short */
92 VARTYPE_NOT_SUPPORTED, /* VT_I8 [T][P] signed 64-bit int */
93 VARTYPE_NOT_SUPPORTED, /* VT_UI8 [T][P] unsigned 64-bit int */
94 VARTYPE_NOT_SUPPORTED, /* VT_INT [T] signed machine int */
95 VARTYPE_NOT_SUPPORTED, /* VT_UINT [T] unsigned machine int */
96 VARTYPE_NOT_SUPPORTED, /* VT_VOID [T] C style void */
97 VARTYPE_NOT_SUPPORTED, /* VT_HRESULT [T] Standard return type */
98 VARTYPE_NOT_SUPPORTED, /* VT_PTR [T] pointer type */
99 VARTYPE_NOT_SUPPORTED, /* VT_SAFEARRAY [T] (use VT_ARRAY in VARIANT)*/
100 VARTYPE_NOT_SUPPORTED, /* VT_CARRAY [T] C style array */
101 VARTYPE_NOT_SUPPORTED, /* VT_USERDEFINED [T] user defined type */
102 VARTYPE_NOT_SUPPORTED, /* VT_LPSTR [T][P] null terminated string */
103 VARTYPE_NOT_SUPPORTED, /* VT_LPWSTR [T][P] wide null term string */
104 VARTYPE_NOT_SUPPORTED, /* VT_FILETIME [P] FILETIME */
105 VARTYPE_NOT_SUPPORTED, /* VT_BLOB [P] Length prefixed bytes */
106 VARTYPE_NOT_SUPPORTED, /* VT_STREAM [P] Name of stream follows */
107 VARTYPE_NOT_SUPPORTED, /* VT_STORAGE [P] Name of storage follows */
108 VARTYPE_NOT_SUPPORTED, /* VT_STREAMED_OBJECT[P] Stream contains an object*/
109 VARTYPE_NOT_SUPPORTED, /* VT_STORED_OBJECT [P] Storage contains object*/
110 VARTYPE_NOT_SUPPORTED, /* VT_BLOB_OBJECT [P] Blob contains an object*/
111 VARTYPE_NOT_SUPPORTED, /* VT_CF [P] Clipboard format */
112 VARTYPE_NOT_SUPPORTED, /* VT_CLSID [P] A Class ID */
113 VARTYPE_NOT_SUPPORTED, /* VT_VECTOR [P] simple counted array */
114 VARTYPE_NOT_SUPPORTED, /* VT_ARRAY [V] SAFEARRAY* */
115 VARTYPE_NOT_SUPPORTED /* VT_BYREF [V] void* for local use */
118 static const int LAST_VARTYPE = sizeof(VARTYPE_SIZE)/sizeof(VARTYPE_SIZE[0]);
121 /*************************************************************************
122 * SafeArrayAllocDescriptor (OLEAUT32.36)
123 * Allocate the appropriate amount of memory for the SafeArray descriptor
125 HRESULT WINAPI SafeArrayAllocDescriptor(
126 UINT cDims,
127 SAFEARRAY **ppsaOut)
129 SAFEARRAYBOUND *sab;
130 LONG allocSize = 0;
132 /* SAFEARRAY + SAFEARRAYBOUND * (cDims -1) ( -1 because there is already one
133 ( in SAFEARRAY struct */
134 allocSize = sizeof(**ppsaOut) + (sizeof(*sab) * (cDims-1));
136 /* Allocate memory for SAFEARRAY struc */
137 if(( (*ppsaOut)=HeapAlloc(
138 GetProcessHeap(), HEAP_ZERO_MEMORY, allocSize)) == NULL){
139 return(E_UNEXPECTED);
141 TRACE("SafeArray: %lu bytes allocated for descriptor.\n", allocSize);
143 return(S_OK);
146 /*************************************************************************
147 * SafeArrayAllocDescriptorEx (OLEAUT32.41)
148 * Allocate the appropriate amount of memory for the SafeArray descriptor
150 * This is a minimal implementation just to get things moving.
152 * The MSDN documentation on this doesn't tell us much.
154 HRESULT WINAPI SafeArrayAllocDescriptorEx(
155 VARTYPE vt,
156 UINT cDims,
157 SAFEARRAY **ppsaOut)
159 if ( (vt >= LAST_VARTYPE) ||
160 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
161 return E_UNEXPECTED;
163 return SafeArrayAllocDescriptor (cDims, ppsaOut);
166 /*************************************************************************
167 * SafeArrayAllocData (OLEAUT32.37)
168 * Allocate the appropriate amount of data for the SafeArray data
170 HRESULT WINAPI SafeArrayAllocData(
171 SAFEARRAY *psa)
173 ULONG ulWholeArraySize; /* to store the size of the whole thing */
175 if(! validArg(psa))
176 return E_INVALIDARG;
178 ulWholeArraySize = getArraySize(psa);
180 /* Allocate memory for the data itself */
181 if((psa->pvData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
182 psa->cbElements*ulWholeArraySize)) == NULL)
183 return(E_UNEXPECTED);
185 TRACE("SafeArray: %lu bytes allocated for data at %p (%lu objects).\n",
186 psa->cbElements*ulWholeArraySize, psa->pvData, ulWholeArraySize);
188 return(S_OK);
191 /*************************************************************************
192 * SafeArrayCreate (OLEAUT32.15)
193 * Create a SafeArray object by encapsulating AllocDescriptor and AllocData
195 SAFEARRAY* WINAPI SafeArrayCreate(
196 VARTYPE vt,
197 UINT cDims,
198 SAFEARRAYBOUND *rgsabound)
200 SAFEARRAY *psa;
201 HRESULT hRes;
202 USHORT cDim;
204 /* Validate supported VARTYPE */
205 if ( (vt >= LAST_VARTYPE) ||
206 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
207 return NULL;
209 /* Allocate memory for the array descriptor */
210 if( FAILED( hRes = SafeArrayAllocDescriptor(cDims, &psa)))
211 return NULL;
213 /* setup data members... */
214 psa->cDims = cDims;
215 psa->fFeatures = getFeatures(vt);
216 psa->cLocks = 0;
217 psa->pvData = NULL;
218 psa->cbElements= VARTYPE_SIZE[vt];
220 /* Invert the bounds ... */
221 for(cDim=0; cDim < psa->cDims; cDim++) {
222 psa->rgsabound[cDim].cElements = rgsabound[psa->cDims-cDim-1].cElements;
223 psa->rgsabound[cDim].lLbound = rgsabound[psa->cDims-cDim-1].lLbound;
226 /* allocate memory for the data... */
227 if( FAILED( hRes = SafeArrayAllocData(psa))) {
228 SafeArrayDestroyDescriptor(psa);
229 ERR("() : Failed to allocate the Safe Array data\n");
230 return NULL;
233 return(psa);
236 /*************************************************************************
237 * SafeArrayDestroyDescriptor (OLEAUT32.38)
238 * Frees the memory associated with the descriptor.
240 HRESULT WINAPI SafeArrayDestroyDescriptor(
241 SAFEARRAY *psa)
243 /* Check for lockness before to free... */
244 if(psa->cLocks > 0)
245 return DISP_E_ARRAYISLOCKED;
247 /* The array is unlocked, then, deallocate memory */
248 if(HeapFree( GetProcessHeap(), 0, psa) == FALSE)
249 return E_UNEXPECTED;
251 return(S_OK);
255 /*************************************************************************
256 * SafeArrayLock (OLEAUT32.21)
257 * Increment the lock counter
259 * Doc says (MSDN Library ) that psa->pvData should be made available (!= NULL)
260 * only when psa->cLocks is > 0... I don't get it since pvData is allocated
261 * before the array is locked, therefore
263 HRESULT WINAPI SafeArrayLock(
264 SAFEARRAY *psa)
266 if(! validArg(psa))
267 return E_INVALIDARG;
269 psa->cLocks++;
271 return(S_OK);
274 /*************************************************************************
275 * SafeArrayUnlock (OLEAUT32.22)
276 * Decrement the lock counter
278 HRESULT WINAPI SafeArrayUnlock(
279 SAFEARRAY *psa)
281 if(! validArg(psa))
282 return E_INVALIDARG;
284 if (psa->cLocks > 0)
285 psa->cLocks--;
287 return(S_OK);
291 /*************************************************************************
292 * SafeArrayPutElement (OLEAUT32.26)
293 * Set the data at the given coordinate
295 HRESULT WINAPI SafeArrayPutElement(
296 SAFEARRAY *psa,
297 LONG *rgIndices,
298 void *pv)
300 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
301 the desired one... */
302 PVOID elementStorageAddress = NULL; /* Adress to store the data */
304 /* Validate the index given */
305 if(! validCoordinate(rgIndices, psa))
306 return DISP_E_BADINDEX;
307 if(! validArg(psa))
308 return E_INVALIDARG;
310 if( SafeArrayLock(psa) == S_OK) {
312 /* Figure out the number of items to skip */
313 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
315 /* Figure out the number of byte to skip ... */
316 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
318 if(isPointer(psa->fFeatures)) { /* increment ref count for this pointer */
320 *((PVOID*)elementStorageAddress) = *(PVOID*)pv;
321 IUnknown_AddRef( *(IUnknown**)pv);
323 } else {
325 if(psa->fFeatures == FADF_BSTR) { /* Create a new object */
326 BSTR pbstrReAllocStr = NULL;
327 if(pv &&
328 ((pbstrReAllocStr = SYSDUPSTRING( (OLECHAR*)pv )) == NULL)) {
329 SafeArrayUnlock(psa);
330 return E_OUTOFMEMORY;
331 } else
332 *((BSTR*)elementStorageAddress) = pbstrReAllocStr;
334 else if(psa->fFeatures == FADF_VARIANT) {
335 HRESULT hr = VariantCopy(elementStorageAddress, pv);
336 if (FAILED(hr)) {
337 SafeArrayUnlock(psa);
338 return hr;
341 else /* duplicate the memory */
342 memcpy(elementStorageAddress, pv, SafeArrayGetElemsize(psa) );
345 } else {
346 ERR("SafeArray: Cannot lock array....\n");
347 return E_UNEXPECTED; /* UNDOC error condition */
350 TRACE("SafeArray: item put at adress %p.\n",elementStorageAddress);
351 return SafeArrayUnlock(psa);
355 /*************************************************************************
356 * SafeArrayGetElement (OLEAUT32.25)
357 * Return the data element corresponding the the given coordinate
359 HRESULT WINAPI SafeArrayGetElement(
360 SAFEARRAY *psa,
361 LONG *rgIndices,
362 void *pv)
364 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
365 the desired one... */
366 PVOID elementStorageAddress = NULL; /* Adress to store the data */
368 if(! validArg(psa))
369 return E_INVALIDARG;
371 if(! validCoordinate(rgIndices, psa)) /* Validate the index given */
372 return(DISP_E_BADINDEX);
374 if( SafeArrayLock(psa) == S_OK) {
376 /* Figure out the number of items to skip */
377 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
379 /* Figure out the number of byte to skip ... */
380 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
382 if( psa->fFeatures == FADF_BSTR) { /* reallocate the obj */
383 BSTR pbstrStoredStr = *(OLECHAR**)elementStorageAddress;
384 BSTR pbstrReturnedStr = NULL;
385 if( pbstrStoredStr &&
386 ((pbstrReturnedStr = SYSDUPSTRING( pbstrStoredStr )) == NULL) ) {
387 SafeArrayUnlock(psa);
388 return E_OUTOFMEMORY;
389 } else
390 *((BSTR*)pv) = pbstrReturnedStr;
392 else if( psa->fFeatures == FADF_VARIANT) {
393 HRESULT hr;
394 VariantInit(pv);
395 hr = VariantCopy(pv, elementStorageAddress);
396 if (FAILED(hr)) {
397 SafeArrayUnlock(psa);
398 return hr;
401 else if( isPointer(psa->fFeatures) ) /* simply copy the pointer */
402 *(PVOID*)pv = *((PVOID*)elementStorageAddress);
403 else /* copy the bytes */
404 memcpy(pv, elementStorageAddress, psa->cbElements );
406 } else {
407 ERR("SafeArray: Cannot lock array....\n");
408 return E_UNEXPECTED; /* UNDOC error condition */
411 return( SafeArrayUnlock(psa) );
414 /*************************************************************************
415 * SafeArrayGetUBound (OLEAUT32.19)
416 * return the UP bound for a given array dimension
418 HRESULT WINAPI SafeArrayGetUBound(
419 SAFEARRAY *psa,
420 UINT nDim,
421 LONG *plUbound)
423 if(! validArg(psa))
424 return E_INVALIDARG;
426 if(nDim > psa->cDims)
427 return DISP_E_BADINDEX;
429 if(0 == nDim)
430 return DISP_E_BADINDEX;
432 *plUbound = psa->rgsabound[nDim-1].lLbound +
433 psa->rgsabound[nDim-1].cElements - 1;
435 return S_OK;
438 /*************************************************************************
439 * SafeArrayGetLBound (OLEAUT32.20)
440 * Return the LO bound for a given array dimension
442 HRESULT WINAPI SafeArrayGetLBound(
443 SAFEARRAY *psa,
444 UINT nDim,
445 LONG *plLbound)
447 if(! validArg(psa))
448 return E_INVALIDARG;
450 if(nDim > psa->cDims)
451 return DISP_E_BADINDEX;
453 if(0 == nDim)
454 return DISP_E_BADINDEX;
456 *plLbound = psa->rgsabound[nDim-1].lLbound;
457 return S_OK;
460 /*************************************************************************
461 * SafeArrayGetDim (OLEAUT32.17)
462 * returns the number of dimension in the array
464 UINT WINAPI SafeArrayGetDim(
465 SAFEARRAY * psa)
468 * A quick test in Windows shows that the behavior here for an invalid
469 * pointer is to return 0.
471 if(! validArg(psa))
472 return 0;
474 return psa->cDims;
477 /*************************************************************************
478 * SafeArrayGetElemsize (OLEAUT32.18)
479 * Return the size of the element in the array
481 UINT WINAPI SafeArrayGetElemsize(
482 SAFEARRAY * psa)
485 * A quick test in Windows shows that the behavior here for an invalid
486 * pointer is to return 0.
488 if(! validArg(psa))
489 return 0;
491 return psa->cbElements;
494 /*************************************************************************
495 * SafeArrayAccessData (OLEAUT32.23)
496 * increment the access count and return the data
498 HRESULT WINAPI SafeArrayAccessData(
499 SAFEARRAY *psa,
500 void **ppvData)
502 HRESULT hRes;
504 if(! validArg(psa))
505 return E_INVALIDARG;
507 hRes = SafeArrayLock(psa);
509 switch (hRes) {
510 case S_OK:
511 (*ppvData) = psa->pvData;
512 break;
513 case E_INVALIDARG:
514 (*ppvData) = NULL;
515 return E_INVALIDARG;
518 return S_OK;
522 /*************************************************************************
523 * SafeArrayUnaccessData (OLEAUT32.24)
524 * Decrement the access count
526 HRESULT WINAPI SafeArrayUnaccessData(
527 SAFEARRAY * psa)
529 if(! validArg(psa))
530 return E_INVALIDARG;
532 return(SafeArrayUnlock(psa));
535 /************************************************************************
536 * SafeArrayPtrOfIndex (OLEAUT32.148)
537 * Return a pointer to the element at rgIndices
539 HRESULT WINAPI SafeArrayPtrOfIndex(
540 SAFEARRAY *psa,
541 LONG *rgIndices,
542 void **ppvData)
544 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
545 the desired one... */
547 if(! validArg(psa))
548 return E_INVALIDARG;
550 if(! validCoordinate(rgIndices, psa))
551 return DISP_E_BADINDEX;
553 /* Although it is dangerous to do this without having a lock, it is not
554 * illegal. Microsoft do warn of the danger.
557 /* Figure out the number of items to skip */
558 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
560 *ppvData = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
562 return S_OK;
565 /************************************************************************
566 * SafeArrayDestroyData (OLEAUT32.39)
567 * Frees the memory data bloc
569 HRESULT WINAPI SafeArrayDestroyData(
570 SAFEARRAY *psa)
572 HRESULT hRes;
573 ULONG ulWholeArraySize; /* count spot in array */
574 ULONG ulDataIter; /* to iterate the data space */
576 if(! validArg(psa))
577 return E_INVALIDARG;
579 if(psa->cLocks > 0)
580 return DISP_E_ARRAYISLOCKED;
582 ulWholeArraySize = getArraySize(psa);
584 if(isPointer(psa->fFeatures)) { /* release the pointers */
585 IUnknown *punk;
587 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
588 punk = *(IUnknown**)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
590 if( punk != NULL)
591 IUnknown_Release(punk);
595 else if(psa->fFeatures & FADF_BSTR) { /* deallocate the obj */
596 BSTR bstr;
598 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
599 bstr = *(BSTR*)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
601 if( bstr != NULL)
602 SysFreeString( bstr );
605 else if(psa->fFeatures & FADF_VARIANT) { /* deallocate the obj */
607 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
608 VariantClear((VARIANT*)((char *) psa->pvData+(ulDataIter*(psa->cbElements))));
612 /* check if this array is a Vector, in which case do not free the data
613 block since it has been allocated by AllocDescriptor and therefore
614 deserve to be freed by DestroyDescriptor */
615 if(!(psa->fFeatures & FADF_CREATEVECTOR)) { /* Set when we do CreateVector */
617 /* free the whole chunk */
618 if((hRes = HeapFree( GetProcessHeap(), 0, psa->pvData)) == 0) /*falied*/
619 return E_UNEXPECTED; /* UNDOC error condition */
621 psa->pvData = NULL;
624 return S_OK;
627 /************************************************************************
628 * SafeArrayCopyData (OLEAUT32.412)
629 * Copy the psaSource's data block into psaTarget if dimension and size
630 * permits it.
632 HRESULT WINAPI SafeArrayCopyData(
633 SAFEARRAY *psaSource,
634 SAFEARRAY **psaTarget)
636 USHORT cDimCount; /* looper */
637 LONG lDelta; /* looper */
638 IUnknown *punk;
639 ULONG ulWholeArraySize; /* Number of item in SA */
640 BSTR bstr;
642 if(! (validArg(psaSource) && validArg(*psaTarget)) )
643 return E_INVALIDARG;
645 if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(*psaTarget))
646 return E_INVALIDARG;
648 ulWholeArraySize = getArraySize(psaSource);
650 /* The two arrays boundaries must be of same lenght */
651 for(cDimCount=0;cDimCount < psaSource->cDims; cDimCount++)
652 if( psaSource->rgsabound[cDimCount].cElements !=
653 (*psaTarget)->rgsabound[cDimCount].cElements)
654 return E_INVALIDARG;
656 if( isPointer((*psaTarget)->fFeatures) ) { /* the target contains ptr
657 that must be released */
658 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
659 punk = *(IUnknown**)
660 ((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
662 if( punk != NULL)
663 IUnknown_Release(punk);
667 else if( (*psaTarget)->fFeatures & FADF_BSTR) { /* the target contain BSTR
668 that must be freed */
669 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
670 bstr =
671 *(BSTR*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
673 if( bstr != NULL)
674 SysFreeString( bstr );
677 else if( (*psaTarget)->fFeatures & FADF_VARIANT) {
679 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
680 VariantClear((VARIANT*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements)));
684 return duplicateData(psaSource, psaTarget);
687 /************************************************************************
688 * SafeArrayDestroy (OLEAUT32.16)
689 * Deallocates all memory reserved for the SafeArray
691 HRESULT WINAPI SafeArrayDestroy(
692 SAFEARRAY * psa)
694 HRESULT hRes;
696 if(! validArg(psa))
697 return E_INVALIDARG;
699 if(psa->cLocks > 0)
700 return DISP_E_ARRAYISLOCKED;
702 if((hRes = SafeArrayDestroyData( psa )) == S_OK)
703 if((hRes = SafeArrayDestroyDescriptor( psa )) == S_OK)
704 return S_OK;
706 return E_UNEXPECTED; /* UNDOC error condition */
709 /************************************************************************
710 * SafeArrayCopy (OLEAUT32.27)
711 * Make a dupplicate of a SafeArray
713 HRESULT WINAPI SafeArrayCopy(
714 SAFEARRAY *psa,
715 SAFEARRAY **ppsaOut)
717 HRESULT hRes;
718 DWORD dAllocSize;
719 ULONG ulWholeArraySize; /* size of the thing */
721 if(! validArg(psa))
722 return E_INVALIDARG;
724 if((hRes=SafeArrayAllocDescriptor(psa->cDims, ppsaOut)) == S_OK){
726 /* Duplicate the SAFEARRAY struc */
727 memcpy(*ppsaOut, psa,
728 sizeof(*psa)+(sizeof(*(psa->rgsabound))*(psa->cDims-1)));
730 (*ppsaOut)->pvData = NULL; /* do not point to the same data area */
732 /* make sure the new safe array doesn't have the FADF_CREATEVECTOR flag,
733 because the data has not been allocated with the descriptor. */
734 (*ppsaOut)->fFeatures &= ~FADF_CREATEVECTOR;
736 /* Get the allocated memory size for source and allocate it for target */
737 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
738 dAllocSize = ulWholeArraySize*psa->cbElements;
740 (*ppsaOut)->pvData =
741 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dAllocSize);
742 if( (*ppsaOut)->pvData != NULL) { /* HeapAlloc succeed */
744 if( (hRes=duplicateData(psa, ppsaOut)) != S_OK) { /* E_OUTOFMEMORY */
745 HeapFree(GetProcessHeap(), 0, (*ppsaOut)->pvData);
746 (*ppsaOut)->pvData = NULL;
747 SafeArrayDestroyDescriptor(*ppsaOut);
748 return hRes;
751 } else { /* failed to allocate or dupplicate... */
752 SafeArrayDestroyDescriptor(*ppsaOut);
753 return E_UNEXPECTED; /* UNDOC error condition */
755 } else { /* failed to allocate mem for descriptor */
756 return E_OUTOFMEMORY; /* UNDOC error condiftion */
759 return S_OK;
762 /************************************************************************
763 * SafeArrayCreateVector (OLEAUT32.411)
764 * Creates a one dimension safearray where the data is next to the
765 * SAFEARRAY structure.
767 SAFEARRAY* WINAPI SafeArrayCreateVector(
768 VARTYPE vt,
769 LONG lLbound,
770 ULONG cElements)
772 SAFEARRAY *psa;
774 /* Validate supported VARTYPE */
775 if ( (vt >= LAST_VARTYPE) ||
776 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
777 return NULL;
779 /* Allocate memory for the array descriptor and data contiguously */
780 if( FAILED( psa = HeapAlloc( GetProcessHeap(),
781 HEAP_ZERO_MEMORY,
782 (sizeof(*psa) + (VARTYPE_SIZE[vt] * cElements))))) {
783 return NULL;
786 /* setup data members... */
787 psa->cDims = 1; /* always and forever */
788 psa->fFeatures = getFeatures(vt) | FADF_CREATEVECTOR; /* undocumented flag used by Microsoft */
789 psa->cLocks = 0;
790 psa->pvData = (BYTE*)psa + sizeof(*psa);
791 psa->cbElements = VARTYPE_SIZE[vt];
793 psa->rgsabound[0].cElements = cElements;
794 psa->rgsabound[0].lLbound = lLbound;
796 return(psa);
799 /************************************************************************
800 * SafeArrayRedim (OLEAUT32.40)
801 * Changes the caracteristics of the last dimension of the SafeArray
803 HRESULT WINAPI SafeArrayRedim(
804 SAFEARRAY *psa,
805 SAFEARRAYBOUND *psaboundNew)
807 LONG lDelta; /* hold difference in size */
808 USHORT cDims=1; /* dims counter */
810 if( !validArg(psa) )
811 return E_INVALIDARG;
813 if( psa->cLocks > 0 )
814 return DISP_E_ARRAYISLOCKED;
816 if( psa->fFeatures & FADF_FIXEDSIZE )
817 return E_INVALIDARG;
819 if( SafeArrayLock(psa)==E_UNEXPECTED )
820 return E_UNEXPECTED;/* UNDOC error condition */
822 /* find the delta in number of array spot to apply to the new array */
823 lDelta = psaboundNew->cElements - psa->rgsabound[0].cElements;
824 for(; cDims < psa->cDims; cDims++)
825 /* delta in number of spot implied by modifying the last dimension */
826 lDelta *= psa->rgsabound[cDims].cElements;
828 TRACE("elements=%ld, Lbound=%ld (delta=%ld)\n", psaboundNew->cElements, psaboundNew->lLbound, lDelta);
830 if (lDelta == 0) { ;/* same size, maybe a change of lLbound, just set it */
832 } else /* need to enlarge (lDelta +) reduce (lDelta -) */
833 if(! resizeSafeArray(psa, lDelta))
834 return E_UNEXPECTED; /* UNDOC error condition */
836 /* the only modifyable dimension sits in [0] as the dimensions were reversed
837 at array creation time... */
838 psa->rgsabound[0].cElements = psaboundNew->cElements;
839 psa->rgsabound[0].lLbound = psaboundNew->lLbound;
841 return SafeArrayUnlock(psa);
844 /************************************************************************
845 * NOT WINDOWS API - SafeArray* Utility functions
846 ************************************************************************/
848 /************************************************************************
849 * Used to validate the SAFEARRAY type of arg
851 static BOOL validArg(
852 SAFEARRAY *psa)
854 SAFEARRAYBOUND *sab;
855 LONG psaSize = 0;
856 LONG descSize = 0;
857 LONG fullSize = 0;
860 * Let's check for the null pointer just in case.
862 if (psa == NULL)
863 return FALSE;
865 /* Check whether the size of the chunk makes sense... That's the only thing
866 I can think of now... */
868 psaSize = HeapSize(GetProcessHeap(), 0, psa);
869 if (psaSize == -1)
870 /* uh, foreign heap. Better don't mess with it ! */
871 return TRUE;
873 /* size of the descriptor when the SA is not created with CreateVector */
874 descSize = sizeof(*psa) + (sizeof(*sab) * (psa->cDims-1));
876 /* size of the descriptor + data when created with CreateVector */
877 fullSize = sizeof(*psa) + (psa->cbElements * psa->rgsabound[0].cElements);
879 return((psaSize >= descSize) || (psaSize >= fullSize));
882 /************************************************************************
883 * Used to reallocate memory
885 static BOOL resizeSafeArray(
886 SAFEARRAY *psa,
887 LONG lDelta)
889 ULONG ulWholeArraySize; /* use as multiplicator */
890 PVOID pvNewBlock = NULL;
891 IUnknown *punk;
892 BSTR bstr;
894 ulWholeArraySize = getArraySize(psa);
896 if(lDelta < 0) { /* array needs to be shorthen */
897 if( isPointer(psa->fFeatures)) /* ptr that need to be released */
898 for(;lDelta < 0; lDelta++) {
899 punk = *(IUnknown**)
900 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
902 if( punk != NULL )
903 IUnknown_Release(punk);
906 else if(psa->fFeatures & FADF_BSTR) /* BSTR that need to be freed */
907 for(;lDelta < 0; lDelta++) {
908 bstr = *(BSTR*)
909 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
911 if( bstr != NULL )
912 SysFreeString( bstr );
914 else if(psa->fFeatures & FADF_VARIANT)
915 for(;lDelta < 0; lDelta++) {
916 VariantClear((VARIANT*)((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements)));
920 if (!(psa->fFeatures & FADF_CREATEVECTOR))
922 /* Ok now, if we are enlarging the array, we *MUST* move the whole block
923 pointed to by pvData. If we are shorthening the array, this move is
924 optional but we do it anyway becuase the benefit is that we are
925 releasing to the system the unused memory */
927 if((pvNewBlock = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, psa->pvData,
928 (ulWholeArraySize + lDelta) * psa->cbElements)) == NULL)
929 return FALSE; /* TODO If we get here it means:
930 SHRINK situation : we've deleted the undesired
931 data and did not release the memory
932 GROWING situation: we've been unable to grow the array
935 else
937 /* Allocate a new block, because the previous data has been allocated with
938 the descriptor in SafeArrayCreateVector function. */
940 if((pvNewBlock = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
941 ulWholeArraySize * psa->cbElements)) == NULL)
942 return FALSE;
944 psa->fFeatures &= ~FADF_CREATEVECTOR;
946 /* reassign to the new block of data */
947 psa->pvData = pvNewBlock;
948 return TRUE;
951 /************************************************************************
952 * Used to set the fFeatures data member of the SAFEARRAY structure.
954 static INT getFeatures(
955 VARTYPE vt)
957 switch(vt) {
958 case VT_BSTR: return FADF_BSTR;
959 case VT_UNKNOWN: return FADF_UNKNOWN;
960 case VT_DISPATCH: return FADF_DISPATCH;
961 case VT_VARIANT: return FADF_VARIANT;
963 return 0;
966 /************************************************************************
967 * Used to figure out if the fFeatures data member of the SAFEARRAY
968 * structure contain any information about the type of data stored...
970 static BOOL isPointer(
971 USHORT feature)
973 switch(feature) {
974 case FADF_UNKNOWN: return TRUE; /* those are pointers */
975 case FADF_DISPATCH: return TRUE;
977 return FALSE;
980 /************************************************************************
981 * Used to calculate the displacement when accessing or modifying
982 * safearray data set.
984 * Parameters: - LONG *coor is the desired location in the multidimension
985 * table. Ex for a 3 dim table: coor[] = {1,2,3};
986 * - ULONG *mat is the format of the table. Ex for a 3 dim
987 * table mat[] = {4,4,4};
988 * - USHORT dim is the number of dimension of the SafeArray
990 static ULONG calcDisplacement(
991 LONG *coor,
992 SAFEARRAYBOUND *mat,
993 LONG dim)
995 ULONG res = 0;
996 LONG iterDim;
998 for(iterDim=0; iterDim<dim; iterDim++)
999 /* the -mat[dim] bring coor[dim] relative to 0 for calculation */
1000 res += ((coor[iterDim]-mat[iterDim].lLbound) *
1001 endOfDim(coor, mat, iterDim+1, dim));
1003 TRACE("SafeArray: calculated displacement is %lu.\n", res);
1004 return(res);
1007 /************************************************************************
1008 * Recursivity agent for calcDisplacement method. Used within Put and
1009 * Get methods.
1011 static INT endOfDim(
1012 LONG *coor,
1013 SAFEARRAYBOUND *mat,
1014 LONG dim,
1015 LONG realDim)
1017 if(dim==realDim)
1018 return 1;
1019 else
1020 return (endOfDim(coor, mat, dim+1, realDim) * mat[dim].cElements);
1024 /************************************************************************
1025 * Method used to validate the coordinate received in Put and Get
1026 * methods.
1028 static BOOL validCoordinate(
1029 LONG *coor,
1030 SAFEARRAY *psa)
1032 INT iter=0;
1033 LONG lUBound;
1034 LONG lLBound;
1035 HRESULT hRes;
1037 if (!psa->cDims) return FALSE;
1038 for(; iter<psa->cDims; iter++) {
1039 TRACE("coor[%d]=%ld\n", iter, coor[iter]);
1040 if((hRes = SafeArrayGetLBound(psa, (iter+1), &lLBound)) != S_OK)
1041 return FALSE;
1042 if((hRes = SafeArrayGetUBound(psa, (iter+1), &lUBound)) != S_OK)
1043 return FALSE;
1045 if(lLBound > lUBound)
1046 return FALSE;
1048 if((coor[iter] < lLBound) || (coor[iter] > lUBound))
1049 return FALSE;
1051 return TRUE;
1054 /************************************************************************
1055 * Method used to calculate the number of cells of the SA
1057 static ULONG getArraySize(
1058 SAFEARRAY *psa)
1060 USHORT cCount;
1061 ULONG ulWholeArraySize = 1;
1063 for(cCount=0; cCount < psa->cDims; cCount++) /* foreach dimensions... */
1064 ulWholeArraySize *= psa->rgsabound[cCount].cElements;
1066 return ulWholeArraySize;
1070 /************************************************************************
1071 * Method used to handle data space dupplication for Copy32 and CopyData32
1073 static HRESULT duplicateData(
1074 SAFEARRAY *psa,
1075 SAFEARRAY **ppsaOut)
1077 ULONG ulWholeArraySize; /* size of the thing */
1078 LONG lDelta;
1080 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
1082 SafeArrayLock(*ppsaOut);
1084 if( isPointer(psa->fFeatures) ) { /* If datatype is object increment
1085 object's reference count */
1086 IUnknown *punk;
1088 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1089 punk = *(IUnknown**)((char *) psa->pvData+(lDelta * psa->cbElements));
1091 if( punk != NULL)
1092 IUnknown_AddRef(punk);
1095 /* Copy the source array data into target array */
1096 memcpy((*ppsaOut)->pvData, psa->pvData,
1097 ulWholeArraySize*psa->cbElements);
1100 else if( psa->fFeatures & FADF_BSTR ) { /* if datatype is BSTR allocate
1101 the BSTR in the new array */
1102 BSTR pbstrReAllocStr = NULL;
1104 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1105 if(( pbstrReAllocStr = SYSDUPSTRING(
1106 *(BSTR*)((char *) psa->pvData+(lDelta * psa->cbElements)))) == NULL) {
1108 SafeArrayUnlock(*ppsaOut);
1109 return E_OUTOFMEMORY;
1112 *((BSTR*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements))) =
1113 pbstrReAllocStr;
1117 else if( psa->fFeatures & FADF_VARIANT ) {
1119 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1120 VariantCopy((VARIANT*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements)),
1121 (VARIANT*)((char *) psa->pvData+(lDelta * psa->cbElements)));
1125 else { /* Simply copy the source array data into target array */
1127 memcpy((*ppsaOut)->pvData, psa->pvData,
1128 ulWholeArraySize*psa->cbElements);
1131 SafeArrayUnlock(*ppsaOut);
1133 return S_OK;
1137 /************************************************************************
1138 * SafeArrayGetVartype (OLEAUT32.77)
1139 * Returns the VARTYPE stored in the given safearray
1141 HRESULT WINAPI SafeArrayGetVartype(
1142 SAFEARRAY* psa,
1143 VARTYPE* pvt)
1145 HRESULT hr = E_INVALIDARG;
1146 VARTYPE vt = VT_EMPTY;
1148 /* const short VARTYPE_OFFSET = -4; */
1150 if (psa->fFeatures & FADF_HAVEVARTYPE)
1152 /* VT tag @ negative offset 4 in the array descriptor */
1153 FIXME("Returning VT_BSTR instead of VT_...\n");
1154 vt = VT_BSTR;
1156 else if (psa->fFeatures & FADF_RECORD)
1158 vt = VT_RECORD;
1160 else if (psa->fFeatures & FADF_BSTR)
1162 vt = VT_BSTR;
1164 else if (psa->fFeatures & FADF_UNKNOWN)
1166 vt = VT_UNKNOWN;
1168 else if (psa->fFeatures & FADF_DISPATCH)
1170 vt = VT_DISPATCH;
1172 else if (psa->fFeatures & FADF_VARIANT)
1174 vt = VT_VARIANT;
1177 if (vt != VT_EMPTY)
1179 *pvt = vt;
1180 hr = S_OK;
1183 TRACE("HRESULT = %08lx\n", hr);
1184 return hr;