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

Last change on this file since 10631 was 10631, checked in by cinc, 21 years ago

Added stubs for

SafeArrayGetRecordInfo()
SafeArraySetRecordInfo()
SafeArrayCreateEx()

Added from Wine:

SafeArraySetIID()
SafeArrayGetIID()

File size: 38.3 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 * SafeArrayCreateEx (OLEAUT32.42)
128*
129 * Create a new SafeArray.
130 *
131 * PARAMS
132 * vt [I] Type to store in the safe array
133 * cDims [I] Number of array dimensions
134 * rgsabound [I] Bounds of the array dimensions
135 * pvExtra [I] Extra data
136 *
137 * RETURNS
138 * Success: A pointer to a new array object.
139 * Failure: NULL, if any parameter is invalid or memory allocation fails.
140 *
141 * NOTES
142 * See SafeArray.
143 */
144SAFEARRAY* WINAPI SafeArrayCreateEx(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound, LPVOID pvExtra)
145#ifdef __WIN32OS2__
146{
147 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
148 return E_NOTIMPL;
149}
150#else
151{
152 ULONG ulSize = 0;
153 IRecordInfo* iRecInfo = (IRecordInfo*)pvExtra;
154 SAFEARRAY* psa;
155
156 TRACE("(%d->%s,%d,%p,%p)\n", vt, debugstr_vt(vt), cDims, rgsabound, pvExtra);
157
158 if (vt == VT_RECORD)
159 {
160 if (!iRecInfo)
161 return NULL;
162 IRecordInfo_GetSize(iRecInfo, &ulSize);
163 }
164 psa = SAFEARRAY_Create(vt, cDims, rgsabound, ulSize);
165
166 if (pvExtra)
167 {
168 switch(vt)
169 {
170 case VT_RECORD:
171 SafeArraySetRecordInfo(psa, pvExtra);
172 break;
173 case VT_UNKNOWN:
174 case VT_DISPATCH:
175 SafeArraySetIID(psa, pvExtra);
176 break;
177 }
178 }
179 return psa;
180}
181#endif
182
183/***********************************************************************
184 * SafeArraySetIID (OLEAUT32.57)
185*
186 * Set the IID for a SafeArray.
187 *
188 * PARAMS
189 * psa [I] Array to set the IID from
190 * guid [I] IID
191 *
192 * RETURNS
193 * Success: S_OK. The IID is stored with the array
194 * Failure: An HRESULT error code indicating the error.
195 *
196 * NOTES
197 * See SafeArray.
198 */
199HRESULT WINAPI SafeArraySetIID(SAFEARRAY *psa, REFGUID guid)
200{
201 GUID* dest = (GUID*)psa;
202
203 TRACE("(%p,%s)\n", psa, debugstr_guid(guid));
204
205 if (!psa || !guid || !(psa->fFeatures & FADF_HAVEIID))
206 return E_INVALIDARG;
207
208 dest[-1] = *guid;
209 return S_OK;
210}
211
212
213/***********************************************************************
214 * SafeArrayGetIID (OLEAUT32.67)
215 *
216 * Get the IID from a SafeArray.
217 *
218 * PARAMS
219 * psa [I] Array to get the ID from
220 * pGuid [O] Destination for the IID
221 *
222 * RETURNS
223 * Success: S_OK. pRinfo contains the IID, or NULL if there was none.
224 * Failure: An HRESULT error code indicating the error.
225 *
226 * NOTES
227 * See SafeArray.
228 */
229HRESULT WINAPI SafeArrayGetIID(SAFEARRAY *psa, GUID *pGuid)
230{
231 GUID* src = (GUID*)psa;
232
233 TRACE("(%p,%p)\n", psa, pGuid);
234
235 if (!psa || !pGuid || !(psa->fFeatures & FADF_HAVEIID))
236 return E_INVALIDARG;
237
238 *pGuid = src[-1];
239 return S_OK;
240}
241
242
243/***********************************************************************
244 * SafeArraySetRecordInfo (OLEAUT32.45)
245 */
246#ifdef __WIN32OS2__
247HRESULT WINAPI SafeArraySetRecordInfo(void* pFixMe, void* pFixMe2)
248#else
249HRESULT WINAPI SafeArraySetRecordInfo(SAFEARRAY* psa, IRecordInfo * psaboundNew)
250#endif
251{
252 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
253 return E_NOTIMPL;
254}
255
256
257/***********************************************************************
258 * SafeArrayGetRecordInfo (OLEAUT32.45)
259 */
260/* IRecordInfo helpers */
261#ifdef __WIN32OS2__
262HRESULT WINAPI SafeArrayGetRecordInfo(void* pFixMe, void** ppFixMe)
263#else
264HRESULT WINAPI SafeArrayGetRecordInfo(SAFEARRAY* psa,IRecordInfo** prinfo)
265#endif
266{
267 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
268 return E_NOTIMPL;
269}
270
271
272/*************************************************************************
273 * SafeArrayAllocDescriptor (OLEAUT32.36)
274 * Allocate the appropriate amount of memory for the SafeArray descriptor
275 */
276HRESULT WINAPI SafeArrayAllocDescriptor(
277 UINT cDims,
278 SAFEARRAY **ppsaOut)
279{
280 SAFEARRAYBOUND *sab;
281 LONG allocSize = 0;
282
283 /* SAFEARRAY + SAFEARRAYBOUND * (cDims -1) ( -1 because there is already one
284 ( in SAFEARRAY struct */
285 allocSize = sizeof(**ppsaOut) + (sizeof(*sab) * (cDims-1));
286
287 /* Allocate memory for SAFEARRAY struc */
288 if(( (*ppsaOut)=HeapAlloc(
289 GetProcessHeap(), HEAP_ZERO_MEMORY, allocSize)) == NULL){
290 return(E_UNEXPECTED);
291 }
292 TRACE("SafeArray: %lu bytes allocated for descriptor.\n", allocSize);
293
294 return(S_OK);
295}
296
297/*************************************************************************
298 * SafeArrayAllocDescriptorEx (OLEAUT32.41)
299 * Allocate the appropriate amount of memory for the SafeArray descriptor
300 *
301 * This is a minimal implementation just to get things moving.
302 *
303 * The MSDN documentation on this doesn't tell us much.
304 */
305HRESULT WINAPI SafeArrayAllocDescriptorEx(
306 VARTYPE vt,
307 UINT cDims,
308 SAFEARRAY **ppsaOut)
309{
310 if ( (vt >= LAST_VARTYPE) ||
311 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
312 return E_UNEXPECTED;
313
314 return SafeArrayAllocDescriptor (cDims, ppsaOut);
315}
316
317/*************************************************************************
318 * SafeArrayAllocData (OLEAUT32.37)
319 * Allocate the appropriate amount of data for the SafeArray data
320 */
321HRESULT WINAPI SafeArrayAllocData(
322 SAFEARRAY *psa)
323{
324 ULONG ulWholeArraySize; /* to store the size of the whole thing */
325
326 if(! validArg(psa))
327 return E_INVALIDARG;
328
329 ulWholeArraySize = getArraySize(psa);
330
331 /* Allocate memory for the data itself */
332 if((psa->pvData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
333 psa->cbElements*ulWholeArraySize)) == NULL)
334 return(E_UNEXPECTED);
335
336 TRACE("SafeArray: %lu bytes allocated for data at %p (%lu objects).\n",
337 psa->cbElements*ulWholeArraySize, psa->pvData, ulWholeArraySize);
338
339 return(S_OK);
340}
341
342/*************************************************************************
343 * SafeArrayCreate (OLEAUT32.15)
344 * Create a SafeArray object by encapsulating AllocDescriptor and AllocData
345 */
346SAFEARRAY* WINAPI SafeArrayCreate(
347 VARTYPE vt,
348 UINT cDims,
349 SAFEARRAYBOUND *rgsabound)
350{
351 SAFEARRAY *psa;
352 HRESULT hRes;
353 USHORT cDim;
354
355 /* Validate supported VARTYPE */
356 if ( (vt >= LAST_VARTYPE) ||
357 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
358 return NULL;
359
360 /* Allocate memory for the array descriptor */
361 if( FAILED( hRes = SafeArrayAllocDescriptor(cDims, &psa)))
362 return NULL;
363
364 /* setup data members... */
365 psa->cDims = cDims;
366 psa->fFeatures = getFeatures(vt);
367 psa->cLocks = 0;
368 psa->pvData = NULL;
369 psa->cbElements= VARTYPE_SIZE[vt];
370
371 /* Invert the bounds ... */
372 for(cDim=0; cDim < psa->cDims; cDim++) {
373 psa->rgsabound[cDim].cElements = rgsabound[psa->cDims-cDim-1].cElements;
374 psa->rgsabound[cDim].lLbound = rgsabound[psa->cDims-cDim-1].lLbound;
375 }
376
377 /* allocate memory for the data... */
378 if( FAILED( hRes = SafeArrayAllocData(psa))) {
379 SafeArrayDestroyDescriptor(psa);
380 ERR("() : Failed to allocate the Safe Array data\n");
381 return NULL;
382 }
383
384 return(psa);
385}
386
387/*************************************************************************
388 * SafeArrayDestroyDescriptor (OLEAUT32.38)
389 * Frees the memory associated with the descriptor.
390 */
391HRESULT WINAPI SafeArrayDestroyDescriptor(
392 SAFEARRAY *psa)
393{
394 /* Check for lockness before to free... */
395 if(psa->cLocks > 0)
396 return DISP_E_ARRAYISLOCKED;
397
398 /* The array is unlocked, then, deallocate memory */
399 if(HeapFree( GetProcessHeap(), 0, psa) == FALSE)
400 return E_UNEXPECTED;
401
402 return(S_OK);
403}
404
405
406/*************************************************************************
407 * SafeArrayLock (OLEAUT32.21)
408 * Increment the lock counter
409 *
410 * Doc says (MSDN Library ) that psa->pvData should be made available (!= NULL)
411 * only when psa->cLocks is > 0... I don't get it since pvData is allocated
412 * before the array is locked, therefore
413 */
414HRESULT WINAPI SafeArrayLock(
415 SAFEARRAY *psa)
416{
417 if(! validArg(psa))
418 return E_INVALIDARG;
419
420 psa->cLocks++;
421
422 return(S_OK);
423}
424
425/*************************************************************************
426 * SafeArrayUnlock (OLEAUT32.22)
427 * Decrement the lock counter
428 */
429HRESULT WINAPI SafeArrayUnlock(
430 SAFEARRAY *psa)
431{
432 if(! validArg(psa))
433 return E_INVALIDARG;
434
435 if (psa->cLocks > 0)
436 psa->cLocks--;
437
438 return(S_OK);
439}
440
441
442/*************************************************************************
443 * SafeArrayPutElement (OLEAUT32.26)
444 * Set the data at the given coordinate
445 */
446HRESULT WINAPI SafeArrayPutElement(
447 SAFEARRAY *psa,
448 LONG *rgIndices,
449 void *pv)
450{
451 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
452 the desired one... */
453 PVOID elementStorageAddress = NULL; /* Adress to store the data */
454
455 /* Validate the index given */
456 if(! validCoordinate(rgIndices, psa))
457 return DISP_E_BADINDEX;
458 if(! validArg(psa))
459 return E_INVALIDARG;
460
461 if( SafeArrayLock(psa) == S_OK) {
462
463 /* Figure out the number of items to skip */
464 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
465
466 /* Figure out the number of byte to skip ... */
467 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
468
469 if(isPointer(psa->fFeatures)) { /* increment ref count for this pointer */
470
471 *((PVOID*)elementStorageAddress) = *(PVOID*)pv;
472 IUnknown_AddRef( *(IUnknown**)pv);
473
474 } else {
475
476 if(psa->fFeatures == FADF_BSTR) { /* Create a new object */
477 BSTR pbstrReAllocStr = NULL;
478 if(pv &&
479 ((pbstrReAllocStr = SYSDUPSTRING( (OLECHAR*)pv )) == NULL)) {
480 SafeArrayUnlock(psa);
481 return E_OUTOFMEMORY;
482 } else
483 *((BSTR*)elementStorageAddress) = pbstrReAllocStr;
484 }
485 else if(psa->fFeatures == FADF_VARIANT) {
486 HRESULT hr = VariantCopy(elementStorageAddress, pv);
487 if (FAILED(hr)) {
488 SafeArrayUnlock(psa);
489 return hr;
490 }
491 }
492 else /* duplicate the memory */
493 memcpy(elementStorageAddress, pv, SafeArrayGetElemsize(psa) );
494 }
495
496 } else {
497 ERR("SafeArray: Cannot lock array....\n");
498 return E_UNEXPECTED; /* UNDOC error condition */
499 }
500
501 TRACE("SafeArray: item put at adress %p.\n",elementStorageAddress);
502 return SafeArrayUnlock(psa);
503}
504
505
506/*************************************************************************
507 * SafeArrayGetElement (OLEAUT32.25)
508 * Return the data element corresponding the the given coordinate
509 */
510HRESULT WINAPI SafeArrayGetElement(
511 SAFEARRAY *psa,
512 LONG *rgIndices,
513 void *pv)
514{
515 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
516 the desired one... */
517 PVOID elementStorageAddress = NULL; /* Adress to store the data */
518
519 if(! validArg(psa))
520 return E_INVALIDARG;
521
522 if(! validCoordinate(rgIndices, psa)) /* Validate the index given */
523 return(DISP_E_BADINDEX);
524
525 if( SafeArrayLock(psa) == S_OK) {
526
527 /* Figure out the number of items to skip */
528 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
529
530 /* Figure out the number of byte to skip ... */
531 elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
532
533 if( psa->fFeatures == FADF_BSTR) { /* reallocate the obj */
534 BSTR pbstrStoredStr = *(OLECHAR**)elementStorageAddress;
535 BSTR pbstrReturnedStr = NULL;
536 if( pbstrStoredStr &&
537 ((pbstrReturnedStr = SYSDUPSTRING( pbstrStoredStr )) == NULL) ) {
538 SafeArrayUnlock(psa);
539 return E_OUTOFMEMORY;
540 } else
541 *((BSTR*)pv) = pbstrReturnedStr;
542 }
543 else if( psa->fFeatures == FADF_VARIANT) {
544 HRESULT hr;
545 VariantInit(pv);
546 hr = VariantCopy(pv, elementStorageAddress);
547 if (FAILED(hr)) {
548 SafeArrayUnlock(psa);
549 return hr;
550 }
551 }
552 else if( isPointer(psa->fFeatures) ) /* simply copy the pointer */
553 *(PVOID*)pv = *((PVOID*)elementStorageAddress);
554 else /* copy the bytes */
555 memcpy(pv, elementStorageAddress, psa->cbElements );
556
557 } else {
558 ERR("SafeArray: Cannot lock array....\n");
559 return E_UNEXPECTED; /* UNDOC error condition */
560 }
561
562 return( SafeArrayUnlock(psa) );
563}
564
565/*************************************************************************
566 * SafeArrayGetUBound (OLEAUT32.19)
567 * return the UP bound for a given array dimension
568 */
569HRESULT WINAPI SafeArrayGetUBound(
570 SAFEARRAY *psa,
571 UINT nDim,
572 LONG *plUbound)
573{
574 if(! validArg(psa))
575 return E_INVALIDARG;
576
577 if(nDim > psa->cDims)
578 return DISP_E_BADINDEX;
579
580 if(0 == nDim)
581 return DISP_E_BADINDEX;
582
583 *plUbound = psa->rgsabound[nDim-1].lLbound +
584 psa->rgsabound[nDim-1].cElements - 1;
585
586 return S_OK;
587}
588
589/*************************************************************************
590 * SafeArrayGetLBound (OLEAUT32.20)
591 * Return the LO bound for a given array dimension
592 */
593HRESULT WINAPI SafeArrayGetLBound(
594 SAFEARRAY *psa,
595 UINT nDim,
596 LONG *plLbound)
597{
598 if(! validArg(psa))
599 return E_INVALIDARG;
600
601 if(nDim > psa->cDims)
602 return DISP_E_BADINDEX;
603
604 if(0 == nDim)
605 return DISP_E_BADINDEX;
606
607 *plLbound = psa->rgsabound[nDim-1].lLbound;
608 return S_OK;
609}
610
611/*************************************************************************
612 * SafeArrayGetDim (OLEAUT32.17)
613 * returns the number of dimension in the array
614 */
615UINT WINAPI SafeArrayGetDim(
616 SAFEARRAY * psa)
617{
618 /*
619 * A quick test in Windows shows that the behavior here for an invalid
620 * pointer is to return 0.
621 */
622 if(! validArg(psa))
623 return 0;
624
625 return psa->cDims;
626}
627
628/*************************************************************************
629 * SafeArrayGetElemsize (OLEAUT32.18)
630 * Return the size of the element in the array
631 */
632UINT WINAPI SafeArrayGetElemsize(
633 SAFEARRAY * psa)
634{
635 /*
636 * A quick test in Windows shows that the behavior here for an invalid
637 * pointer is to return 0.
638 */
639 if(! validArg(psa))
640 return 0;
641
642 return psa->cbElements;
643}
644
645/*************************************************************************
646 * SafeArrayAccessData (OLEAUT32.23)
647 * increment the access count and return the data
648 */
649HRESULT WINAPI SafeArrayAccessData(
650 SAFEARRAY *psa,
651 void **ppvData)
652{
653 HRESULT hRes;
654
655 if(! validArg(psa))
656 return E_INVALIDARG;
657
658 hRes = SafeArrayLock(psa);
659
660 switch (hRes) {
661 case S_OK:
662 (*ppvData) = psa->pvData;
663 break;
664 case E_INVALIDARG:
665 (*ppvData) = NULL;
666 return E_INVALIDARG;
667 }
668
669 return S_OK;
670}
671
672
673/*************************************************************************
674 * SafeArrayUnaccessData (OLEAUT32.24)
675 * Decrement the access count
676 */
677HRESULT WINAPI SafeArrayUnaccessData(
678 SAFEARRAY * psa)
679{
680 if(! validArg(psa))
681 return E_INVALIDARG;
682
683 return(SafeArrayUnlock(psa));
684}
685
686/************************************************************************
687 * SafeArrayPtrOfIndex (OLEAUT32.148)
688 * Return a pointer to the element at rgIndices
689 */
690HRESULT WINAPI SafeArrayPtrOfIndex(
691 SAFEARRAY *psa,
692 LONG *rgIndices,
693 void **ppvData)
694{
695 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
696 the desired one... */
697
698 if(! validArg(psa))
699 return E_INVALIDARG;
700
701 if(! validCoordinate(rgIndices, psa))
702 return DISP_E_BADINDEX;
703
704 /* Although it is dangerous to do this without having a lock, it is not
705 * illegal. Microsoft do warn of the danger.
706 */
707
708 /* Figure out the number of items to skip */
709 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
710
711 *ppvData = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
712
713 return S_OK;
714}
715
716/************************************************************************
717 * SafeArrayDestroyData (OLEAUT32.39)
718 * Frees the memory data bloc
719 */
720HRESULT WINAPI SafeArrayDestroyData(
721 SAFEARRAY *psa)
722{
723 HRESULT hRes;
724 ULONG ulWholeArraySize; /* count spot in array */
725 ULONG ulDataIter; /* to iterate the data space */
726
727 if(! validArg(psa))
728 return E_INVALIDARG;
729
730 if(psa->cLocks > 0)
731 return DISP_E_ARRAYISLOCKED;
732
733 ulWholeArraySize = getArraySize(psa);
734
735 if(isPointer(psa->fFeatures)) { /* release the pointers */
736 IUnknown *punk;
737
738 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
739 punk = *(IUnknown**)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
740
741 if( punk != NULL)
742 IUnknown_Release(punk);
743 }
744
745 }
746 else if(psa->fFeatures & FADF_BSTR) { /* deallocate the obj */
747 BSTR bstr;
748
749 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
750 bstr = *(BSTR*)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
751
752 if( bstr != NULL)
753 SysFreeString( bstr );
754 }
755 }
756 else if(psa->fFeatures & FADF_VARIANT) { /* deallocate the obj */
757
758 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
759 VariantClear((VARIANT*)((char *) psa->pvData+(ulDataIter*(psa->cbElements))));
760 }
761 }
762
763 /* check if this array is a Vector, in which case do not free the data
764 block since it has been allocated by AllocDescriptor and therefore
765 deserve to be freed by DestroyDescriptor */
766 if(!(psa->fFeatures & FADF_CREATEVECTOR)) { /* Set when we do CreateVector */
767
768 /* free the whole chunk */
769 if((hRes = HeapFree( GetProcessHeap(), 0, psa->pvData)) == 0) /*falied*/
770 return E_UNEXPECTED; /* UNDOC error condition */
771
772 psa->pvData = NULL;
773 }
774
775 return S_OK;
776}
777
778/************************************************************************
779 * SafeArrayCopyData (OLEAUT32.412)
780 * Copy the psaSource's data block into psaTarget if dimension and size
781 * permits it.
782 */
783HRESULT WINAPI SafeArrayCopyData(
784 SAFEARRAY *psaSource,
785 SAFEARRAY **psaTarget)
786{
787 USHORT cDimCount; /* looper */
788 LONG lDelta; /* looper */
789 IUnknown *punk;
790 ULONG ulWholeArraySize; /* Number of item in SA */
791 BSTR bstr;
792
793 if(! (validArg(psaSource) && validArg(*psaTarget)) )
794 return E_INVALIDARG;
795
796 if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(*psaTarget))
797 return E_INVALIDARG;
798
799 ulWholeArraySize = getArraySize(psaSource);
800
801 /* The two arrays boundaries must be of same lenght */
802 for(cDimCount=0;cDimCount < psaSource->cDims; cDimCount++)
803 if( psaSource->rgsabound[cDimCount].cElements !=
804 (*psaTarget)->rgsabound[cDimCount].cElements)
805 return E_INVALIDARG;
806
807 if( isPointer((*psaTarget)->fFeatures) ) { /* the target contains ptr
808 that must be released */
809 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
810 punk = *(IUnknown**)
811 ((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
812
813 if( punk != NULL)
814 IUnknown_Release(punk);
815 }
816
817 }
818 else if( (*psaTarget)->fFeatures & FADF_BSTR) { /* the target contain BSTR
819 that must be freed */
820 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
821 bstr =
822 *(BSTR*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
823
824 if( bstr != NULL)
825 SysFreeString( bstr );
826 }
827 }
828 else if( (*psaTarget)->fFeatures & FADF_VARIANT) {
829
830 for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
831 VariantClear((VARIANT*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements)));
832 }
833 }
834
835 return duplicateData(psaSource, psaTarget);
836}
837
838/************************************************************************
839 * SafeArrayDestroy (OLEAUT32.16)
840 * Deallocates all memory reserved for the SafeArray
841 */
842HRESULT WINAPI SafeArrayDestroy(
843 SAFEARRAY * psa)
844{
845 HRESULT hRes;
846
847 if(! validArg(psa))
848 return E_INVALIDARG;
849
850 if(psa->cLocks > 0)
851 return DISP_E_ARRAYISLOCKED;
852
853 if((hRes = SafeArrayDestroyData( psa )) == S_OK)
854 if((hRes = SafeArrayDestroyDescriptor( psa )) == S_OK)
855 return S_OK;
856
857 return E_UNEXPECTED; /* UNDOC error condition */
858}
859
860/************************************************************************
861 * SafeArrayCopy (OLEAUT32.27)
862 * Make a dupplicate of a SafeArray
863 */
864HRESULT WINAPI SafeArrayCopy(
865 SAFEARRAY *psa,
866 SAFEARRAY **ppsaOut)
867{
868 HRESULT hRes;
869 DWORD dAllocSize;
870 ULONG ulWholeArraySize; /* size of the thing */
871
872 if(! validArg(psa))
873 return E_INVALIDARG;
874
875 if((hRes=SafeArrayAllocDescriptor(psa->cDims, ppsaOut)) == S_OK){
876
877 /* Duplicate the SAFEARRAY struc */
878 memcpy(*ppsaOut, psa,
879 sizeof(*psa)+(sizeof(*(psa->rgsabound))*(psa->cDims-1)));
880
881 (*ppsaOut)->pvData = NULL; /* do not point to the same data area */
882
883 /* make sure the new safe array doesn't have the FADF_CREATEVECTOR flag,
884 because the data has not been allocated with the descriptor. */
885 (*ppsaOut)->fFeatures &= ~FADF_CREATEVECTOR;
886
887 /* Get the allocated memory size for source and allocate it for target */
888 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
889 dAllocSize = ulWholeArraySize*psa->cbElements;
890
891 (*ppsaOut)->pvData =
892 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dAllocSize);
893 if( (*ppsaOut)->pvData != NULL) { /* HeapAlloc succeed */
894
895 if( (hRes=duplicateData(psa, ppsaOut)) != S_OK) { /* E_OUTOFMEMORY */
896 HeapFree(GetProcessHeap(), 0, (*ppsaOut)->pvData);
897 (*ppsaOut)->pvData = NULL;
898 SafeArrayDestroyDescriptor(*ppsaOut);
899 return hRes;
900 }
901
902 } else { /* failed to allocate or dupplicate... */
903 SafeArrayDestroyDescriptor(*ppsaOut);
904 return E_UNEXPECTED; /* UNDOC error condition */
905 }
906 } else { /* failed to allocate mem for descriptor */
907 return E_OUTOFMEMORY; /* UNDOC error condiftion */
908 }
909
910 return S_OK;
911}
912
913/************************************************************************
914 * SafeArrayCreateVector (OLEAUT32.411)
915 * Creates a one dimension safearray where the data is next to the
916 * SAFEARRAY structure.
917 */
918SAFEARRAY* WINAPI SafeArrayCreateVector(
919 VARTYPE vt,
920 LONG lLbound,
921 ULONG cElements)
922{
923 SAFEARRAY *psa;
924
925 /* Validate supported VARTYPE */
926 if ( (vt >= LAST_VARTYPE) ||
927 ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
928 return NULL;
929
930 /* Allocate memory for the array descriptor and data contiguously */
931 if( FAILED( psa = HeapAlloc( GetProcessHeap(),
932 HEAP_ZERO_MEMORY,
933 (sizeof(*psa) + (VARTYPE_SIZE[vt] * cElements))))) {
934 return NULL;
935 }
936
937 /* setup data members... */
938 psa->cDims = 1; /* always and forever */
939 psa->fFeatures = getFeatures(vt) | FADF_CREATEVECTOR; /* undocumented flag used by Microsoft */
940 psa->cLocks = 0;
941 psa->pvData = (BYTE*)psa + sizeof(*psa);
942 psa->cbElements = VARTYPE_SIZE[vt];
943
944 psa->rgsabound[0].cElements = cElements;
945 psa->rgsabound[0].lLbound = lLbound;
946
947 return(psa);
948}
949
950/************************************************************************
951 * SafeArrayRedim (OLEAUT32.40)
952 * Changes the caracteristics of the last dimension of the SafeArray
953 */
954HRESULT WINAPI SafeArrayRedim(
955 SAFEARRAY *psa,
956 SAFEARRAYBOUND *psaboundNew)
957{
958 LONG lDelta; /* hold difference in size */
959 USHORT cDims=1; /* dims counter */
960
961 if( !validArg(psa) )
962 return E_INVALIDARG;
963
964 if( psa->cLocks > 0 )
965 return DISP_E_ARRAYISLOCKED;
966
967 if( psa->fFeatures & FADF_FIXEDSIZE )
968 return E_INVALIDARG;
969
970 if( SafeArrayLock(psa)==E_UNEXPECTED )
971 return E_UNEXPECTED;/* UNDOC error condition */
972
973 /* find the delta in number of array spot to apply to the new array */
974 lDelta = psaboundNew->cElements - psa->rgsabound[0].cElements;
975 for(; cDims < psa->cDims; cDims++)
976 /* delta in number of spot implied by modifying the last dimension */
977 lDelta *= psa->rgsabound[cDims].cElements;
978
979 TRACE("elements=%ld, Lbound=%ld (delta=%ld)\n", psaboundNew->cElements, psaboundNew->lLbound, lDelta);
980
981 if (lDelta == 0) { ;/* same size, maybe a change of lLbound, just set it */
982
983 } else /* need to enlarge (lDelta +) reduce (lDelta -) */
984 if(! resizeSafeArray(psa, lDelta))
985 return E_UNEXPECTED; /* UNDOC error condition */
986
987 /* the only modifyable dimension sits in [0] as the dimensions were reversed
988 at array creation time... */
989 psa->rgsabound[0].cElements = psaboundNew->cElements;
990 psa->rgsabound[0].lLbound = psaboundNew->lLbound;
991
992 return SafeArrayUnlock(psa);
993}
994
995/************************************************************************
996 * NOT WINDOWS API - SafeArray* Utility functions
997 ************************************************************************/
998
999/************************************************************************
1000 * Used to validate the SAFEARRAY type of arg
1001 */
1002static BOOL validArg(
1003 SAFEARRAY *psa)
1004{
1005 SAFEARRAYBOUND *sab;
1006 LONG psaSize = 0;
1007 LONG descSize = 0;
1008 LONG fullSize = 0;
1009
1010 /*
1011 * Let's check for the null pointer just in case.
1012 */
1013 if (psa == NULL)
1014 return FALSE;
1015
1016 /* Check whether the size of the chunk makes sense... That's the only thing
1017 I can think of now... */
1018
1019 psaSize = HeapSize(GetProcessHeap(), 0, psa);
1020 if (psaSize == -1)
1021 /* uh, foreign heap. Better don't mess with it ! */
1022 return TRUE;
1023
1024 /* size of the descriptor when the SA is not created with CreateVector */
1025 descSize = sizeof(*psa) + (sizeof(*sab) * (psa->cDims-1));
1026
1027 /* size of the descriptor + data when created with CreateVector */
1028 fullSize = sizeof(*psa) + (psa->cbElements * psa->rgsabound[0].cElements);
1029
1030 return((psaSize >= descSize) || (psaSize >= fullSize));
1031}
1032
1033/************************************************************************
1034 * Used to reallocate memory
1035 */
1036static BOOL resizeSafeArray(
1037 SAFEARRAY *psa,
1038 LONG lDelta)
1039{
1040 ULONG ulWholeArraySize; /* use as multiplicator */
1041 PVOID pvNewBlock = NULL;
1042 IUnknown *punk;
1043 BSTR bstr;
1044
1045 ulWholeArraySize = getArraySize(psa);
1046
1047 if(lDelta < 0) { /* array needs to be shorthen */
1048 if( isPointer(psa->fFeatures)) /* ptr that need to be released */
1049 for(;lDelta < 0; lDelta++) {
1050 punk = *(IUnknown**)
1051 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
1052
1053 if( punk != NULL )
1054 IUnknown_Release(punk);
1055 }
1056
1057 else if(psa->fFeatures & FADF_BSTR) /* BSTR that need to be freed */
1058 for(;lDelta < 0; lDelta++) {
1059 bstr = *(BSTR*)
1060 ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
1061
1062 if( bstr != NULL )
1063 SysFreeString( bstr );
1064 }
1065 else if(psa->fFeatures & FADF_VARIANT)
1066 for(;lDelta < 0; lDelta++) {
1067 VariantClear((VARIANT*)((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements)));
1068 }
1069 }
1070
1071 if (!(psa->fFeatures & FADF_CREATEVECTOR))
1072 {
1073 /* Ok now, if we are enlarging the array, we *MUST* move the whole block
1074 pointed to by pvData. If we are shorthening the array, this move is
1075 optional but we do it anyway becuase the benefit is that we are
1076 releasing to the system the unused memory */
1077
1078 if((pvNewBlock = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, psa->pvData,
1079 (ulWholeArraySize + lDelta) * psa->cbElements)) == NULL)
1080 return FALSE; /* TODO If we get here it means:
1081 SHRINK situation : we've deleted the undesired
1082 data and did not release the memory
1083 GROWING situation: we've been unable to grow the array
1084 */
1085 }
1086 else
1087 {
1088 /* Allocate a new block, because the previous data has been allocated with
1089 the descriptor in SafeArrayCreateVector function. */
1090
1091 if((pvNewBlock = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1092 ulWholeArraySize * psa->cbElements)) == NULL)
1093 return FALSE;
1094
1095 psa->fFeatures &= ~FADF_CREATEVECTOR;
1096 }
1097 /* reassign to the new block of data */
1098 psa->pvData = pvNewBlock;
1099 return TRUE;
1100}
1101
1102/************************************************************************
1103 * Used to set the fFeatures data member of the SAFEARRAY structure.
1104 */
1105static INT getFeatures(
1106 VARTYPE vt)
1107{
1108 switch(vt) {
1109 case VT_BSTR: return FADF_BSTR;
1110 case VT_UNKNOWN: return FADF_UNKNOWN;
1111 case VT_DISPATCH: return FADF_DISPATCH;
1112 case VT_VARIANT: return FADF_VARIANT;
1113 }
1114 return 0;
1115}
1116
1117/************************************************************************
1118 * Used to figure out if the fFeatures data member of the SAFEARRAY
1119 * structure contain any information about the type of data stored...
1120 */
1121static BOOL isPointer(
1122 USHORT feature)
1123{
1124 switch(feature) {
1125 case FADF_UNKNOWN: return TRUE; /* those are pointers */
1126 case FADF_DISPATCH: return TRUE;
1127 }
1128 return FALSE;
1129}
1130
1131/************************************************************************
1132 * Used to calculate the displacement when accessing or modifying
1133 * safearray data set.
1134 *
1135 * Parameters: - LONG *coor is the desired location in the multidimension
1136 * table. Ex for a 3 dim table: coor[] = {1,2,3};
1137 * - ULONG *mat is the format of the table. Ex for a 3 dim
1138 * table mat[] = {4,4,4};
1139 * - USHORT dim is the number of dimension of the SafeArray
1140 */
1141static ULONG calcDisplacement(
1142 LONG *coor,
1143 SAFEARRAYBOUND *mat,
1144 LONG dim)
1145{
1146 ULONG res = 0;
1147 LONG iterDim;
1148
1149 for(iterDim=0; iterDim<dim; iterDim++)
1150 /* the -mat[dim] bring coor[dim] relative to 0 for calculation */
1151 res += ((coor[iterDim]-mat[iterDim].lLbound) *
1152 endOfDim(coor, mat, iterDim+1, dim));
1153
1154 TRACE("SafeArray: calculated displacement is %lu.\n", res);
1155 return(res);
1156}
1157
1158/************************************************************************
1159 * Recursivity agent for calcDisplacement method. Used within Put and
1160 * Get methods.
1161 */
1162static INT endOfDim(
1163 LONG *coor,
1164 SAFEARRAYBOUND *mat,
1165 LONG dim,
1166 LONG realDim)
1167{
1168 if(dim==realDim)
1169 return 1;
1170 else
1171 return (endOfDim(coor, mat, dim+1, realDim) * mat[dim].cElements);
1172}
1173
1174
1175/************************************************************************
1176 * Method used to validate the coordinate received in Put and Get
1177 * methods.
1178 */
1179static BOOL validCoordinate(
1180 LONG *coor,
1181 SAFEARRAY *psa)
1182{
1183 INT iter=0;
1184 LONG lUBound;
1185 LONG lLBound;
1186 HRESULT hRes;
1187
1188 if (!psa->cDims) return FALSE;
1189 for(; iter<psa->cDims; iter++) {
1190 TRACE("coor[%d]=%ld\n", iter, coor[iter]);
1191 if((hRes = SafeArrayGetLBound(psa, (iter+1), &lLBound)) != S_OK)
1192 return FALSE;
1193 if((hRes = SafeArrayGetUBound(psa, (iter+1), &lUBound)) != S_OK)
1194 return FALSE;
1195
1196 if(lLBound > lUBound)
1197 return FALSE;
1198
1199 if((coor[iter] < lLBound) || (coor[iter] > lUBound))
1200 return FALSE;
1201 }
1202 return TRUE;
1203}
1204
1205/************************************************************************
1206 * Method used to calculate the number of cells of the SA
1207 */
1208static ULONG getArraySize(
1209 SAFEARRAY *psa)
1210{
1211 USHORT cCount;
1212 ULONG ulWholeArraySize = 1;
1213
1214 for(cCount=0; cCount < psa->cDims; cCount++) /* foreach dimensions... */
1215 ulWholeArraySize *= psa->rgsabound[cCount].cElements;
1216
1217 return ulWholeArraySize;
1218}
1219
1220
1221/************************************************************************
1222 * Method used to handle data space dupplication for Copy32 and CopyData32
1223 */
1224static HRESULT duplicateData(
1225 SAFEARRAY *psa,
1226 SAFEARRAY **ppsaOut)
1227{
1228 ULONG ulWholeArraySize; /* size of the thing */
1229 LONG lDelta;
1230
1231 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
1232
1233 SafeArrayLock(*ppsaOut);
1234
1235 if( isPointer(psa->fFeatures) ) { /* If datatype is object increment
1236 object's reference count */
1237 IUnknown *punk;
1238
1239 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1240 punk = *(IUnknown**)((char *) psa->pvData+(lDelta * psa->cbElements));
1241
1242 if( punk != NULL)
1243 IUnknown_AddRef(punk);
1244 }
1245
1246 /* Copy the source array data into target array */
1247 memcpy((*ppsaOut)->pvData, psa->pvData,
1248 ulWholeArraySize*psa->cbElements);
1249
1250 }
1251 else if( psa->fFeatures & FADF_BSTR ) { /* if datatype is BSTR allocate
1252 the BSTR in the new array */
1253 BSTR pbstrReAllocStr = NULL;
1254
1255 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1256 if(( pbstrReAllocStr = SYSDUPSTRING(
1257 *(BSTR*)((char *) psa->pvData+(lDelta * psa->cbElements)))) == NULL) {
1258
1259 SafeArrayUnlock(*ppsaOut);
1260 return E_OUTOFMEMORY;
1261 }
1262
1263 *((BSTR*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements))) =
1264 pbstrReAllocStr;
1265 }
1266
1267 }
1268 else if( psa->fFeatures & FADF_VARIANT ) {
1269
1270 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1271 VariantCopy((VARIANT*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements)),
1272 (VARIANT*)((char *) psa->pvData+(lDelta * psa->cbElements)));
1273 }
1274
1275 }
1276 else { /* Simply copy the source array data into target array */
1277
1278 memcpy((*ppsaOut)->pvData, psa->pvData,
1279 ulWholeArraySize*psa->cbElements);
1280 }
1281
1282 SafeArrayUnlock(*ppsaOut);
1283
1284 return S_OK;
1285}
1286
1287
1288/************************************************************************
1289 * SafeArrayGetVartype (OLEAUT32.77)
1290 * Returns the VARTYPE stored in the given safearray
1291 */
1292HRESULT WINAPI SafeArrayGetVartype(
1293 SAFEARRAY* psa,
1294 VARTYPE* pvt)
1295{
1296 HRESULT hr = E_INVALIDARG;
1297 VARTYPE vt = VT_EMPTY;
1298
1299 /* const short VARTYPE_OFFSET = -4; */
1300
1301 if (psa->fFeatures & FADF_HAVEVARTYPE)
1302 {
1303 /* VT tag @ negative offset 4 in the array descriptor */
1304 FIXME("Returning VT_BSTR instead of VT_...\n");
1305 vt = VT_BSTR;
1306 }
1307 else if (psa->fFeatures & FADF_RECORD)
1308 {
1309 vt = VT_RECORD;
1310 }
1311 else if (psa->fFeatures & FADF_BSTR)
1312 {
1313 vt = VT_BSTR;
1314 }
1315 else if (psa->fFeatures & FADF_UNKNOWN)
1316 {
1317 vt = VT_UNKNOWN;
1318 }
1319 else if (psa->fFeatures & FADF_DISPATCH)
1320 {
1321 vt = VT_DISPATCH;
1322 }
1323 else if (psa->fFeatures & FADF_VARIANT)
1324 {
1325 vt = VT_VARIANT;
1326 }
1327
1328 if (vt != VT_EMPTY)
1329 {
1330 *pvt = vt;
1331 hr = S_OK;
1332 }
1333
1334 TRACE("HRESULT = %08lx\n", hr);
1335 return hr;
1336}
Note: See TracBrowser for help on using the repository browser.