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

Last change on this file since 6944 was 6944, checked in by sandervl, 24 years ago

wine update

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