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

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

update

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