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

Last change on this file since 6648 was 6648, checked in by bird, 24 years ago

Added $Id:$ keyword.

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