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

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

Wine 20020215 resync + added extended logging

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