source: trunk/src/oleaut32/safearray.c@ 8450

Last change on this file since 8450 was 8450, checked in by sandervl, 23 years ago

Wine resync

File size: 35.3 KB
Line 
1/*************************************************************************
2 * OLE Automation
3 * SafeArray Implementation
4 *
5 * This file contains the implementation of the SafeArray interface.
6 *
7 * Copyright 1999 Sylvain St-Germain
8 *
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.
13 *
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.
18 *
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
22 */
23#ifdef __WIN32OS2__
24#define HAVE_FLOAT_H
25#define WINE_LARGE_INTEGER
26#include "oleaut32.h"
27
28#endif
29
30#include <stdio.h>
31#include <string.h>
32#include "windef.h"
33#include "winerror.h"
34#include "winbase.h"
35#include "oleauto.h"
36#include "wine/obj_base.h"
37#include "wine/debug.h"
38
39WINE_DEFAULT_DEBUG_CHANNEL(ole);
40
41#define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
42
43/* Locally used methods */
44static INT
45endOfDim(LONG *coor, SAFEARRAYBOUND *mat, LONG dim, LONG realDim);
46
47static ULONG
48calcDisplacement(LONG *coor, SAFEARRAYBOUND *mat, LONG dim);
49
50static BOOL
51isPointer(USHORT feature);
52
53static INT
54getFeatures(VARTYPE vt);
55
56static BOOL
57validCoordinate(LONG *coor, SAFEARRAY *psa);
58
59static BOOL
60resizeSafeArray(SAFEARRAY *psa, LONG lDelta);
61
62static BOOL
63validArg(SAFEARRAY *psa);
64
65static ULONG
66getArraySize(SAFEARRAY *psa);
67
68static HRESULT
69duplicateData(SAFEARRAY *psa, SAFEARRAY **ppsaOut);
70
71/* Association between VARTYPE and their size.
72 A size of zero is defined for the unsupported types. */
73
74#define VARTYPE_NOT_SUPPORTED 0
75static const ULONG VARTYPE_SIZE[] =
76{
77 /* this is taken from wtypes.h. Only [S]es are supported by the SafeArray */
78VARTYPE_NOT_SUPPORTED, /* VT_EMPTY [V] [P] nothing */
79VARTYPE_NOT_SUPPORTED, /* VT_NULL [V] [P] SQL style Nul */
802, /* VT_I2 [V][T][P][S] 2 byte signed int */
814, /* VT_I4 [V][T][P][S] 4 byte signed int */
824, /* VT_R4 [V][T][P][S] 4 byte real */
838, /* VT_R8 [V][T][P][S] 8 byte real */
848, /* VT_CY [V][T][P][S] currency */
858, /* VT_DATE [V][T][P][S] date */
86sizeof(BSTR), /* VT_BSTR [V][T][P][S] OLE Automation string*/
87sizeof(LPDISPATCH), /* VT_DISPATCH [V][T][P][S] IDispatch * */
884, /* VT_ERROR [V][T] [S] SCODE */
894, /* VT_BOOL [V][T][P][S] True=-1, False=0*/
90sizeof(VARIANT), /* VT_VARIANT [V][T][P][S] VARIANT * */
91sizeof(LPUNKNOWN), /* VT_UNKNOWN [V][T] [S] IUnknown * */
92sizeof(DECIMAL), /* VT_DECIMAL [V][T] [S] 16 byte fixed point */
93VARTYPE_NOT_SUPPORTED, /* no VARTYPE here..... */
94VARTYPE_NOT_SUPPORTED, /* VT_I1 [T] signed char */
951, /* VT_UI1 [V][T][P][S] unsigned char */
96VARTYPE_NOT_SUPPORTED, /* VT_UI2 [T][P] unsigned short */
97VARTYPE_NOT_SUPPORTED, /* VT_UI4 [T][P] unsigned short */
98VARTYPE_NOT_SUPPORTED, /* VT_I8 [T][P] signed 64-bit int */
99VARTYPE_NOT_SUPPORTED, /* VT_UI8 [T][P] unsigned 64-bit int */
100VARTYPE_NOT_SUPPORTED, /* VT_INT [T] signed machine int */
101VARTYPE_NOT_SUPPORTED, /* VT_UINT [T] unsigned machine int */
102VARTYPE_NOT_SUPPORTED, /* VT_VOID [T] C style void */
103VARTYPE_NOT_SUPPORTED, /* VT_HRESULT [T] Standard return type */
104VARTYPE_NOT_SUPPORTED, /* VT_PTR [T] pointer type */
105VARTYPE_NOT_SUPPORTED, /* VT_SAFEARRAY [T] (use VT_ARRAY in VARIANT)*/
106VARTYPE_NOT_SUPPORTED, /* VT_CARRAY [T] C style array */
107VARTYPE_NOT_SUPPORTED, /* VT_USERDEFINED [T] user defined type */
108VARTYPE_NOT_SUPPORTED, /* VT_LPSTR [T][P] null terminated string */
109VARTYPE_NOT_SUPPORTED, /* VT_LPWSTR [T][P] wide null term string */
110VARTYPE_NOT_SUPPORTED, /* VT_FILETIME [P] FILETIME */
111VARTYPE_NOT_SUPPORTED, /* VT_BLOB [P] Length prefixed bytes */
112VARTYPE_NOT_SUPPORTED, /* VT_STREAM [P] Name of stream follows */
113VARTYPE_NOT_SUPPORTED, /* VT_STORAGE [P] Name of storage follows */
114VARTYPE_NOT_SUPPORTED, /* VT_STREAMED_OBJECT[P] Stream contains an object*/
115VARTYPE_NOT_SUPPORTED, /* VT_STORED_OBJECT [P] Storage contains object*/
116VARTYPE_NOT_SUPPORTED, /* VT_BLOB_OBJECT [P] Blob contains an object*/
117VARTYPE_NOT_SUPPORTED, /* VT_CF [P] Clipboard format */
118VARTYPE_NOT_SUPPORTED, /* VT_CLSID [P] A Class ID */
119VARTYPE_NOT_SUPPORTED, /* VT_VECTOR [P] simple counted array */
120VARTYPE_NOT_SUPPORTED, /* VT_ARRAY [V] SAFEARRAY* */
121VARTYPE_NOT_SUPPORTED /* VT_BYREF [V] void* for local use */
122};
123
124static const int LAST_VARTYPE = sizeof(VARTYPE_SIZE)/sizeof(VARTYPE_SIZE[0]);
125
126
127/*************************************************************************
128 * SafeArrayAllocDescriptor (OLEAUT32.36)
129 * Allocate the appropriate amount of memory for the SafeArray descriptor
130 */
131HRESULT WINAPI SafeArrayAllocDescriptor(
132 UINT cDims,
133 SAFEARRAY **ppsaOut)
134{
135 SAFEARRAYBOUND *sab;
136 LONG allocSize = 0;
137
138 /* SAFEARRAY + SAFEARRAYBOUND * (cDims -1) ( -1 because there is already one
139 ( in SAFEARRAY struct */
140 allocSize = sizeof(**ppsaOut) + (sizeof(*sab) * (cDims-1));
141
142 /* Allocate memory for SAFEARRAY struc */
143 if(( (*ppsaOut)=HeapAlloc(
144 GetProcessHeap(), HEAP_ZERO_MEMORY, allocSize)) == NULL){
145 return(E_UNEXPECTED);
146 }
147 TRACE("SafeArray: %lu bytes allocated for descriptor.\n", allocSize);
148
149 return(S_OK);
150}
151
152/*************************************************************************
153 * SafeArrayAllocDescriptorEx (OLEAUT32.429)
154 * Allocate the appropriate amount of memory for the SafeArray descriptor
155 *
156 * This is a minimal implementation just to get things moving.
157 *
158 * The MSDN documentation on this doesn't tell us much.
159 */
160HRESULT WINAPI SafeArrayAllocDescriptorEx(
161 VARTYPE vt,
162 UINT cDims,
163 SAFEARRAY **ppsaOut)
164{
165 if ( (vt >= LAST_VARTYPE) ||
166 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
167 return E_UNEXPECTED;
168
169 return SafeArrayAllocDescriptor (cDims, ppsaOut);
170}
171
172/*************************************************************************
173 * SafeArrayAllocData (OLEAUT32.37)
174 * Allocate the appropriate amount of data for the SafeArray data
175 */
176HRESULT WINAPI SafeArrayAllocData(
177 SAFEARRAY *psa)
178{
179 ULONG ulWholeArraySize; /* to store the size of the whole thing */
180
181 if(! validArg(psa))
182 return E_INVALIDARG;
183
184 ulWholeArraySize = getArraySize(psa);
185
186 /* Allocate memory for the data itself */
187 if((psa->pvData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
188 psa->cbElements*ulWholeArraySize)) == NULL)
189 return(E_UNEXPECTED);
190
191 TRACE("SafeArray: %lu bytes allocated for data at %p (%lu objects).\n",
192 psa->cbElements*ulWholeArraySize, psa->pvData, ulWholeArraySize);
193
194 return(S_OK);
195}
196
197/*************************************************************************
198 * SafeArrayCreate (OLEAUT32.15)
199 * Create a SafeArray object by encapsulating AllocDescriptor and AllocData
200 */
201SAFEARRAY* WINAPI SafeArrayCreate(
202 VARTYPE vt,
203 UINT cDims,
204 SAFEARRAYBOUND *rgsabound)
205{
206 SAFEARRAY *psa;
207 HRESULT hRes;
208 USHORT cDim;
209
210 /* Validate supported VARTYPE */
211 if ( (vt >= LAST_VARTYPE) ||
212 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
213 return NULL;
214
215 /* Allocate memory for the array descriptor */
216 if( FAILED( hRes = SafeArrayAllocDescriptor(cDims, &psa)))
217 return NULL;
218
219 /* setup data members... */
220 psa->cDims = cDims;
221 psa->fFeatures = getFeatures(vt);
222 psa->cLocks = 0;
223 psa->pvData = NULL;
224 psa->cbElements= VARTYPE_SIZE[vt];
225
226 /* Invert the bounds ... */
227 for(cDim=0; cDim < psa->cDims; cDim++) {
228 psa->rgsabound[cDim].cElements = rgsabound[psa->cDims-cDim-1].cElements;
229 psa->rgsabound[cDim].lLbound = rgsabound[psa->cDims-cDim-1].lLbound;
230 }
231
232 /* allocate memory for the data... */
233 if( FAILED( hRes = SafeArrayAllocData(psa))) {
234 SafeArrayDestroyDescriptor(psa);
235 ERR("() : Failed to allocate the Safe Array data\n");
236 return NULL;
237 }
238
239 return(psa);
240}
241
242/*************************************************************************
243 * SafeArrayDestroyDescriptor (OLEAUT32.38)
244 * Frees the memory associated with the descriptor.
245 */
246HRESULT WINAPI SafeArrayDestroyDescriptor(
247 SAFEARRAY *psa)
248{
249 /* Check for lockness before to free... */
250 if(psa->cLocks > 0)
251 return DISP_E_ARRAYISLOCKED;
252
253 /* The array is unlocked, then, deallocate memory */
254 if(HeapFree( GetProcessHeap(), 0, psa) == FALSE)
255 return E_UNEXPECTED;
256
257 return(S_OK);
258}
259
260
261/*************************************************************************
262 * SafeArrayLock (OLEAUT32.21)
263 * Increment the lock counter
264 *
265 * Doc says (MSDN Library ) that psa->pvData should be made available (!= NULL)
266 * only when psa->cLocks is > 0... I don't get it since pvData is allocated
267 * before the array is locked, therefore
268 */
269HRESULT WINAPI SafeArrayLock(
270 SAFEARRAY *psa)
271{
272 if(! validArg(psa))
273 return E_INVALIDARG;
274
275 psa->cLocks++;
276
277 return(S_OK);
278}
279
280/*************************************************************************
281 * SafeArrayUnlock (OLEAUT32.22)
282 * Decrement the lock counter
283 */
284HRESULT WINAPI SafeArrayUnlock(
285 SAFEARRAY *psa)
286{
287 if(! validArg(psa))
288 return E_INVALIDARG;
289
290 if (psa->cLocks > 0)
291 psa->cLocks--;
292
293 return(S_OK);
294}
295
296
297/*************************************************************************
298 * SafeArrayPutElement (OLEAUT32.26)
299 * Set the data at the given coordinate
300 */
301HRESULT WINAPI SafeArrayPutElement(
302 SAFEARRAY *psa,
303 LONG *rgIndices,
304 void *pv)
305{
306 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
307 the desired one... */
308 PVOID elementStorageAddress = NULL; /* Adress to store the data */
309
310 /* Validate the index given */
311 if(! validCoordinate(rgIndices, psa))
312 return DISP_E_BADINDEX;
313 if(! validArg(psa))
314 return E_INVALIDARG;
315
316 if( SafeArrayLock(psa) == S_OK) {
317
318 /* Figure out the number of items to skip */
319 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
320
321 /* Figure out the number of byte to skip ... */
322 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
323
324 if(isPointer(psa->fFeatures)) { /* increment ref count for this pointer */
325
326 *((PVOID*)elementStorageAddress) = *(PVOID*)pv;
327 IUnknown_AddRef( *(IUnknown**)pv);
328
329 } else {
330
331 if(psa->fFeatures == FADF_BSTR) { /* Create a new object */
332 BSTR pbstrReAllocStr = NULL;
333 if(pv &&
334 ((pbstrReAllocStr = SYSDUPSTRING( (OLECHAR*)pv )) == NULL)) {
335 SafeArrayUnlock(psa);
336 return E_OUTOFMEMORY;
337 } else
338 *((BSTR*)elementStorageAddress) = pbstrReAllocStr;
339 }
340 else if(psa->fFeatures == FADF_VARIANT) {
341 HRESULT hr = VariantCopy(elementStorageAddress, pv);
342 if (FAILED(hr)) {
343 SafeArrayUnlock(psa);
344 return hr;
345 }
346 }
347 else /* duplicate the memory */
348 memcpy(elementStorageAddress, pv, SafeArrayGetElemsize(psa) );
349 }
350
351 } else {
352 ERR("SafeArray: Cannot lock array....\n");
353 return E_UNEXPECTED; /* UNDOC error condition */
354 }
355
356 TRACE("SafeArray: item put at adress %p.\n",elementStorageAddress);
357 return SafeArrayUnlock(psa);
358}
359
360
361/*************************************************************************
362 * SafeArrayGetElement (OLEAUT32.25)
363 * Return the data element corresponding the the given coordinate
364 */
365HRESULT WINAPI SafeArrayGetElement(
366 SAFEARRAY *psa,
367 LONG *rgIndices,
368 void *pv)
369{
370 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
371 the desired one... */
372 PVOID elementStorageAddress = NULL; /* Adress to store the data */
373
374 if(! validArg(psa))
375 return E_INVALIDARG;
376
377 if(! validCoordinate(rgIndices, psa)) /* Validate the index given */
378 return(DISP_E_BADINDEX);
379
380 if( SafeArrayLock(psa) == S_OK) {
381
382 /* Figure out the number of items to skip */
383 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
384
385 /* Figure out the number of byte to skip ... */
386 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
387
388 if( psa->fFeatures == FADF_BSTR) { /* reallocate the obj */
389 BSTR pbstrStoredStr = *(OLECHAR**)elementStorageAddress;
390 BSTR pbstrReturnedStr = NULL;
391 if( pbstrStoredStr &&
392 ((pbstrReturnedStr = SYSDUPSTRING( pbstrStoredStr )) == NULL) ) {
393 SafeArrayUnlock(psa);
394 return E_OUTOFMEMORY;
395 } else
396 *((BSTR*)pv) = pbstrReturnedStr;
397 }
398 else if( psa->fFeatures == FADF_VARIANT) {
399 HRESULT hr;
400 VariantInit(pv);
401 hr = VariantCopy(pv, elementStorageAddress);
402 if (FAILED(hr)) {
403 SafeArrayUnlock(psa);
404 return hr;
405 }
406 }
407 else if( isPointer(psa->fFeatures) ) /* simply copy the pointer */
408 *(PVOID*)pv = *((PVOID*)elementStorageAddress);
409 else /* copy the bytes */
410 memcpy(pv, elementStorageAddress, psa->cbElements );
411
412 } else {
413 ERR("SafeArray: Cannot lock array....\n");
414 return E_UNEXPECTED; /* UNDOC error condition */
415 }
416
417 return( SafeArrayUnlock(psa) );
418}
419
420/*************************************************************************
421 * SafeArrayGetUBound (OLEAUT32.19)
422 * return the UP bound for a given array dimension
423 */
424HRESULT WINAPI SafeArrayGetUBound(
425 SAFEARRAY *psa,
426 UINT nDim,
427 LONG *plUbound)
428{
429 if(! validArg(psa))
430 return E_INVALIDARG;
431
432 if(nDim > psa->cDims)
433 return DISP_E_BADINDEX;
434
435 if(0 == nDim)
436 return DISP_E_BADINDEX;
437
438 *plUbound = psa->rgsabound[nDim-1].lLbound +
439 psa->rgsabound[nDim-1].cElements - 1;
440
441 return S_OK;
442}
443
444/*************************************************************************
445 * SafeArrayGetLBound (OLEAUT32.20)
446 * Return the LO bound for a given array dimension
447 */
448HRESULT WINAPI SafeArrayGetLBound(
449 SAFEARRAY *psa,
450 UINT nDim,
451 LONG *plLbound)
452{
453 if(! validArg(psa))
454 return E_INVALIDARG;
455
456 if(nDim > psa->cDims)
457 return DISP_E_BADINDEX;
458
459 if(0 == nDim)
460 return DISP_E_BADINDEX;
461
462 *plLbound = psa->rgsabound[nDim-1].lLbound;
463 return S_OK;
464}
465
466/*************************************************************************
467 * SafeArrayGetDim (OLEAUT32.17)
468 * returns the number of dimension in the array
469 */
470UINT WINAPI SafeArrayGetDim(
471 SAFEARRAY * psa)
472{
473 /*
474 * A quick test in Windows shows that the behavior here for an invalid
475 * pointer is to return 0.
476 */
477 if(! validArg(psa))
478 return 0;
479
480 return psa->cDims;
481}
482
483/*************************************************************************
484 * SafeArrayGetElemsize (OLEAUT32.18)
485 * Return the size of the element in the array
486 */
487UINT WINAPI SafeArrayGetElemsize(
488 SAFEARRAY * psa)
489{
490 /*
491 * A quick test in Windows shows that the behavior here for an invalid
492 * pointer is to return 0.
493 */
494 if(! validArg(psa))
495 return 0;
496
497 return psa->cbElements;
498}
499
500/*************************************************************************
501 * SafeArrayAccessData (OLEAUT32.23)
502 * increment the access count and return the data
503 */
504HRESULT WINAPI SafeArrayAccessData(
505 SAFEARRAY *psa,
506 void **ppvData)
507{
508 HRESULT hRes;
509
510 if(! validArg(psa))
511 return E_INVALIDARG;
512
513 hRes = SafeArrayLock(psa);
514
515 switch (hRes) {
516 case S_OK:
517 (*ppvData) = psa->pvData;
518 break;
519 case E_INVALIDARG:
520 (*ppvData) = NULL;
521 return E_INVALIDARG;
522 }
523
524 return S_OK;
525}
526
527
528/*************************************************************************
529 * SafeArrayUnaccessData (OLEAUT32.24)
530 * Decrement the access count
531 */
532HRESULT WINAPI SafeArrayUnaccessData(
533 SAFEARRAY * psa)
534{
535 if(! validArg(psa))
536 return E_INVALIDARG;
537
538 return(SafeArrayUnlock(psa));
539}
540
541/************************************************************************
542 * SafeArrayPtrOfIndex (OLEAUT32.148)
543 * Return a pointer to the element at rgIndices
544 */
545HRESULT WINAPI SafeArrayPtrOfIndex(
546 SAFEARRAY *psa,
547 LONG *rgIndices,
548 void **ppvData)
549{
550 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
551 the desired one... */
552
553 if(! validArg(psa))
554 return E_INVALIDARG;
555
556 if(! validCoordinate(rgIndices, psa))
557 return DISP_E_BADINDEX;
558
559 /* Although it is dangerous to do this without having a lock, it is not
560 * illegal. Microsoft do warn of the danger.
561 */
562
563 /* Figure out the number of items to skip */
564 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
565
566 *ppvData = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
567
568 return S_OK;
569}
570
571/************************************************************************
572 * SafeArrayDestroyData (OLEAUT32.39)
573 * Frees the memory data bloc
574 */
575HRESULT WINAPI SafeArrayDestroyData(
576 SAFEARRAY *psa)
577{
578 HRESULT hRes;
579 ULONG ulWholeArraySize; /* count spot in array */
580 ULONG ulDataIter; /* to iterate the data space */
581
582 if(! validArg(psa))
583 return E_INVALIDARG;
584
585 if(psa->cLocks > 0)
586 return DISP_E_ARRAYISLOCKED;
587
588 ulWholeArraySize = getArraySize(psa);
589
590 if(isPointer(psa->fFeatures)) { /* release the pointers */
591 IUnknown *punk;
592
593 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
594 punk = *(IUnknown**)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
595
596 if( punk != NULL)
597 IUnknown_Release(punk);
598 }
599
600 }
601 else if(psa->fFeatures & FADF_BSTR) { /* deallocate the obj */
602 BSTR bstr;
603
604 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
605 bstr = *(BSTR*)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
606
607 if( bstr != NULL)
608 SysFreeString( bstr );
609 }
610 }
611 else if(psa->fFeatures & FADF_VARIANT) { /* deallocate the obj */
612
613 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
614 VariantClear((VARIANT*)((char *) psa->pvData+(ulDataIter*(psa->cbElements))));
615 }
616 }
617
618 /* check if this array is a Vector, in which case do not free the data
619 block since it has been allocated by AllocDescriptor and therefore
620 deserve to be freed by DestroyDescriptor */
621 if(!(psa->fFeatures & FADF_CREATEVECTOR)) { /* Set when we do CreateVector */
622
623 /* free the whole chunk */
624 if((hRes = HeapFree( GetProcessHeap(), 0, psa->pvData)) == 0) /*falied*/
625 return E_UNEXPECTED; /* UNDOC error condition */
626
627 psa->pvData = NULL;
628 }
629
630 return S_OK;
631}
632
633/************************************************************************
634 * SafeArrayCopyData (OLEAUT32.412)
635 * Copy the psaSource's data block into psaTarget if dimension and size
636 * permits it.
637 */
638HRESULT WINAPI SafeArrayCopyData(
639 SAFEARRAY *psaSource,
640 SAFEARRAY **psaTarget)
641{
642 USHORT cDimCount; /* looper */
643 LONG lDelta; /* looper */
644 IUnknown *punk;
645 ULONG ulWholeArraySize; /* Number of item in SA */
646 BSTR bstr;
647
648 if(! (validArg(psaSource) && validArg(*psaTarget)) )
649 return E_INVALIDARG;
650
651 if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(*psaTarget))
652 return E_INVALIDARG;
653
654 ulWholeArraySize = getArraySize(psaSource);
655
656 /* The two arrays boundaries must be of same lenght */
657 for(cDimCount=0;cDimCount < psaSource->cDims; cDimCount++)
658 if( psaSource->rgsabound[cDimCount].cElements !=
659 (*psaTarget)->rgsabound[cDimCount].cElements)
660 return E_INVALIDARG;
661
662 if( isPointer((*psaTarget)->fFeatures) ) { /* the target contains ptr
663 that must be released */
664 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
665 punk = *(IUnknown**)
666 ((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
667
668 if( punk != NULL)
669 IUnknown_Release(punk);
670 }
671
672 }
673 else if( (*psaTarget)->fFeatures & FADF_BSTR) { /* the target contain BSTR
674 that must be freed */
675 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
676 bstr =
677 *(BSTR*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
678
679 if( bstr != NULL)
680 SysFreeString( bstr );
681 }
682 }
683 else if( (*psaTarget)->fFeatures & FADF_VARIANT) {
684
685 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
686 VariantClear((VARIANT*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements)));
687 }
688 }
689
690 return duplicateData(psaSource, psaTarget);
691}
692
693/************************************************************************
694 * SafeArrayDestroy (OLEAUT32.16)
695 * Deallocates all memory reserved for the SafeArray
696 */
697HRESULT WINAPI SafeArrayDestroy(
698 SAFEARRAY * psa)
699{
700 HRESULT hRes;
701
702 if(! validArg(psa))
703 return E_INVALIDARG;
704
705 if(psa->cLocks > 0)
706 return DISP_E_ARRAYISLOCKED;
707
708 if((hRes = SafeArrayDestroyData( psa )) == S_OK)
709 if((hRes = SafeArrayDestroyDescriptor( psa )) == S_OK)
710 return S_OK;
711
712 return E_UNEXPECTED; /* UNDOC error condition */
713}
714
715/************************************************************************
716 * SafeArrayCopy (OLEAUT32.27)
717 * Make a dupplicate of a SafeArray
718 */
719HRESULT WINAPI SafeArrayCopy(
720 SAFEARRAY *psa,
721 SAFEARRAY **ppsaOut)
722{
723 HRESULT hRes;
724 DWORD dAllocSize;
725 ULONG ulWholeArraySize; /* size of the thing */
726
727 if(! validArg(psa))
728 return E_INVALIDARG;
729
730 if((hRes=SafeArrayAllocDescriptor(psa->cDims, ppsaOut)) == S_OK){
731
732 /* Duplicate the SAFEARRAY struc */
733 memcpy(*ppsaOut, psa,
734 sizeof(*psa)+(sizeof(*(psa->rgsabound))*(psa->cDims-1)));
735
736 (*ppsaOut)->pvData = NULL; /* do not point to the same data area */
737
738 /* make sure the new safe array doesn't have the FADF_CREATEVECTOR flag,
739 because the data has not been allocated with the descriptor. */
740 (*ppsaOut)->fFeatures &= ~FADF_CREATEVECTOR;
741
742 /* Get the allocated memory size for source and allocate it for target */
743 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
744 dAllocSize = ulWholeArraySize*psa->cbElements;
745
746 (*ppsaOut)->pvData =
747 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dAllocSize);
748 if( (*ppsaOut)->pvData != NULL) { /* HeapAlloc succeed */
749
750 if( (hRes=duplicateData(psa, ppsaOut)) != S_OK) { /* E_OUTOFMEMORY */
751 HeapFree(GetProcessHeap(), 0, (*ppsaOut)->pvData);
752 (*ppsaOut)->pvData = NULL;
753 SafeArrayDestroyDescriptor(*ppsaOut);
754 return hRes;
755 }
756
757 } else { /* failed to allocate or dupplicate... */
758 SafeArrayDestroyDescriptor(*ppsaOut);
759 return E_UNEXPECTED; /* UNDOC error condition */
760 }
761 } else { /* failed to allocate mem for descriptor */
762 return E_OUTOFMEMORY; /* UNDOC error condiftion */
763 }
764
765 return S_OK;
766}
767
768/************************************************************************
769 * SafeArrayCreateVector (OLEAUT32.411)
770 * Creates a one dimension safearray where the data is next to the
771 * SAFEARRAY structure.
772 */
773SAFEARRAY* WINAPI SafeArrayCreateVector(
774 VARTYPE vt,
775 LONG lLbound,
776 ULONG cElements)
777{
778 SAFEARRAY *psa;
779
780 /* Validate supported VARTYPE */
781 if ( (vt >= LAST_VARTYPE) ||
782 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
783 return NULL;
784
785 /* Allocate memory for the array descriptor and data contiguously */
786 if( FAILED( psa = HeapAlloc( GetProcessHeap(),
787 HEAP_ZERO_MEMORY,
788 (sizeof(*psa) + (VARTYPE_SIZE[vt] * cElements))))) {
789 return NULL;
790 }
791
792 /* setup data members... */
793 psa->cDims = 1; /* always and forever */
794 psa->fFeatures = getFeatures(vt) | FADF_CREATEVECTOR; /* undocumented flag used by Microsoft */
795 psa->cLocks = 0;
796 psa->pvData = (BYTE*)psa + sizeof(*psa);
797 psa->cbElements = VARTYPE_SIZE[vt];
798
799 psa->rgsabound[0].cElements = cElements;
800 psa->rgsabound[0].lLbound = lLbound;
801
802 return(psa);
803}
804
805/************************************************************************
806 * SafeArrayRedim (OLEAUT32.40)
807 * Changes the caracteristics of the last dimension of the SafeArray
808 */
809HRESULT WINAPI SafeArrayRedim(
810 SAFEARRAY *psa,
811 SAFEARRAYBOUND *psaboundNew)
812{
813 LONG lDelta; /* hold difference in size */
814 USHORT cDims=1; /* dims counter */
815
816 if( !validArg(psa) )
817 return E_INVALIDARG;
818
819 if( psa->cLocks > 0 )
820 return DISP_E_ARRAYISLOCKED;
821
822 if( psa->fFeatures & FADF_FIXEDSIZE )
823 return E_INVALIDARG;
824
825 if( SafeArrayLock(psa)==E_UNEXPECTED )
826 return E_UNEXPECTED;/* UNDOC error condition */
827
828 /* find the delta in number of array spot to apply to the new array */
829 lDelta = psaboundNew->cElements - psa->rgsabound[0].cElements;
830 for(; cDims < psa->cDims; cDims++)
831 /* delta in number of spot implied by modifying the last dimension */
832 lDelta *= psa->rgsabound[cDims].cElements;
833
834 TRACE("elements=%ld, Lbound=%ld (delta=%ld)\n", psaboundNew->cElements, psaboundNew->lLbound, lDelta);
835
836 if (lDelta == 0) { ;/* same size, maybe a change of lLbound, just set it */
837
838 } else /* need to enlarge (lDelta +) reduce (lDelta -) */
839 if(! resizeSafeArray(psa, lDelta))
840 return E_UNEXPECTED; /* UNDOC error condition */
841
842 /* the only modifyable dimension sits in [0] as the dimensions were reversed
843 at array creation time... */
844 psa->rgsabound[0].cElements = psaboundNew->cElements;
845 psa->rgsabound[0].lLbound = psaboundNew->lLbound;
846
847 return SafeArrayUnlock(psa);
848}
849
850/************************************************************************
851 * NOT WINDOWS API - SafeArray* Utility functions
852 ************************************************************************/
853
854/************************************************************************
855 * Used to validate the SAFEARRAY type of arg
856 */
857static BOOL validArg(
858 SAFEARRAY *psa)
859{
860 SAFEARRAYBOUND *sab;
861 LONG psaSize = 0;
862 LONG descSize = 0;
863 LONG fullSize = 0;
864
865 /*
866 * Let's check for the null pointer just in case.
867 */
868 if (psa == NULL)
869 return FALSE;
870
871 /* Check whether the size of the chunk makes sense... That's the only thing
872 I can think of now... */
873
874 psaSize = HeapSize(GetProcessHeap(), 0, psa);
875 if (psaSize == -1)
876 /* uh, foreign heap. Better don't mess with it ! */
877 return TRUE;
878
879 /* size of the descriptor when the SA is not created with CreateVector */
880 descSize = sizeof(*psa) + (sizeof(*sab) * (psa->cDims-1));
881
882 /* size of the descriptor + data when created with CreateVector */
883 fullSize = sizeof(*psa) + (psa->cbElements * psa->rgsabound[0].cElements);
884
885 return((psaSize >= descSize) || (psaSize >= fullSize));
886}
887
888/************************************************************************
889 * Used to reallocate memory
890 */
891static BOOL resizeSafeArray(
892 SAFEARRAY *psa,
893 LONG lDelta)
894{
895 ULONG ulWholeArraySize; /* use as multiplicator */
896 PVOID pvNewBlock = NULL;
897 IUnknown *punk;
898 BSTR bstr;
899
900 ulWholeArraySize = getArraySize(psa);
901
902 if(lDelta < 0) { /* array needs to be shorthen */
903 if( isPointer(psa->fFeatures)) /* ptr that need to be released */
904 for(;lDelta < 0; lDelta++) {
905 punk = *(IUnknown**)
906 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
907
908 if( punk != NULL )
909 IUnknown_Release(punk);
910 }
911
912 else if(psa->fFeatures & FADF_BSTR) /* BSTR that need to be freed */
913 for(;lDelta < 0; lDelta++) {
914 bstr = *(BSTR*)
915 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
916
917 if( bstr != NULL )
918 SysFreeString( bstr );
919 }
920 else if(psa->fFeatures & FADF_VARIANT)
921 for(;lDelta < 0; lDelta++) {
922 VariantClear((VARIANT*)((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements)));
923 }
924 }
925
926 if (!(psa->fFeatures & FADF_CREATEVECTOR))
927 {
928 /* Ok now, if we are enlarging the array, we *MUST* move the whole block
929 pointed to by pvData. If we are shorthening the array, this move is
930 optional but we do it anyway becuase the benefit is that we are
931 releasing to the system the unused memory */
932
933 if((pvNewBlock = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, psa->pvData,
934 (ulWholeArraySize + lDelta) * psa->cbElements)) == NULL)
935 return FALSE; /* TODO If we get here it means:
936 SHRINK situation : we've deleted the undesired
937 data and did not release the memory
938 GROWING situation: we've been unable to grow the array
939 */
940 }
941 else
942 {
943 /* Allocate a new block, because the previous data has been allocated with
944 the descriptor in SafeArrayCreateVector function. */
945
946 if((pvNewBlock = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
947 ulWholeArraySize * psa->cbElements)) == NULL)
948 return FALSE;
949
950 psa->fFeatures &= ~FADF_CREATEVECTOR;
951 }
952 /* reassign to the new block of data */
953 psa->pvData = pvNewBlock;
954 return TRUE;
955}
956
957/************************************************************************
958 * Used to set the fFeatures data member of the SAFEARRAY structure.
959 */
960static INT getFeatures(
961 VARTYPE vt)
962{
963 switch(vt) {
964 case VT_BSTR: return FADF_BSTR;
965 case VT_UNKNOWN: return FADF_UNKNOWN;
966 case VT_DISPATCH: return FADF_DISPATCH;
967 case VT_VARIANT: return FADF_VARIANT;
968 }
969 return 0;
970}
971
972/************************************************************************
973 * Used to figure out if the fFeatures data member of the SAFEARRAY
974 * structure contain any information about the type of data stored...
975 */
976static BOOL isPointer(
977 USHORT feature)
978{
979 switch(feature) {
980 case FADF_UNKNOWN: return TRUE; /* those are pointers */
981 case FADF_DISPATCH: return TRUE;
982 }
983 return FALSE;
984}
985
986/************************************************************************
987 * Used to calculate the displacement when accessing or modifying
988 * safearray data set.
989 *
990 * Parameters: - LONG *coor is the desired location in the multidimension
991 * table. Ex for a 3 dim table: coor[] = {1,2,3};
992 * - ULONG *mat is the format of the table. Ex for a 3 dim
993 * table mat[] = {4,4,4};
994 * - USHORT dim is the number of dimension of the SafeArray
995 */
996static ULONG calcDisplacement(
997 LONG *coor,
998 SAFEARRAYBOUND *mat,
999 LONG dim)
1000{
1001 ULONG res = 0;
1002 LONG iterDim;
1003
1004 for(iterDim=0; iterDim<dim; iterDim++)
1005 /* the -mat[dim] bring coor[dim] relative to 0 for calculation */
1006 res += ((coor[iterDim]-mat[iterDim].lLbound) *
1007 endOfDim(coor, mat, iterDim+1, dim));
1008
1009 TRACE("SafeArray: calculated displacement is %lu.\n", res);
1010 return(res);
1011}
1012
1013/************************************************************************
1014 * Recursivity agent for calcDisplacement method. Used within Put and
1015 * Get methods.
1016 */
1017static INT endOfDim(
1018 LONG *coor,
1019 SAFEARRAYBOUND *mat,
1020 LONG dim,
1021 LONG realDim)
1022{
1023 if(dim==realDim)
1024 return 1;
1025 else
1026 return (endOfDim(coor, mat, dim+1, realDim) * mat[dim].cElements);
1027}
1028
1029
1030/************************************************************************
1031 * Method used to validate the coordinate received in Put and Get
1032 * methods.
1033 */
1034static BOOL validCoordinate(
1035 LONG *coor,
1036 SAFEARRAY *psa)
1037{
1038 INT iter=0;
1039 LONG lUBound;
1040 LONG lLBound;
1041 HRESULT hRes;
1042
1043 if (!psa->cDims) return FALSE;
1044 for(; iter<psa->cDims; iter++) {
1045 TRACE("coor[%d]=%ld\n", iter, coor[iter]);
1046 if((hRes = SafeArrayGetLBound(psa, (iter+1), &lLBound)) != S_OK)
1047 return FALSE;
1048 if((hRes = SafeArrayGetUBound(psa, (iter+1), &lUBound)) != S_OK)
1049 return FALSE;
1050
1051 if(lLBound > lUBound)
1052 return FALSE;
1053
1054 if((coor[iter] < lLBound) || (coor[iter] > lUBound))
1055 return FALSE;
1056 }
1057 return TRUE;
1058}
1059
1060/************************************************************************
1061 * Method used to calculate the number of cells of the SA
1062 */
1063static ULONG getArraySize(
1064 SAFEARRAY *psa)
1065{
1066 USHORT cCount;
1067 ULONG ulWholeArraySize = 1;
1068
1069 for(cCount=0; cCount < psa->cDims; cCount++) /* foreach dimensions... */
1070 ulWholeArraySize *= psa->rgsabound[cCount].cElements;
1071
1072 return ulWholeArraySize;
1073}
1074
1075
1076/************************************************************************
1077 * Method used to handle data space dupplication for Copy32 and CopyData32
1078 */
1079static HRESULT duplicateData(
1080 SAFEARRAY *psa,
1081 SAFEARRAY **ppsaOut)
1082{
1083 ULONG ulWholeArraySize; /* size of the thing */
1084 LONG lDelta;
1085
1086 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
1087
1088 SafeArrayLock(*ppsaOut);
1089
1090 if( isPointer(psa->fFeatures) ) { /* If datatype is object increment
1091 object's reference count */
1092 IUnknown *punk;
1093
1094 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1095 punk = *(IUnknown**)((char *) psa->pvData+(lDelta * psa->cbElements));
1096
1097 if( punk != NULL)
1098 IUnknown_AddRef(punk);
1099 }
1100
1101 /* Copy the source array data into target array */
1102 memcpy((*ppsaOut)->pvData, psa->pvData,
1103 ulWholeArraySize*psa->cbElements);
1104
1105 }
1106 else if( psa->fFeatures & FADF_BSTR ) { /* if datatype is BSTR allocate
1107 the BSTR in the new array */
1108 BSTR pbstrReAllocStr = NULL;
1109
1110 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1111 if(( pbstrReAllocStr = SYSDUPSTRING(
1112 *(BSTR*)((char *) psa->pvData+(lDelta * psa->cbElements)))) == NULL) {
1113
1114 SafeArrayUnlock(*ppsaOut);
1115 return E_OUTOFMEMORY;
1116 }
1117
1118 *((BSTR*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements))) =
1119 pbstrReAllocStr;
1120 }
1121
1122 }
1123 else if( psa->fFeatures & FADF_VARIANT ) {
1124
1125 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1126 VariantCopy((VARIANT*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements)),
1127 (VARIANT*)((char *) psa->pvData+(lDelta * psa->cbElements)));
1128 }
1129
1130 }
1131 else { /* Simply copy the source array data into target array */
1132
1133 memcpy((*ppsaOut)->pvData, psa->pvData,
1134 ulWholeArraySize*psa->cbElements);
1135 }
1136
1137 SafeArrayUnlock(*ppsaOut);
1138
1139 return S_OK;
1140}
1141
1142
1143/************************************************************************
1144 * SafeArrayGetVarType (OLEAUT32.77)
1145 * Returns the VARTYPE stored in the given safearray
1146 */
1147HRESULT WINAPI SafeArrayGetVarType(
1148 SAFEARRAY* psa,
1149 VARTYPE* pvt)
1150{
1151 HRESULT hr = E_INVALIDARG;
1152 VARTYPE vt = VT_EMPTY;
1153
1154 /* const short VARTYPE_OFFSET = -4; */
1155
1156 if (psa->fFeatures & FADF_HAVEVARTYPE)
1157 {
1158 /* VT tag @ negative offset 4 in the array descriptor */
1159 FIXME("Returning VT_BSTR instead of VT_...\n");
1160 vt = VT_BSTR;
1161 }
1162 else if (psa->fFeatures & FADF_RECORD)
1163 {
1164 vt = VT_RECORD;
1165 }
1166 else if (psa->fFeatures & FADF_BSTR)
1167 {
1168 vt = VT_BSTR;
1169 }
1170 else if (psa->fFeatures & FADF_UNKNOWN)
1171 {
1172 vt = VT_UNKNOWN;
1173 }
1174 else if (psa->fFeatures & FADF_DISPATCH)
1175 {
1176 vt = VT_DISPATCH;
1177 }
1178 else if (psa->fFeatures & FADF_VARIANT)
1179 {
1180 vt = VT_VARIANT;
1181 }
1182
1183 if (vt != VT_EMPTY)
1184 {
1185 *pvt = vt;
1186 hr = S_OK;
1187 }
1188
1189 TRACE("HRESULT = %08lx\n", hr);
1190 return hr;
1191}
Note: See TracBrowser for help on using the repository browser.