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

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

Created (WINE Port of OLEAUT32)

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