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

Last change on this file since 4837 was 4837, checked in by sandervl, 25 years ago

merged with Wine 12-22-2000

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