When emulating fullscreen it helps to not allocate space for menu bars
[wine.git] / dlls / oleaut32 / safearray.c
blob46a0af30794d45698a9abf22041bfba263b1dba3
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
23 /* Memory Layout of a SafeArray:
25 * -0x10: start of memory.
26 * -0x10: GUID for VT_DISPATCH and VT_UNKNOWN safearrays (if FADF_HAVEIID)
27 * -0x04: DWORD varianttype; (for all others, except VT_RECORD) (if FADF_HAVEVARTYPE)
28 * -0x4: IRecordInfo* iface; (if FADF_RECORD, for VT_RECORD (can be NULL))
29 * 0x00: SAFEARRAY,
30 * 0x10: SAFEARRAYBOUNDS[0...]
33 #include <stdio.h>
34 #include <string.h>
35 #include "windef.h"
36 #include "winerror.h"
37 #include "winbase.h"
38 #include "oleauto.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(ole);
43 #define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
45 /* Locally used methods */
46 static ULONG
47 calcDisplacement(LONG *coor, SAFEARRAYBOUND *mat, LONG dim);
49 static BOOL
50 isPointer(USHORT feature);
52 static INT
53 getFeatures(VARTYPE vt);
55 static BOOL
56 validCoordinate(LONG *coor, SAFEARRAY *psa);
58 static BOOL
59 resizeSafeArray(SAFEARRAY *psa, LONG lDelta);
61 static BOOL
62 validArg(SAFEARRAY *psa);
64 static ULONG
65 getArraySize(SAFEARRAY *psa);
67 static HRESULT
68 duplicateData(SAFEARRAY *psa, SAFEARRAY *ppsaOut);
70 /* Association between VARTYPE and their size.
71 A size of zero is defined for the unsupported types. */
73 #define VARTYPE_NOT_SUPPORTED 0
74 static const ULONG VARTYPE_SIZE[] =
76 /* this is taken from wtypes.h. Only [S]es are supported by the SafeArray */
77 VARTYPE_NOT_SUPPORTED, /* VT_EMPTY [V] [P] nothing */
78 VARTYPE_NOT_SUPPORTED, /* VT_NULL [V] [P] SQL style Nul */
79 2, /* VT_I2 [V][T][P][S] 2 byte signed int */
80 4, /* VT_I4 [V][T][P][S] 4 byte signed int */
81 4, /* VT_R4 [V][T][P][S] 4 byte real */
82 8, /* VT_R8 [V][T][P][S] 8 byte real */
83 8, /* VT_CY [V][T][P][S] currency */
84 8, /* VT_DATE [V][T][P][S] date */
85 sizeof(BSTR), /* VT_BSTR [V][T][P][S] OLE Automation string*/
86 sizeof(LPDISPATCH), /* VT_DISPATCH [V][T][P][S] IDispatch * */
87 4, /* VT_ERROR [V][T] [S] SCODE */
88 2, /* VT_BOOL [V][T][P][S] True=-1, False=0*/
89 sizeof(VARIANT), /* VT_VARIANT [V][T][P][S] VARIANT * */
90 sizeof(LPUNKNOWN), /* VT_UNKNOWN [V][T] [S] IUnknown * */
91 sizeof(DECIMAL), /* VT_DECIMAL [V][T] [S] 16 byte fixed point */
92 VARTYPE_NOT_SUPPORTED, /* no VARTYPE here..... */
93 1, /* VT_I1 [T] [S] signed char */
94 1, /* VT_UI1 [V][T][P][S] unsigned char */
95 2, /* VT_UI2 [T][P][S] unsigned short */
96 4, /* VT_UI4 [T][P][S] unsigned int */
97 VARTYPE_NOT_SUPPORTED, /* VT_I8 [T][P] signed 64-bit int */
98 VARTYPE_NOT_SUPPORTED, /* VT_UI8 [T][P] unsigned 64-bit int */
99 sizeof(INT), /* VT_INT [T] signed machine int */
100 sizeof(UINT), /* VT_UINT [T] unsigned machine int */
101 VARTYPE_NOT_SUPPORTED, /* VT_VOID [T] C style void */
102 VARTYPE_NOT_SUPPORTED, /* VT_HRESULT [T] Standard return type */
103 VARTYPE_NOT_SUPPORTED, /* VT_PTR [T] pointer type */
104 VARTYPE_NOT_SUPPORTED, /* VT_SAFEARRAY [T] (use VT_ARRAY in VARIANT)*/
105 VARTYPE_NOT_SUPPORTED, /* VT_CARRAY [T] C style array */
106 VARTYPE_NOT_SUPPORTED, /* VT_USERDEFINED [T] user defined type */
107 VARTYPE_NOT_SUPPORTED, /* VT_LPSTR [T][P] null terminated string */
108 VARTYPE_NOT_SUPPORTED, /* VT_LPWSTR [T][P] wide null term string */
109 VARTYPE_NOT_SUPPORTED, /* 32 */
110 VARTYPE_NOT_SUPPORTED, /* 33 */
111 VARTYPE_NOT_SUPPORTED, /* 34 */
112 VARTYPE_NOT_SUPPORTED, /* 35 */
113 VARTYPE_NOT_SUPPORTED, /* VT_RECORD record */
114 VARTYPE_NOT_SUPPORTED, /* 37 */
115 VARTYPE_NOT_SUPPORTED, /* 38 */
116 VARTYPE_NOT_SUPPORTED, /* 39 */
117 VARTYPE_NOT_SUPPORTED, /* 40 */
118 VARTYPE_NOT_SUPPORTED, /* 41 */
119 VARTYPE_NOT_SUPPORTED, /* 42 */
120 VARTYPE_NOT_SUPPORTED, /* 43 */
121 VARTYPE_NOT_SUPPORTED, /* 44 */
122 VARTYPE_NOT_SUPPORTED, /* 45 */
123 VARTYPE_NOT_SUPPORTED, /* 46 */
124 VARTYPE_NOT_SUPPORTED, /* 47 */
125 VARTYPE_NOT_SUPPORTED, /* 48 */
126 VARTYPE_NOT_SUPPORTED, /* 49 */
127 VARTYPE_NOT_SUPPORTED, /* 50 */
128 VARTYPE_NOT_SUPPORTED, /* 51 */
129 VARTYPE_NOT_SUPPORTED, /* 52 */
130 VARTYPE_NOT_SUPPORTED, /* 53 */
131 VARTYPE_NOT_SUPPORTED, /* 54 */
132 VARTYPE_NOT_SUPPORTED, /* 55 */
133 VARTYPE_NOT_SUPPORTED, /* 56 */
134 VARTYPE_NOT_SUPPORTED, /* 57 */
135 VARTYPE_NOT_SUPPORTED, /* 58 */
136 VARTYPE_NOT_SUPPORTED, /* 59 */
137 VARTYPE_NOT_SUPPORTED, /* 60 */
138 VARTYPE_NOT_SUPPORTED, /* 61 */
139 VARTYPE_NOT_SUPPORTED, /* 62 */
140 VARTYPE_NOT_SUPPORTED, /* 63 */
141 VARTYPE_NOT_SUPPORTED, /* VT_FILETIME [P] FILETIME */
142 VARTYPE_NOT_SUPPORTED, /* VT_BLOB [P] Length prefixed bytes */
143 VARTYPE_NOT_SUPPORTED, /* VT_STREAM [P] Name of stream follows */
144 VARTYPE_NOT_SUPPORTED, /* VT_STORAGE [P] Name of storage follows */
145 VARTYPE_NOT_SUPPORTED, /* VT_STREAMED_OBJECT[P] Stream contains an object*/
146 VARTYPE_NOT_SUPPORTED, /* VT_STORED_OBJECT [P] Storage contains object*/
147 VARTYPE_NOT_SUPPORTED, /* VT_BLOB_OBJECT [P] Blob contains an object*/
148 VARTYPE_NOT_SUPPORTED, /* VT_CF [P] Clipboard format */
149 VARTYPE_NOT_SUPPORTED, /* VT_CLSID [P] A Class ID */
152 static const int LAST_VARTYPE = sizeof(VARTYPE_SIZE)/sizeof(VARTYPE_SIZE[0]);
155 /*************************************************************************
156 * SafeArrayAllocDescriptor (OLEAUT32.36)
157 * Allocate the appropriate amount of memory for the SafeArray descriptor
159 HRESULT WINAPI SafeArrayAllocDescriptor(
160 UINT cDims,
161 SAFEARRAY **ppsaOut)
163 SAFEARRAYBOUND *sab;
164 LONG allocSize = 0;
165 char *ptr;
167 if (!cDims || cDims >= 0x10000) /* 65536 appears to be the limit */
168 return E_INVALIDARG;
169 if (!ppsaOut)
170 return E_POINTER;
172 /* GUID + SAFEARRAY + SAFEARRAYBOUND * (cDims -1)
173 * ( -1 because there is already one ( in SAFEARRAY struct
175 allocSize = sizeof(GUID) + sizeof(**ppsaOut) + (sizeof(*sab) * (cDims-1));
177 /* Allocate memory for SAFEARRAY struc */
178 ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, allocSize);
179 if (!ptr)
180 return E_OUTOFMEMORY;
181 *ppsaOut = (SAFEARRAY *)(ptr + sizeof(GUID));
182 (*ppsaOut)->cDims = cDims;
183 TRACE("(%d): %lu bytes allocated for descriptor.\n", cDims, allocSize);
185 return(S_OK);
188 /*************************************************************************
189 * SafeArrayAllocDescriptorEx (OLEAUT32.41)
190 * Allocate the appropriate amount of memory for the SafeArray descriptor
191 * and also store information about the vartype before the returned pointer.
193 HRESULT WINAPI SafeArrayAllocDescriptorEx(
194 VARTYPE vt,
195 UINT cDims,
196 SAFEARRAY **ppsaOut)
198 HRESULT hres;
200 hres = SafeArrayAllocDescriptor (cDims, ppsaOut);
201 if (FAILED(hres))
202 return hres;
204 switch (vt) {
205 case VT_DISPATCH:
206 (*ppsaOut)->fFeatures = FADF_HAVEIID;
207 SafeArraySetIID( *ppsaOut, &IID_IDispatch);
208 break;
209 case VT_UNKNOWN:
210 (*ppsaOut)->fFeatures = FADF_HAVEIID;
211 SafeArraySetIID( *ppsaOut, &IID_IUnknown);
212 break;
213 case VT_RECORD:
214 (*ppsaOut)->fFeatures = FADF_RECORD;
215 break;
216 default:
217 (*ppsaOut)->fFeatures = FADF_HAVEVARTYPE;
218 ((DWORD*)*ppsaOut)[-1] = vt;
219 break;
221 return S_OK;
224 /*************************************************************************
225 * SafeArrayAllocData (OLEAUT32.37)
226 * Allocate the appropriate amount of data for the SafeArray data
228 HRESULT WINAPI SafeArrayAllocData(
229 SAFEARRAY *psa)
231 ULONG ulWholeArraySize; /* to store the size of the whole thing */
233 if(! validArg(psa))
234 return E_INVALIDARG;
236 ulWholeArraySize = getArraySize(psa);
238 /* Allocate memory for the data itself */
239 if((psa->pvData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
240 psa->cbElements*ulWholeArraySize)) == NULL)
241 return(E_UNEXPECTED);
243 TRACE("SafeArray: %lu bytes allocated for data at %p (%lu objects).\n",
244 psa->cbElements*ulWholeArraySize, psa->pvData, ulWholeArraySize);
246 return(S_OK);
249 /*************************************************************************
250 * SafeArrayCreate (OLEAUT32.15)
251 * Create a SafeArray object by encapsulating AllocDescriptor and AllocData
253 SAFEARRAY* WINAPI SafeArrayCreate(
254 VARTYPE vt,
255 UINT cDims,
256 SAFEARRAYBOUND *rgsabound)
258 SAFEARRAY *psa;
259 HRESULT hRes;
260 USHORT cDim;
262 TRACE("(%d, %d, %p)\n", vt, cDims, rgsabound);
264 /* Validate supported VARTYPE */
265 if ( (vt >= LAST_VARTYPE) ||
266 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
267 return NULL;
269 /* Allocate memory for the array descriptor */
270 if( FAILED( hRes = SafeArrayAllocDescriptorEx(vt, cDims, &psa)))
271 return NULL;
273 /* setup data members... */
274 psa->cDims = cDims;
275 switch (vt) {
276 case VT_BSTR: psa->fFeatures |= FADF_BSTR;break;
277 case VT_UNKNOWN: psa->fFeatures |= FADF_UNKNOWN;break;
278 case VT_DISPATCH: psa->fFeatures |= FADF_DISPATCH;break;
279 case VT_VARIANT: psa->fFeatures |= FADF_VARIANT;break;
280 default: break;
282 psa->cLocks = 0;
283 psa->pvData = NULL;
284 psa->cbElements= VARTYPE_SIZE[vt];
286 /* Invert the bounds ... */
287 for(cDim=0; cDim < psa->cDims; cDim++) {
288 psa->rgsabound[cDim].cElements = rgsabound[psa->cDims-cDim-1].cElements;
289 psa->rgsabound[cDim].lLbound = rgsabound[psa->cDims-cDim-1].lLbound;
292 /* allocate memory for the data... */
293 if( FAILED( hRes = SafeArrayAllocData(psa))) {
294 SafeArrayDestroyDescriptor(psa);
295 ERR("() : Failed to allocate the Safe Array data\n");
296 return NULL;
299 return(psa);
302 /*************************************************************************
303 * SafeArrayDestroyDescriptor (OLEAUT32.38)
304 * Frees the memory associated with the descriptor.
306 HRESULT WINAPI SafeArrayDestroyDescriptor(
307 SAFEARRAY *psa)
309 LPVOID ptr;
311 /* Check for lockness before to free... */
312 if(psa->cLocks > 0)
313 return DISP_E_ARRAYISLOCKED;
315 /* The array is unlocked, then, deallocate memory */
316 ptr = ((IID*)psa)-1;
317 if(HeapFree( GetProcessHeap(), 0, ptr) == FALSE)
318 return E_UNEXPECTED;
319 return(S_OK);
323 /*************************************************************************
324 * SafeArrayLock (OLEAUT32.21)
325 * Increment the lock counter
327 * Doc says (MSDN Library ) that psa->pvData should be made available (!= NULL)
328 * only when psa->cLocks is > 0... I don't get it since pvData is allocated
329 * before the array is locked, therefore
331 HRESULT WINAPI SafeArrayLock(
332 SAFEARRAY *psa)
334 if(! validArg(psa))
335 return E_INVALIDARG;
337 psa->cLocks++;
339 return(S_OK);
342 /*************************************************************************
343 * SafeArrayUnlock (OLEAUT32.22)
344 * Decrement the lock counter
346 HRESULT WINAPI SafeArrayUnlock(
347 SAFEARRAY *psa)
349 if(! validArg(psa))
350 return E_INVALIDARG;
352 if (psa->cLocks > 0)
353 psa->cLocks--;
355 return(S_OK);
359 /*************************************************************************
360 * SafeArrayPutElement (OLEAUT32.26)
361 * Set the data at the given coordinate
363 HRESULT WINAPI SafeArrayPutElement(
364 SAFEARRAY *psa,
365 LONG *rgIndices,
366 void *pv)
368 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
369 the desired one... */
370 PVOID elementStorageAddress = NULL; /* Adress to store the data */
372 /* Validate the index given */
373 if(! validCoordinate(rgIndices, psa))
374 return DISP_E_BADINDEX;
375 if(! validArg(psa))
376 return E_INVALIDARG;
378 if( SafeArrayLock(psa) == S_OK) {
380 /* Figure out the number of items to skip */
381 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
383 /* Figure out the number of byte to skip ... */
384 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
386 if(isPointer(psa->fFeatures)) { /* increment ref count for this pointer */
388 *((PVOID*)elementStorageAddress) = *(PVOID*)pv;
389 IUnknown_AddRef( *(IUnknown**)pv);
391 } else {
393 if(psa->fFeatures & FADF_BSTR) { /* Create a new object */
394 BSTR pbstrReAllocStr = NULL;
395 if(pv &&
396 ((pbstrReAllocStr = SYSDUPSTRING( (OLECHAR*)pv )) == NULL)) {
397 SafeArrayUnlock(psa);
398 return E_OUTOFMEMORY;
399 } else
400 *((BSTR*)elementStorageAddress) = pbstrReAllocStr;
402 else if(psa->fFeatures & FADF_VARIANT) {
403 HRESULT hr = VariantCopy(elementStorageAddress, pv);
404 if (FAILED(hr)) {
405 SafeArrayUnlock(psa);
406 return hr;
409 else /* duplicate the memory */
410 memcpy(elementStorageAddress, pv, SafeArrayGetElemsize(psa) );
413 } else {
414 ERR("SafeArray: Cannot lock array....\n");
415 return E_UNEXPECTED; /* UNDOC error condition */
418 TRACE("SafeArray: item put at adress %p.\n",elementStorageAddress);
419 return SafeArrayUnlock(psa);
423 /*************************************************************************
424 * SafeArrayGetElement (OLEAUT32.25)
425 * Return the data element corresponding the the given coordinate
427 HRESULT WINAPI SafeArrayGetElement(
428 SAFEARRAY *psa,
429 LONG *rgIndices,
430 void *pv)
432 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
433 the desired one... */
434 PVOID elementStorageAddress = NULL; /* Adress to store the data */
436 if(! validArg(psa))
437 return E_INVALIDARG;
439 if(! validCoordinate(rgIndices, psa)) /* Validate the index given */
440 return(DISP_E_BADINDEX);
442 if( SafeArrayLock(psa) == S_OK) {
444 /* Figure out the number of items to skip */
445 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
447 /* Figure out the number of byte to skip ... */
448 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
450 if( psa->fFeatures & FADF_BSTR) { /* reallocate the obj */
451 BSTR pbstrStoredStr = *(OLECHAR**)elementStorageAddress;
452 BSTR pbstrReturnedStr = NULL;
453 if( pbstrStoredStr &&
454 ((pbstrReturnedStr = SYSDUPSTRING( pbstrStoredStr )) == NULL) ) {
455 SafeArrayUnlock(psa);
456 return E_OUTOFMEMORY;
457 } else
458 *((BSTR*)pv) = pbstrReturnedStr;
460 else if( psa->fFeatures & FADF_VARIANT) {
461 HRESULT hr;
462 VariantInit(pv);
463 hr = VariantCopy(pv, elementStorageAddress);
464 if (FAILED(hr)) {
465 SafeArrayUnlock(psa);
466 return hr;
469 else if( isPointer(psa->fFeatures) ) /* simply copy the pointer */
470 *(PVOID*)pv = *((PVOID*)elementStorageAddress);
471 else /* copy the bytes */
472 memcpy(pv, elementStorageAddress, psa->cbElements );
474 } else {
475 ERR("SafeArray: Cannot lock array....\n");
476 return E_UNEXPECTED; /* UNDOC error condition */
479 return( SafeArrayUnlock(psa) );
482 /*************************************************************************
483 * SafeArrayGetUBound (OLEAUT32.19)
484 * return the UP bound for a given array dimension
485 * Note: [0] is the right most (least significant) array index!
487 HRESULT WINAPI SafeArrayGetUBound(
488 SAFEARRAY *psa,
489 UINT nDim,
490 LONG *plUbound)
492 if(! validArg(psa))
493 return E_INVALIDARG;
495 if(nDim > psa->cDims)
496 return DISP_E_BADINDEX;
498 if(0 == nDim)
499 return DISP_E_BADINDEX;
501 *plUbound = psa->rgsabound[psa->cDims - nDim].lLbound +
502 psa->rgsabound[psa->cDims - nDim].cElements - 1;
504 return S_OK;
507 /*************************************************************************
508 * SafeArrayGetLBound (OLEAUT32.20)
509 * Return the LO bound for a given array dimension
510 * Note: [0] is the right most (least significant) array index!
512 HRESULT WINAPI SafeArrayGetLBound(
513 SAFEARRAY *psa,
514 UINT nDim,
515 LONG *plLbound)
517 if(! validArg(psa))
518 return E_INVALIDARG;
520 if(nDim > psa->cDims)
521 return DISP_E_BADINDEX;
523 if(0 == nDim)
524 return DISP_E_BADINDEX;
526 *plLbound = psa->rgsabound[psa->cDims - nDim].lLbound;
527 return S_OK;
530 /*************************************************************************
531 * SafeArrayGetDim (OLEAUT32.17)
532 * returns the number of dimension in the array
534 UINT WINAPI SafeArrayGetDim(
535 SAFEARRAY * psa)
538 * A quick test in Windows shows that the behavior here for an invalid
539 * pointer is to return 0.
541 if(! validArg(psa))
542 return 0;
544 return psa->cDims;
547 /*************************************************************************
548 * SafeArrayGetElemsize (OLEAUT32.18)
549 * Return the size of the element in the array
551 UINT WINAPI SafeArrayGetElemsize(
552 SAFEARRAY * psa)
555 * A quick test in Windows shows that the behavior here for an invalid
556 * pointer is to return 0.
558 if(! validArg(psa))
559 return 0;
561 return psa->cbElements;
564 /*************************************************************************
565 * SafeArrayAccessData (OLEAUT32.23)
566 * increment the access count and return the data
568 HRESULT WINAPI SafeArrayAccessData(
569 SAFEARRAY *psa,
570 void **ppvData)
572 HRESULT hRes;
574 if(! validArg(psa))
575 return E_INVALIDARG;
577 hRes = SafeArrayLock(psa);
579 switch (hRes) {
580 case S_OK:
581 (*ppvData) = psa->pvData;
582 break;
583 case E_INVALIDARG:
584 (*ppvData) = NULL;
585 return E_INVALIDARG;
588 return S_OK;
592 /*************************************************************************
593 * SafeArrayUnaccessData (OLEAUT32.24)
594 * Decrement the access count
596 HRESULT WINAPI SafeArrayUnaccessData(
597 SAFEARRAY * psa)
599 if(! validArg(psa))
600 return E_INVALIDARG;
602 return(SafeArrayUnlock(psa));
605 /************************************************************************
606 * SafeArrayPtrOfIndex (OLEAUT32.148)
607 * Return a pointer to the element at rgIndices
609 HRESULT WINAPI SafeArrayPtrOfIndex(
610 SAFEARRAY *psa,
611 LONG *rgIndices,
612 void **ppvData)
614 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
615 the desired one... */
617 if(! validArg(psa))
618 return E_INVALIDARG;
620 if(! validCoordinate(rgIndices, psa))
621 return DISP_E_BADINDEX;
623 /* Although it is dangerous to do this without having a lock, it is not
624 * illegal. Microsoft do warn of the danger.
627 /* Figure out the number of items to skip */
628 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
630 *ppvData = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
632 return S_OK;
635 /************************************************************************
636 * SafeArrayDestroyData (OLEAUT32.39)
637 * Frees the memory data bloc
639 HRESULT WINAPI SafeArrayDestroyData(
640 SAFEARRAY *psa)
642 HRESULT hRes;
643 ULONG ulWholeArraySize; /* count spot in array */
644 ULONG ulDataIter; /* to iterate the data space */
646 if(! validArg(psa))
647 return E_INVALIDARG;
649 if(psa->cLocks > 0)
650 return DISP_E_ARRAYISLOCKED;
652 if(psa->pvData==NULL)
653 return S_OK;
655 ulWholeArraySize = getArraySize(psa);
657 if(isPointer(psa->fFeatures)) { /* release the pointers */
658 IUnknown *punk;
660 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
661 punk = *(IUnknown**)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
663 if( punk != NULL)
664 IUnknown_Release(punk);
668 else if(psa->fFeatures & FADF_BSTR) { /* deallocate the obj */
669 BSTR bstr;
671 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
672 bstr = *(BSTR*)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
674 if( bstr != NULL)
675 SysFreeString( bstr );
678 else if(psa->fFeatures & FADF_VARIANT) { /* deallocate the obj */
680 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
681 VariantClear((VARIANT*)((char *) psa->pvData+(ulDataIter*(psa->cbElements))));
685 /* check if this array is a Vector, in which case do not free the data
686 block since it has been allocated by AllocDescriptor and therefore
687 deserve to be freed by DestroyDescriptor */
688 if(!(psa->fFeatures & FADF_CREATEVECTOR)) { /* Set when we do CreateVector */
690 /* free the whole chunk */
691 if((hRes = HeapFree( GetProcessHeap(), 0, psa->pvData)) == 0) /*failed*/
692 return E_UNEXPECTED; /* UNDOC error condition */
694 psa->pvData = NULL;
697 return S_OK;
700 /************************************************************************
701 * SafeArrayCopyData (OLEAUT32.412)
702 * Copy the psaSource's data block into psaTarget if dimension and size
703 * permits it.
705 HRESULT WINAPI SafeArrayCopyData(
706 SAFEARRAY *psaSource,
707 SAFEARRAY *psaTarget)
709 USHORT cDimCount; /* looper */
710 LONG lDelta; /* looper */
711 IUnknown *punk;
712 ULONG ulWholeArraySize; /* Number of item in SA */
713 BSTR bstr;
715 if(! (validArg(psaSource) && validArg(psaTarget)) )
716 return E_INVALIDARG;
718 if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(psaTarget))
719 return E_INVALIDARG;
721 ulWholeArraySize = getArraySize(psaSource);
723 /* The two arrays boundaries must be of same lenght */
724 for(cDimCount=0;cDimCount < psaSource->cDims; cDimCount++)
725 if( psaSource->rgsabound[cDimCount].cElements !=
726 psaTarget->rgsabound[cDimCount].cElements)
727 return E_INVALIDARG;
729 if( isPointer(psaTarget->fFeatures) ) { /* the target contains ptr
730 that must be released */
731 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
732 punk = *(IUnknown**)
733 ((char *) psaTarget->pvData + (lDelta * psaTarget->cbElements));
735 if( punk != NULL)
736 IUnknown_Release(punk);
740 else if( psaTarget->fFeatures & FADF_BSTR) { /* the target contain BSTR
741 that must be freed */
742 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
743 bstr =
744 *(BSTR*)((char *) psaTarget->pvData + (lDelta * psaTarget->cbElements));
746 if( bstr != NULL)
747 SysFreeString( bstr );
750 else if( psaTarget->fFeatures & FADF_VARIANT) {
752 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
753 VariantClear((VARIANT*)((char *) psaTarget->pvData + (lDelta * psaTarget->cbElements)));
757 return duplicateData(psaSource, psaTarget);
760 /************************************************************************
761 * SafeArrayDestroy (OLEAUT32.16)
762 * Deallocates all memory reserved for the SafeArray
764 HRESULT WINAPI SafeArrayDestroy(
765 SAFEARRAY * psa)
767 HRESULT hRes;
769 if(! validArg(psa))
770 return E_INVALIDARG;
772 if(psa->cLocks > 0)
773 return DISP_E_ARRAYISLOCKED;
775 if((hRes = SafeArrayDestroyData( psa )) == S_OK)
776 if((hRes = SafeArrayDestroyDescriptor( psa )) == S_OK)
777 return S_OK;
779 return E_UNEXPECTED; /* UNDOC error condition */
782 /************************************************************************
783 * SafeArrayCopy (OLEAUT32.27)
784 * Make a dupplicate of a SafeArray
786 HRESULT WINAPI SafeArrayCopy(
787 SAFEARRAY *psa,
788 SAFEARRAY **ppsaOut)
790 HRESULT hRes;
791 DWORD dAllocSize;
792 ULONG ulWholeArraySize; /* size of the thing */
794 if(! validArg(psa))
795 return E_INVALIDARG;
797 if((hRes=SafeArrayAllocDescriptor(psa->cDims, ppsaOut)) == S_OK){
799 /* Duplicate the SAFEARRAY struct */
800 memcpy(*ppsaOut, psa,
801 sizeof(*psa)+(sizeof(*(psa->rgsabound))*(psa->cDims-1)));
803 /* If the features that use storage before the SAFEARRAY struct are
804 * enabled, also copy this memory range. Flags have been copied already.
806 if (psa->fFeatures & (FADF_HAVEIID | FADF_HAVEVARTYPE))
807 memcpy(((GUID*)*ppsaOut)-1, ((GUID*)psa)-1, sizeof(GUID));
809 /* Copy the IRecordInfo* reference */
810 if (psa->fFeatures & FADF_RECORD) {
811 IRecordInfo *ri;
813 ri = ((IRecordInfo**)psa)[-1];
814 if (ri) {
815 ((IRecordInfo**)*ppsaOut)[-1] = ri;
816 IRecordInfo_AddRef(ri);
820 (*ppsaOut)->pvData = NULL; /* do not point to the same data area */
822 /* make sure the new safe array doesn't have the FADF_CREATEVECTOR flag,
823 because the data has not been allocated with the descriptor. */
824 (*ppsaOut)->fFeatures &= ~FADF_CREATEVECTOR;
826 /* Get the allocated memory size for source and allocate it for target */
827 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
828 dAllocSize = ulWholeArraySize*psa->cbElements;
830 (*ppsaOut)->pvData =
831 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dAllocSize);
832 if( (*ppsaOut)->pvData != NULL) { /* HeapAlloc succeed */
834 if( (hRes=duplicateData(psa, *ppsaOut)) != S_OK) { /* E_OUTOFMEMORY */
835 HeapFree(GetProcessHeap(), 0, (*ppsaOut)->pvData);
836 (*ppsaOut)->pvData = NULL;
837 SafeArrayDestroyDescriptor(*ppsaOut);
838 return hRes;
841 } else { /* failed to allocate or dupplicate... */
842 SafeArrayDestroyDescriptor(*ppsaOut);
843 return E_UNEXPECTED; /* UNDOC error condition */
845 } else { /* failed to allocate mem for descriptor */
846 return E_OUTOFMEMORY; /* UNDOC error condiftion */
849 return S_OK;
852 /************************************************************************
853 * SafeArrayCreateVector (OLEAUT32.411)
854 * Creates a one dimension safearray where the data is next to the
855 * SAFEARRAY structure.
857 SAFEARRAY* WINAPI SafeArrayCreateVector(
858 VARTYPE vt,
859 LONG lLbound,
860 ULONG cElements)
862 SAFEARRAY *psa;
863 BYTE *ptr;
865 TRACE("%d, %ld, %ld\n", vt, lLbound, cElements);
867 /* Validate supported VARTYPE */
868 if ( (vt >= LAST_VARTYPE) ||
869 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
870 return NULL;
872 /* Allocate memory for the array descriptor and data contiguously */
873 ptr = HeapAlloc( GetProcessHeap(),
874 HEAP_ZERO_MEMORY,
875 (sizeof(GUID)+sizeof(*psa)+(VARTYPE_SIZE[vt]*cElements)));
876 if (!ptr)
877 return NULL;
878 psa = (SAFEARRAY*)(ptr+sizeof(GUID));
880 /* setup data members... */
881 psa->cDims = 1; /* always and forever */
882 psa->fFeatures = getFeatures(vt) | FADF_CREATEVECTOR; /* undocumented flag used by Microsoft */
883 psa->cLocks = 0;
884 psa->pvData = (BYTE*)psa + sizeof(*psa);
885 psa->cbElements = VARTYPE_SIZE[vt];
887 psa->rgsabound[0].cElements = cElements;
888 psa->rgsabound[0].lLbound = lLbound;
890 return(psa);
893 /************************************************************************
894 * SafeArrayRedim (OLEAUT32.40)
895 * Changes the caracteristics of the last dimension of the SafeArray
897 HRESULT WINAPI SafeArrayRedim(
898 SAFEARRAY *psa,
899 SAFEARRAYBOUND *psaboundNew)
901 LONG lDelta; /* hold difference in size */
902 USHORT cDims=1; /* dims counter */
904 if( !validArg(psa) )
905 return E_INVALIDARG;
907 if( psa->cLocks > 0 )
908 return DISP_E_ARRAYISLOCKED;
910 if( psa->fFeatures & FADF_FIXEDSIZE )
911 return E_INVALIDARG;
913 if( SafeArrayLock(psa)==E_UNEXPECTED )
914 return E_UNEXPECTED;/* UNDOC error condition */
916 /* find the delta in number of array spot to apply to the new array */
917 lDelta = psaboundNew->cElements - psa->rgsabound[0].cElements;
918 for(; cDims < psa->cDims; cDims++)
919 /* delta in number of spot implied by modifying the last dimension */
920 lDelta *= psa->rgsabound[cDims].cElements;
922 TRACE("elements=%ld, Lbound=%ld (delta=%ld)\n", psaboundNew->cElements, psaboundNew->lLbound, lDelta);
924 if (lDelta == 0) { ;/* same size, maybe a change of lLbound, just set it */
926 } else /* need to enlarge (lDelta +) reduce (lDelta -) */
927 if(! resizeSafeArray(psa, lDelta))
928 return E_UNEXPECTED; /* UNDOC error condition */
930 /* the only modifyable dimension sits in [0] as the dimensions were reversed
931 at array creation time... */
932 psa->rgsabound[0].cElements = psaboundNew->cElements;
933 psa->rgsabound[0].lLbound = psaboundNew->lLbound;
935 return SafeArrayUnlock(psa);
938 /************************************************************************
939 * NOT WINDOWS API - SafeArray* Utility functions
940 ************************************************************************/
942 /************************************************************************
943 * Used to validate the SAFEARRAY type of arg
945 static BOOL validArg(
946 SAFEARRAY *psa)
948 SAFEARRAYBOUND *sab;
949 LONG psaSize = 0;
950 LONG descSize = 0;
951 LONG fullSize = 0;
954 * Let's check for the null pointer just in case.
956 if (psa == NULL)
957 return FALSE;
959 /* Check whether the size of the chunk makes sense... That's the only thing
960 I can think of now... */
962 psaSize = HeapSize(GetProcessHeap(), 0, ((IID*)psa)-1);
963 if (psaSize == -1)
964 /* uh, foreign heap. Better don't mess with it ! */
965 return TRUE;
967 /* size of the descriptor when the SA is not created with CreateVector */
968 descSize = sizeof(GUID) + sizeof(*psa) + (sizeof(*sab) * (psa->cDims-1));
970 /* size of the descriptor + data when created with CreateVector */
971 fullSize = sizeof(*psa) + (psa->cbElements * psa->rgsabound[0].cElements);
973 return((psaSize >= descSize) || (psaSize >= fullSize));
976 /************************************************************************
977 * Used to reallocate memory
979 static BOOL resizeSafeArray(
980 SAFEARRAY *psa,
981 LONG lDelta)
983 ULONG ulWholeArraySize; /* use as multiplicator */
984 PVOID pvNewBlock = NULL;
985 IUnknown *punk;
986 BSTR bstr;
988 ulWholeArraySize = getArraySize(psa);
990 if(lDelta < 0) { /* array needs to be shorthen */
991 if( isPointer(psa->fFeatures)) /* ptr that need to be released */
992 for(;lDelta < 0; lDelta++) {
993 punk = *(IUnknown**)
994 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
996 if( punk != NULL )
997 IUnknown_Release(punk);
1000 else if(psa->fFeatures & FADF_BSTR) /* BSTR that need to be freed */
1001 for(;lDelta < 0; lDelta++) {
1002 bstr = *(BSTR*)
1003 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
1005 if( bstr != NULL )
1006 SysFreeString( bstr );
1008 else if(psa->fFeatures & FADF_VARIANT)
1009 for(;lDelta < 0; lDelta++) {
1010 VariantClear((VARIANT*)((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements)));
1014 if (!(psa->fFeatures & FADF_CREATEVECTOR))
1016 /* Ok now, if we are enlarging the array, we *MUST* move the whole block
1017 pointed to by pvData. If we are shorthening the array, this move is
1018 optional but we do it anyway becuase the benefit is that we are
1019 releasing to the system the unused memory */
1021 if((pvNewBlock = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, psa->pvData,
1022 (ulWholeArraySize + lDelta) * psa->cbElements)) == NULL)
1023 return FALSE; /* TODO If we get here it means:
1024 SHRINK situation : we've deleted the undesired
1025 data and did not release the memory
1026 GROWING situation: we've been unable to grow the array
1029 else
1031 /* Allocate a new block, because the previous data has been allocated with
1032 the descriptor in SafeArrayCreateVector function. */
1034 if((pvNewBlock = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1035 ulWholeArraySize * psa->cbElements)) == NULL)
1036 return FALSE;
1038 psa->fFeatures &= ~FADF_CREATEVECTOR;
1040 /* reassign to the new block of data */
1041 psa->pvData = pvNewBlock;
1042 return TRUE;
1045 /************************************************************************
1046 * Used to set the fFeatures data member of the SAFEARRAY structure.
1048 static INT getFeatures(VARTYPE vt) {
1049 switch (vt) {
1050 case VT_BSTR: return FADF_BSTR;
1051 case VT_UNKNOWN: return FADF_UNKNOWN;
1052 case VT_DISPATCH: return FADF_DISPATCH;
1053 case VT_VARIANT: return FADF_VARIANT;
1055 return 0;
1058 /************************************************************************
1059 * Used to figure out if the fFeatures data member of the SAFEARRAY
1060 * structure contain any information about the type of data stored...
1062 static BOOL isPointer(
1063 USHORT feature)
1065 switch(feature) {
1066 case FADF_UNKNOWN: return TRUE; /* those are pointers */
1067 case FADF_DISPATCH: return TRUE;
1069 return FALSE;
1072 /************************************************************************
1073 * Used to calculate the displacement when accessing or modifying
1074 * safearray data set.
1076 * Parameters: - LONG *coor is the desired location in the multidimension
1077 * table. Ex for a 3 dim table: coor[] = {1,2,3};
1078 * - ULONG *mat is the format of the table. Ex for a 3 dim
1079 * table mat[] = {4,4,4};
1080 * - USHORT dim is the number of dimension of the SafeArray
1082 static ULONG calcDisplacement(
1083 LONG *coor,
1084 SAFEARRAYBOUND *mat,
1085 LONG dim)
1087 ULONG res = 0;
1088 LONG iterDim;
1090 TRACE("dims is %ld\n", dim);
1092 for (iterDim = dim-1; iterDim >= 0; iterDim--) {
1093 TRACE("%ld: lbound is %ld, adding %ld\n", iterDim, mat[dim-iterDim-1].lLbound,(coor[iterDim] - mat[dim-iterDim-1].lLbound));
1094 res += (coor[iterDim] - mat[dim-iterDim-1].lLbound);
1096 if (iterDim > 0)
1097 res *= mat[dim-iterDim].cElements;
1100 TRACE("SafeArray: calculated displacement is %lu.\n", res);
1101 return(res);
1104 /************************************************************************
1105 * Method used to validate the coordinate received in Put and Get
1106 * methods.
1108 static BOOL validCoordinate(
1109 LONG *coor,
1110 SAFEARRAY *psa)
1112 INT iter=0;
1113 LONG lUBound;
1114 LONG lLBound;
1115 HRESULT hRes;
1117 if (!psa->cDims) { FIXME("no dims?\n");return FALSE; }
1118 for(; iter<psa->cDims; iter++) {
1119 TRACE("coor[%d]=%ld\n", iter, coor[iter]);
1120 if((hRes = SafeArrayGetLBound(psa, (iter+1), &lLBound)) != S_OK) {
1121 FIXME("No lbound?\n");
1122 return FALSE;
1124 if((hRes = SafeArrayGetUBound(psa, (iter+1), &lUBound)) != S_OK) {
1125 FIXME("No ubound?\n");
1126 return FALSE;
1128 if(lLBound > lUBound) {
1129 FIXME("lbound larger than ubound?\n");
1130 return FALSE;
1133 if((coor[iter] < lLBound) || (coor[iter] > lUBound)) {
1134 FIXME("coordinate %ld not within %ld - %ld\n",coor[iter], lLBound, lUBound);
1135 return FALSE;
1138 return TRUE;
1141 /************************************************************************
1142 * Method used to calculate the number of cells of the SA
1144 static ULONG getArraySize(
1145 SAFEARRAY *psa)
1147 USHORT cCount;
1148 ULONG ulWholeArraySize = 1;
1150 for(cCount=0; cCount < psa->cDims; cCount++) /* foreach dimensions... */
1151 ulWholeArraySize *= psa->rgsabound[cCount].cElements;
1153 return ulWholeArraySize;
1157 /************************************************************************
1158 * Method used to handle data space dupplication for Copy32 and CopyData32
1160 static HRESULT duplicateData(
1161 SAFEARRAY *psa,
1162 SAFEARRAY *ppsaOut)
1164 ULONG ulWholeArraySize; /* size of the thing */
1165 LONG lDelta;
1167 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
1169 SafeArrayLock(ppsaOut);
1171 if( isPointer(psa->fFeatures) ) { /* If datatype is object increment
1172 object's reference count */
1173 IUnknown *punk;
1175 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1176 punk = *(IUnknown**)((char *) psa->pvData+(lDelta * psa->cbElements));
1178 if( punk != NULL)
1179 IUnknown_AddRef(punk);
1182 /* Copy the source array data into target array */
1183 memcpy(ppsaOut->pvData, psa->pvData, ulWholeArraySize*psa->cbElements);
1186 else if( psa->fFeatures & FADF_BSTR ) { /* if datatype is BSTR allocate
1187 the BSTR in the new array */
1188 BSTR pbstrReAllocStr = NULL;
1190 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1191 if(( pbstrReAllocStr = SYSDUPSTRING(
1192 *(BSTR*)((char *) psa->pvData+(lDelta * psa->cbElements)))) == NULL) {
1194 SafeArrayUnlock(ppsaOut);
1195 return E_OUTOFMEMORY;
1198 *((BSTR*)((char *)ppsaOut->pvData+(lDelta * psa->cbElements))) =
1199 pbstrReAllocStr;
1203 else if( psa->fFeatures & FADF_VARIANT ) {
1205 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1206 VariantCopy((VARIANT*)((char *) ppsaOut->pvData+(lDelta * psa->cbElements)),
1207 (VARIANT*)((char *) psa->pvData+(lDelta * psa->cbElements)));
1210 } else { /* Simply copy the source array data into target array */
1211 memcpy(ppsaOut->pvData, psa->pvData, ulWholeArraySize*psa->cbElements);
1213 SafeArrayUnlock(ppsaOut);
1214 return S_OK;
1218 /************************************************************************
1219 * SafeArrayGetVartype (OLEAUT32.77)
1220 * Returns the VARTYPE stored in the given safearray
1222 HRESULT WINAPI SafeArrayGetVartype(
1223 SAFEARRAY* psa,
1224 VARTYPE* pvt)
1226 if (psa->fFeatures & FADF_HAVEVARTYPE)
1228 /* VT tag @ negative offset 4 in the array descriptor */
1229 *pvt = ((DWORD*)psa)[-1];
1230 return S_OK;
1233 if (psa->fFeatures & FADF_RECORD)
1235 *pvt = VT_RECORD;
1236 return S_OK;
1239 if (psa->fFeatures & FADF_BSTR)
1241 *pvt = VT_BSTR;
1242 return S_OK;
1245 if (psa->fFeatures & FADF_UNKNOWN)
1247 *pvt = VT_UNKNOWN;
1248 return S_OK;
1251 if (psa->fFeatures & FADF_DISPATCH)
1253 *pvt = VT_UNKNOWN; /* Yes, checked against windows */
1254 return S_OK;
1257 if (psa->fFeatures & FADF_VARIANT)
1259 *pvt = VT_VARIANT;
1260 return S_OK;
1262 if (psa->fFeatures & FADF_HAVEIID)
1264 /* We could check the IID here, but Windows apparently does not
1265 * do that and returns VT_UNKNOWN for VT_DISPATCH too.
1267 *pvt = VT_UNKNOWN;
1268 return S_OK;
1271 WARN("No vt found for safearray\n");
1272 return E_INVALIDARG;
1275 /************************************************************************
1276 * SafeArraySetIID (OLEAUT32.57)
1278 HRESULT WINAPI SafeArraySetIID(SAFEARRAY *arr, REFIID riid) {
1279 IID *xiid = ((IID*)arr)-1;
1280 TRACE("(%p, %s).\n",arr,debugstr_guid(riid));
1282 if (!arr || !(arr->fFeatures & FADF_HAVEIID))
1283 return E_INVALIDARG;
1284 memcpy(xiid, riid, sizeof(GUID));
1285 return S_OK;
1288 /************************************************************************
1289 * SafeArrayGetIID (OLEAUT32.67)
1291 HRESULT WINAPI SafeArrayGetIID(SAFEARRAY *arr, IID *riid) {
1292 IID *xiid = ((IID*)arr)-1;
1293 TRACE("(%p, %s).\n",arr,debugstr_guid(riid));
1295 if (!arr || !(arr->fFeatures & FADF_HAVEIID))
1296 return E_INVALIDARG;
1297 memcpy(riid, xiid, sizeof(GUID));
1298 return S_OK;
1301 /************************************************************************
1302 * SafeArraySetRecordInfo (OLEAUT32.44)
1304 HRESULT WINAPI SafeArraySetRecordInfo(SAFEARRAY *arr, IRecordInfo *iface) {
1305 LPRECORDINFO oldiface;
1307 if (!arr || !(arr->fFeatures & FADF_RECORD))
1308 return E_INVALIDARG;
1309 oldiface = ((IRecordInfo**)arr)[-1];
1310 if (oldiface)
1311 IRecordInfo_Release(oldiface);
1312 ((IRecordInfo**)arr)[-1] = iface;
1313 if (iface)
1314 IRecordInfo_AddRef(iface);
1315 return S_OK;
1318 /************************************************************************
1319 * SafeArrayGetRecordInfo (OLEAUT32.45)
1321 HRESULT WINAPI SafeArrayGetRecordInfo(SAFEARRAY *arr, IRecordInfo** iface) {
1322 if (!arr || !(arr->fFeatures & FADF_RECORD))
1323 return E_INVALIDARG;
1324 *iface = ((IRecordInfo**)arr)[-1];
1325 if (*iface)
1326 IRecordInfo_AddRef(*iface);
1327 return S_OK;