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

Last change on this file since 10367 was 9400, checked in by sandervl, 23 years ago

Wine resync

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