source: trunk/src/oleaut32/safearray.cpp@ 631

Last change on this file since 631 was 631, checked in by sandervl, 26 years ago

Created (WINE Port of OLEAUT32)

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