f3f4c5a6d083b890e2d53c895b0a492072cbc29d
1 /*************************************************************************
2 * OLE Automation - SafeArray
4 * This file contains the implementation of the SafeArray functions.
6 * Copyright 1999 Sylvain St-Germain
7 * Copyright 2002-2003 Marcus Meissner
8 * Copyright 2003 Jon Griffiths
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 /* Memory Layout of a SafeArray:
26 * -0x10: start of memory.
27 * -0x10: GUID for VT_DISPATCH and VT_UNKNOWN safearrays (if FADF_HAVEIID)
28 * -0x04: DWORD varianttype; (for all others, except VT_RECORD) (if FADF_HAVEVARTYPE)
29 * -0x4: IRecordInfo* iface; (if FADF_RECORD, for VT_RECORD (can be NULL))
31 * 0x10: SAFEARRAYBOUNDS[0...]
34 #define WIN32_NO_STATUS
46 //#include "winerror.h"
49 #include <wine/debug.h>
51 WINE_DEFAULT_DEBUG_CHANNEL(variant
);
53 /************************************************************************
54 * SafeArray {OLEAUT32}
57 * The SafeArray data type provides the underlying interface for Ole
58 * Automations arrays, used for example to represent array types in
59 * Visual Basic(tm) and to gather user defined parameters for invocation through
60 * an IDispatch interface.
62 * Safe arrays provide bounds checking and automatically manage the data
63 * types they contain, for example handing reference counting and copying
64 * of interface pointers. User defined types can be stored in arrays
65 * using the IRecordInfo interface.
67 * There are two types of SafeArray, normal and vectors. Normal arrays can have
68 * multiple dimensions and the data for the array is allocated separately from
69 * the array header. This is the most flexible type of array. Vectors, on the
70 * other hand, are fixed in size and consist of a single allocated block, and a
74 * The following types of data can be stored within a SafeArray.
76 *| VT_I1, VT_UI1, VT_I2, VT_UI2, VT_I4, VT_UI4, VT_I8, VT_UI8, VT_INT, VT_UINT,
77 *| VT_R4, VT_R8, VT_CY, VT_DECIMAL
79 *| VT_DISPATCH, VT_UNKNOWN, VT_RECORD
81 *| VT_VARIANT, VT_INT_PTR, VT_UINT_PTR, VT_BOOL, VT_ERROR, VT_DATE, VT_BSTR
88 /* Undocumented hidden space before the start of a SafeArray descriptor */
89 #define SAFEARRAY_HIDDEN_SIZE sizeof(GUID)
92 static inline LPVOID
SAFEARRAY_Malloc(ULONG ulSize
)
94 /* FIXME: Memory should be allocated and freed using a per-thread IMalloc
95 * instance returned from CoGetMalloc().
97 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ulSize
);
101 static inline BOOL
SAFEARRAY_Free(LPVOID lpData
)
103 return HeapFree(GetProcessHeap(), 0, lpData
);
106 /* Get the size of a supported VT type (0 means unsupported) */
107 static DWORD
SAFEARRAY_GetVTSize(VARTYPE vt
)
112 case VT_UI1
: return sizeof(BYTE
);
115 case VT_UI2
: return sizeof(SHORT
);
119 case VT_ERROR
: return sizeof(LONG
);
122 case VT_UI8
: return sizeof(LONG64
);
124 case VT_UINT
: return sizeof(INT
);
126 case VT_UINT_PTR
: return sizeof(UINT_PTR
);
127 case VT_CY
: return sizeof(CY
);
128 case VT_DATE
: return sizeof(DATE
);
129 case VT_BSTR
: return sizeof(BSTR
);
130 case VT_DISPATCH
: return sizeof(LPDISPATCH
);
131 case VT_VARIANT
: return sizeof(VARIANT
);
132 case VT_UNKNOWN
: return sizeof(LPUNKNOWN
);
133 case VT_DECIMAL
: return sizeof(DECIMAL
);
134 /* Note: Return a non-zero size to indicate vt is valid. The actual size
135 * of a UDT is taken from the result of IRecordInfo_GetSize().
137 case VT_RECORD
: return 32;
142 /* Set the hidden data for an array */
143 static inline void SAFEARRAY_SetHiddenDWORD(SAFEARRAY
* psa
, DWORD dw
)
145 /* Implementation data is stored in the 4 bytes before the header */
146 LPDWORD lpDw
= (LPDWORD
)psa
;
150 /* Get the hidden data from an array */
151 static inline DWORD
SAFEARRAY_GetHiddenDWORD(SAFEARRAY
* psa
)
153 LPDWORD lpDw
= (LPDWORD
)psa
;
157 /* Get the number of cells in a SafeArray */
158 static ULONG
SAFEARRAY_GetCellCount(const SAFEARRAY
*psa
)
160 const SAFEARRAYBOUND
* psab
= psa
->rgsabound
;
161 USHORT cCount
= psa
->cDims
;
162 ULONG ulNumCells
= 1;
166 /* This is a valid bordercase. See testcases. -Marcus */
167 if (!psab
->cElements
)
169 ulNumCells
*= psab
->cElements
;
175 /* Allocate a descriptor for an array */
176 static HRESULT
SAFEARRAY_AllocDescriptor(ULONG ulSize
, SAFEARRAY
**ppsaOut
)
178 char *ptr
= SAFEARRAY_Malloc(ulSize
+ SAFEARRAY_HIDDEN_SIZE
);
186 *ppsaOut
= (SAFEARRAY
*)(ptr
+ SAFEARRAY_HIDDEN_SIZE
);
190 /* Set the features of an array */
191 static void SAFEARRAY_SetFeatures(VARTYPE vt
, SAFEARRAY
*psa
)
193 /* Set the IID if we have one, otherwise set the type */
194 if (vt
== VT_DISPATCH
)
196 psa
->fFeatures
= FADF_HAVEIID
;
197 SafeArraySetIID(psa
, &IID_IDispatch
);
199 else if (vt
== VT_UNKNOWN
)
201 psa
->fFeatures
= FADF_HAVEIID
;
202 SafeArraySetIID(psa
, &IID_IUnknown
);
204 else if (vt
== VT_RECORD
)
205 psa
->fFeatures
= FADF_RECORD
;
208 psa
->fFeatures
= FADF_HAVEVARTYPE
;
209 SAFEARRAY_SetHiddenDWORD(psa
, vt
);
213 /* Create an array */
214 static SAFEARRAY
* SAFEARRAY_Create(VARTYPE vt
, UINT cDims
, const SAFEARRAYBOUND
*rgsabound
, ULONG ulSize
)
216 SAFEARRAY
*psa
= NULL
;
222 if (SUCCEEDED(SafeArrayAllocDescriptorEx(vt
, cDims
, &psa
)))
226 case VT_BSTR
: psa
->fFeatures
|= FADF_BSTR
; break;
227 case VT_UNKNOWN
: psa
->fFeatures
|= FADF_UNKNOWN
; break;
228 case VT_DISPATCH
: psa
->fFeatures
|= FADF_DISPATCH
; break;
229 case VT_VARIANT
: psa
->fFeatures
|= FADF_VARIANT
; break;
232 for (i
= 0; i
< cDims
; i
++)
233 memcpy(psa
->rgsabound
+ i
, rgsabound
+ cDims
- 1 - i
, sizeof(SAFEARRAYBOUND
));
236 psa
->cbElements
= ulSize
;
238 if (!psa
->cbElements
|| FAILED(SafeArrayAllocData(psa
)))
240 SafeArrayDestroyDescriptor(psa
);
247 /* Create an array as a vector */
248 static SAFEARRAY
* SAFEARRAY_CreateVector(VARTYPE vt
, LONG lLbound
, ULONG cElements
, ULONG ulSize
)
250 SAFEARRAY
*psa
= NULL
;
252 if (ulSize
|| (vt
== VT_RECORD
))
254 /* Allocate the header and data together */
255 if (SUCCEEDED(SAFEARRAY_AllocDescriptor(sizeof(SAFEARRAY
) + ulSize
* cElements
, &psa
)))
257 SAFEARRAY_SetFeatures(vt
, psa
);
260 psa
->fFeatures
|= FADF_CREATEVECTOR
;
261 psa
->pvData
= &psa
[1]; /* Data follows the header */
262 psa
->cbElements
= ulSize
;
263 psa
->rgsabound
[0].cElements
= cElements
;
264 psa
->rgsabound
[0].lLbound
= lLbound
;
268 case VT_BSTR
: psa
->fFeatures
|= FADF_BSTR
; break;
269 case VT_UNKNOWN
: psa
->fFeatures
|= FADF_UNKNOWN
; break;
270 case VT_DISPATCH
: psa
->fFeatures
|= FADF_DISPATCH
; break;
271 case VT_VARIANT
: psa
->fFeatures
|= FADF_VARIANT
; break;
278 /* Free data items in an array */
279 static HRESULT
SAFEARRAY_DestroyData(SAFEARRAY
*psa
, ULONG ulStartCell
)
281 if (psa
->pvData
&& !(psa
->fFeatures
& FADF_DATADELETED
))
283 ULONG ulCellCount
= SAFEARRAY_GetCellCount(psa
);
285 if (ulStartCell
> ulCellCount
) {
286 FIXME("unexpted ulcellcount %d, start %d\n",ulCellCount
,ulStartCell
);
290 ulCellCount
-= ulStartCell
;
292 if (psa
->fFeatures
& (FADF_UNKNOWN
|FADF_DISPATCH
))
294 LPUNKNOWN
*lpUnknown
= (LPUNKNOWN
*)psa
->pvData
+ ulStartCell
;
299 IUnknown_Release(*lpUnknown
);
303 else if (psa
->fFeatures
& (FADF_RECORD
))
305 IRecordInfo
*lpRecInfo
;
307 if (SUCCEEDED(SafeArrayGetRecordInfo(psa
, &lpRecInfo
)))
309 PBYTE pRecordData
= psa
->pvData
;
312 IRecordInfo_RecordClear(lpRecInfo
, pRecordData
);
313 pRecordData
+= psa
->cbElements
;
315 IRecordInfo_Release(lpRecInfo
);
318 else if (psa
->fFeatures
& FADF_BSTR
)
320 BSTR
* lpBstr
= (BSTR
*)psa
->pvData
+ ulStartCell
;
324 SysFreeString(*lpBstr
);
328 else if (psa
->fFeatures
& FADF_VARIANT
)
330 VARIANT
* lpVariant
= (VARIANT
*)psa
->pvData
+ ulStartCell
;
334 HRESULT hRet
= VariantClear(lpVariant
);
336 if (FAILED(hRet
)) FIXME("VariantClear of element failed!\n");
344 /* Copy data items from one array to another */
345 static HRESULT
SAFEARRAY_CopyData(SAFEARRAY
*psa
, SAFEARRAY
*dest
)
349 else if (!dest
->pvData
|| psa
->fFeatures
& FADF_DATADELETED
)
353 ULONG ulCellCount
= SAFEARRAY_GetCellCount(psa
);
355 dest
->fFeatures
= (dest
->fFeatures
& FADF_CREATEVECTOR
) |
356 (psa
->fFeatures
& ~(FADF_CREATEVECTOR
|FADF_DATADELETED
));
358 if (psa
->fFeatures
& FADF_VARIANT
)
360 VARIANT
* lpVariant
= psa
->pvData
;
361 VARIANT
* lpDest
= dest
->pvData
;
367 hRet
= VariantCopy(lpDest
, lpVariant
);
368 if (FAILED(hRet
)) FIXME("VariantCopy failed with 0x%x\n", hRet
);
373 else if (psa
->fFeatures
& FADF_BSTR
)
375 BSTR
* lpBstr
= psa
->pvData
;
376 BSTR
* lpDest
= dest
->pvData
;
382 *lpDest
= SysAllocStringByteLen((char*)*lpBstr
, SysStringByteLen(*lpBstr
));
384 return E_OUTOFMEMORY
;
394 /* Copy the data over */
395 memcpy(dest
->pvData
, psa
->pvData
, ulCellCount
* psa
->cbElements
);
397 if (psa
->fFeatures
& (FADF_UNKNOWN
|FADF_DISPATCH
))
399 LPUNKNOWN
*lpUnknown
= dest
->pvData
;
404 IUnknown_AddRef(*lpUnknown
);
410 if (psa
->fFeatures
& FADF_RECORD
)
412 IRecordInfo
* pRecInfo
= NULL
;
414 SafeArrayGetRecordInfo(psa
, &pRecInfo
);
415 SafeArraySetRecordInfo(dest
, pRecInfo
);
419 /* Release because Get() adds a reference */
420 IRecordInfo_Release(pRecInfo
);
423 else if (psa
->fFeatures
& FADF_HAVEIID
)
426 SafeArrayGetIID(psa
, &guid
);
427 SafeArraySetIID(dest
, &guid
);
429 else if (psa
->fFeatures
& FADF_HAVEVARTYPE
)
431 SAFEARRAY_SetHiddenDWORD(dest
, SAFEARRAY_GetHiddenDWORD(psa
));
437 /*************************************************************************
438 * SafeArrayAllocDescriptor (OLEAUT32.36)
440 * Allocate and initialise a descriptor for a SafeArray.
443 * cDims [I] Number of dimensions of the array
444 * ppsaOut [O] Destination for new descriptor
447 * Success: S_OK. ppsaOut is filled with a newly allocated descriptor.
448 * Failure: An HRESULT error code indicating the error.
453 HRESULT WINAPI
SafeArrayAllocDescriptor(UINT cDims
, SAFEARRAY
**ppsaOut
)
457 TRACE("(%d,%p)\n", cDims
, ppsaOut
);
459 if (!cDims
|| cDims
>= 0x10000) /* Maximum 65535 dimensions */
465 /* We need enough space for the header and its bounds */
466 allocSize
= sizeof(SAFEARRAY
) + sizeof(SAFEARRAYBOUND
) * (cDims
- 1);
468 if (FAILED(SAFEARRAY_AllocDescriptor(allocSize
, ppsaOut
)))
471 (*ppsaOut
)->cDims
= cDims
;
473 TRACE("(%d): %u bytes allocated for descriptor.\n", cDims
, allocSize
);
477 /*************************************************************************
478 * SafeArrayAllocDescriptorEx (OLEAUT32.41)
480 * Allocate and initialise a descriptor for a SafeArray of a given type.
483 * vt [I] The type of items to store in the array
484 * cDims [I] Number of dimensions of the array
485 * ppsaOut [O] Destination for new descriptor
488 * Success: S_OK. ppsaOut is filled with a newly allocated descriptor.
489 * Failure: An HRESULT error code indicating the error.
492 * - This function does not check that vt is an allowed VARTYPE.
493 * - Unlike SafeArrayAllocDescriptor(), vt is associated with the array.
496 HRESULT WINAPI
SafeArrayAllocDescriptorEx(VARTYPE vt
, UINT cDims
, SAFEARRAY
**ppsaOut
)
499 HRESULT hRet
= E_UNEXPECTED
;
501 TRACE("(%d->%s,%d,%p)\n", vt
, debugstr_vt(vt
), cDims
, ppsaOut
);
503 cbElements
= SAFEARRAY_GetVTSize(vt
);
505 WARN("Creating a descriptor with an invalid VARTYPE!\n");
507 hRet
= SafeArrayAllocDescriptor(cDims
, ppsaOut
);
511 SAFEARRAY_SetFeatures(vt
, *ppsaOut
);
512 (*ppsaOut
)->cbElements
= cbElements
;
517 /*************************************************************************
518 * SafeArrayAllocData (OLEAUT32.37)
520 * Allocate the data area of a SafeArray.
523 * psa [I] SafeArray to allocate the data area of.
526 * Success: S_OK. The data area is allocated and initialised.
527 * Failure: An HRESULT error code indicating the error.
532 HRESULT WINAPI
SafeArrayAllocData(SAFEARRAY
*psa
)
534 HRESULT hRet
= E_INVALIDARG
;
536 TRACE("(%p)\n", psa
);
540 ULONG ulSize
= SAFEARRAY_GetCellCount(psa
);
542 psa
->pvData
= SAFEARRAY_Malloc(ulSize
* psa
->cbElements
);
547 TRACE("%u bytes allocated for data at %p (%u objects).\n",
548 ulSize
* psa
->cbElements
, psa
->pvData
, ulSize
);
551 hRet
= E_OUTOFMEMORY
;
556 /*************************************************************************
557 * SafeArrayCreate (OLEAUT32.15)
559 * Create a new SafeArray.
562 * vt [I] Type to store in the safe array
563 * cDims [I] Number of array dimensions
564 * rgsabound [I] Bounds of the array dimensions
567 * Success: A pointer to a new array object.
568 * Failure: NULL, if any parameter is invalid or memory allocation fails.
571 * Win32 allows arrays with 0 sized dimensions. This bug is not reproduced
572 * in the Wine implementation.
575 SAFEARRAY
* WINAPI
SafeArrayCreate(VARTYPE vt
, UINT cDims
, SAFEARRAYBOUND
*rgsabound
)
577 TRACE("(%d->%s,%d,%p)\n", vt
, debugstr_vt(vt
), cDims
, rgsabound
);
582 return SAFEARRAY_Create(vt
, cDims
, rgsabound
, 0);
585 /*************************************************************************
586 * SafeArrayCreateEx (OLEAUT32.15)
588 * Create a new SafeArray.
591 * vt [I] Type to store in the safe array
592 * cDims [I] Number of array dimensions
593 * rgsabound [I] Bounds of the array dimensions
594 * pvExtra [I] Extra data
597 * Success: A pointer to a new array object.
598 * Failure: NULL, if any parameter is invalid or memory allocation fails.
603 SAFEARRAY
* WINAPI
SafeArrayCreateEx(VARTYPE vt
, UINT cDims
, SAFEARRAYBOUND
*rgsabound
, LPVOID pvExtra
)
606 IRecordInfo
* iRecInfo
= pvExtra
;
609 TRACE("(%d->%s,%d,%p,%p)\n", vt
, debugstr_vt(vt
), cDims
, rgsabound
, pvExtra
);
615 IRecordInfo_GetSize(iRecInfo
, &ulSize
);
617 psa
= SAFEARRAY_Create(vt
, cDims
, rgsabound
, ulSize
);
624 SafeArraySetRecordInfo(psa
, pvExtra
);
628 SafeArraySetIID(psa
, pvExtra
);
635 /************************************************************************
636 * SafeArrayCreateVector (OLEAUT32.411)
638 * Create a one dimensional, contiguous SafeArray.
641 * vt [I] Type to store in the safe array
642 * lLbound [I] Lower bound of the array
643 * cElements [I] Number of elements in the array
646 * Success: A pointer to a new array object.
647 * Failure: NULL, if any parameter is invalid or memory allocation fails.
652 SAFEARRAY
* WINAPI
SafeArrayCreateVector(VARTYPE vt
, LONG lLbound
, ULONG cElements
)
654 TRACE("(%d->%s,%d,%d\n", vt
, debugstr_vt(vt
), lLbound
, cElements
);
659 return SAFEARRAY_CreateVector(vt
, lLbound
, cElements
, SAFEARRAY_GetVTSize(vt
));
662 /************************************************************************
663 * SafeArrayCreateVectorEx (OLEAUT32.411)
665 * Create a one dimensional, contiguous SafeArray.
668 * vt [I] Type to store in the safe array
669 * lLbound [I] Lower bound of the array
670 * cElements [I] Number of elements in the array
671 * pvExtra [I] Extra data
674 * Success: A pointer to a new array object.
675 * Failure: NULL, if any parameter is invalid or memory allocation fails.
680 SAFEARRAY
* WINAPI
SafeArrayCreateVectorEx(VARTYPE vt
, LONG lLbound
, ULONG cElements
, LPVOID pvExtra
)
683 IRecordInfo
* iRecInfo
= pvExtra
;
686 TRACE("(%d->%s,%d,%d,%p\n", vt
, debugstr_vt(vt
), lLbound
, cElements
, pvExtra
);
692 IRecordInfo_GetSize(iRecInfo
, &ulSize
);
695 ulSize
= SAFEARRAY_GetVTSize(vt
);
697 psa
= SAFEARRAY_CreateVector(vt
, lLbound
, cElements
, ulSize
);
704 SafeArraySetRecordInfo(psa
, iRecInfo
);
708 SafeArraySetIID(psa
, pvExtra
);
715 /*************************************************************************
716 * SafeArrayDestroyDescriptor (OLEAUT32.38)
718 * Destroy a SafeArray.
721 * psa [I] SafeArray to destroy.
724 * Success: S_OK. The resources used by the array are freed.
725 * Failure: An HRESULT error code indicating the error.
730 HRESULT WINAPI
SafeArrayDestroyDescriptor(SAFEARRAY
*psa
)
732 TRACE("(%p)\n", psa
);
736 LPVOID lpv
= (char*)psa
- SAFEARRAY_HIDDEN_SIZE
;
739 return DISP_E_ARRAYISLOCKED
; /* Can't destroy a locked array */
741 if (psa
->fFeatures
& FADF_RECORD
)
742 SafeArraySetRecordInfo(psa
, NULL
);
744 if (psa
->fFeatures
& FADF_CREATEVECTOR
&&
745 !(psa
->fFeatures
& FADF_DATADELETED
))
746 SAFEARRAY_DestroyData(psa
, 0); /* Data not previously deleted */
748 if (!SAFEARRAY_Free(lpv
))
754 /*************************************************************************
755 * SafeArrayLock (OLEAUT32.21)
757 * Increment the lock counter of a SafeArray.
760 * psa [O] SafeArray to lock
763 * Success: S_OK. The array lock is incremented.
764 * Failure: E_INVALIDARG if psa is NULL, or E_UNEXPECTED if too many locks
765 * are held on the array at once.
768 * In Win32 these locks are not thread safe.
771 HRESULT WINAPI
SafeArrayLock(SAFEARRAY
*psa
)
775 TRACE("(%p)\n", psa
);
780 ulLocks
= InterlockedIncrement( (LONG
*) &psa
->cLocks
);
782 if (ulLocks
> 0xffff) /* Maximum of 16384 locks at a time */
784 WARN("Out of locks!\n");
785 InterlockedDecrement( (LONG
*) &psa
->cLocks
);
791 /*************************************************************************
792 * SafeArrayUnlock (OLEAUT32.22)
794 * Decrement the lock counter of a SafeArray.
797 * psa [O] SafeArray to unlock
800 * Success: S_OK. The array lock is decremented.
801 * Failure: E_INVALIDARG if psa is NULL, or E_UNEXPECTED if no locks are
807 HRESULT WINAPI
SafeArrayUnlock(SAFEARRAY
*psa
)
809 TRACE("(%p)\n", psa
);
814 if (InterlockedDecrement( (LONG
*) &psa
->cLocks
) < 0)
816 WARN("Unlocked but no lock held!\n");
817 InterlockedIncrement( (LONG
*) &psa
->cLocks
);
823 /*************************************************************************
824 * SafeArrayPutElement (OLEAUT32.26)
826 * Put an item into a SafeArray.
829 * psa [I] SafeArray to insert into
830 * rgIndices [I] Indices to insert at
831 * pvData [I] Data to insert
834 * Success: S_OK. The item is inserted
835 * Failure: An HRESULT error code indicating the error.
840 HRESULT WINAPI
SafeArrayPutElement(SAFEARRAY
*psa
, LONG
*rgIndices
, void *pvData
)
844 TRACE("(%p,%p,%p)\n", psa
, rgIndices
, pvData
);
846 if (!psa
|| !rgIndices
)
849 hRet
= SafeArrayLock(psa
);
855 hRet
= SafeArrayPtrOfIndex(psa
, rgIndices
, &lpvDest
);
859 if (psa
->fFeatures
& FADF_VARIANT
)
861 VARIANT
* lpVariant
= pvData
;
862 VARIANT
* lpDest
= lpvDest
;
864 hRet
= VariantClear(lpDest
);
865 if (FAILED(hRet
)) FIXME("VariantClear failed with 0x%x\n", hRet
);
866 hRet
= VariantCopy(lpDest
, lpVariant
);
867 if (FAILED(hRet
)) FIXME("VariantCopy failed with 0x%x\n", hRet
);
869 else if (psa
->fFeatures
& FADF_BSTR
)
871 BSTR lpBstr
= (BSTR
)pvData
;
872 BSTR
* lpDest
= lpvDest
;
874 SysFreeString(*lpDest
);
876 *lpDest
= SysAllocStringByteLen((char*)lpBstr
, SysStringByteLen(lpBstr
));
878 hRet
= E_OUTOFMEMORY
;
882 if (psa
->fFeatures
& (FADF_UNKNOWN
|FADF_DISPATCH
))
884 LPUNKNOWN lpUnknown
= pvData
;
885 LPUNKNOWN
*lpDest
= lpvDest
;
888 IUnknown_AddRef(lpUnknown
);
890 IUnknown_Release(*lpDest
);
893 /* Copy the data over */
894 memcpy(lpvDest
, pvData
, psa
->cbElements
);
898 SafeArrayUnlock(psa
);
904 /*************************************************************************
905 * SafeArrayGetElement (OLEAUT32.25)
907 * Get an item from a SafeArray.
910 * psa [I] SafeArray to get from
911 * rgIndices [I] Indices to get from
912 * pvData [O] Destination for data
915 * Success: S_OK. The item data is returned in pvData.
916 * Failure: An HRESULT error code indicating the error.
921 HRESULT WINAPI
SafeArrayGetElement(SAFEARRAY
*psa
, LONG
*rgIndices
, void *pvData
)
925 TRACE("(%p,%p,%p)\n", psa
, rgIndices
, pvData
);
927 if (!psa
|| !rgIndices
|| !pvData
)
930 hRet
= SafeArrayLock(psa
);
936 hRet
= SafeArrayPtrOfIndex(psa
, rgIndices
, &lpvSrc
);
940 if (psa
->fFeatures
& FADF_VARIANT
)
942 VARIANT
* lpVariant
= lpvSrc
;
943 VARIANT
* lpDest
= pvData
;
945 /* The original content of pvData is ignored. */
946 V_VT(lpDest
) = VT_EMPTY
;
947 hRet
= VariantCopy(lpDest
, lpVariant
);
948 if (FAILED(hRet
)) FIXME("VariantCopy failed with 0x%x\n", hRet
);
950 else if (psa
->fFeatures
& FADF_BSTR
)
952 BSTR
* lpBstr
= lpvSrc
;
953 BSTR
* lpDest
= pvData
;
957 *lpDest
= SysAllocStringByteLen((char*)*lpBstr
, SysStringByteLen(*lpBstr
));
959 hRet
= E_OUTOFMEMORY
;
966 if (psa
->fFeatures
& (FADF_UNKNOWN
|FADF_DISPATCH
))
968 LPUNKNOWN
*lpUnknown
= lpvSrc
;
971 IUnknown_AddRef(*lpUnknown
);
973 /* Copy the data over */
974 memcpy(pvData
, lpvSrc
, psa
->cbElements
);
977 SafeArrayUnlock(psa
);
982 /*************************************************************************
983 * SafeArrayGetUBound (OLEAUT32.19)
985 * Get the upper bound for a given SafeArray dimension
988 * psa [I] Array to get dimension upper bound from
989 * nDim [I] The dimension number to get the upper bound of
990 * plUbound [O] Destination for the upper bound
993 * Success: S_OK. plUbound contains the dimensions upper bound.
994 * Failure: An HRESULT error code indicating the error.
999 HRESULT WINAPI
SafeArrayGetUBound(SAFEARRAY
*psa
, UINT nDim
, LONG
*plUbound
)
1001 TRACE("(%p,%d,%p)\n", psa
, nDim
, plUbound
);
1003 if (!psa
|| !plUbound
)
1004 return E_INVALIDARG
;
1006 if(!nDim
|| nDim
> psa
->cDims
)
1007 return DISP_E_BADINDEX
;
1009 *plUbound
= psa
->rgsabound
[psa
->cDims
- nDim
].lLbound
+
1010 psa
->rgsabound
[psa
->cDims
- nDim
].cElements
- 1;
1015 /*************************************************************************
1016 * SafeArrayGetLBound (OLEAUT32.20)
1018 * Get the lower bound for a given SafeArray dimension
1021 * psa [I] Array to get dimension lower bound from
1022 * nDim [I] The dimension number to get the lower bound of
1023 * plLbound [O] Destination for the lower bound
1026 * Success: S_OK. plUbound contains the dimensions lower bound.
1027 * Failure: An HRESULT error code indicating the error.
1032 HRESULT WINAPI
SafeArrayGetLBound(SAFEARRAY
*psa
, UINT nDim
, LONG
*plLbound
)
1034 TRACE("(%p,%d,%p)\n", psa
, nDim
, plLbound
);
1036 if (!psa
|| !plLbound
)
1037 return E_INVALIDARG
;
1039 if(!nDim
|| nDim
> psa
->cDims
)
1040 return DISP_E_BADINDEX
;
1042 *plLbound
= psa
->rgsabound
[psa
->cDims
- nDim
].lLbound
;
1046 /*************************************************************************
1047 * SafeArrayGetDim (OLEAUT32.17)
1049 * Get the number of dimensions in a SafeArray.
1052 * psa [I] Array to get the dimensions of
1055 * The number of array dimensions in psa, or 0 if psa is NULL.
1060 UINT WINAPI
SafeArrayGetDim(SAFEARRAY
*psa
)
1062 TRACE("(%p) returning %d\n", psa
, psa
? psa
->cDims
: 0u);
1063 return psa
? psa
->cDims
: 0;
1066 /*************************************************************************
1067 * SafeArrayGetElemsize (OLEAUT32.18)
1069 * Get the size of an element in a SafeArray.
1072 * psa [I] Array to get the element size from
1075 * The size of a single element in psa, or 0 if psa is NULL.
1080 UINT WINAPI
SafeArrayGetElemsize(SAFEARRAY
*psa
)
1082 TRACE("(%p) returning %d\n", psa
, psa
? psa
->cbElements
: 0u);
1083 return psa
? psa
->cbElements
: 0;
1086 /*************************************************************************
1087 * SafeArrayAccessData (OLEAUT32.23)
1089 * Lock a SafeArray and return a pointer to its data.
1092 * psa [I] Array to get the data pointer from
1093 * ppvData [O] Destination for the arrays data pointer
1096 * Success: S_OK. ppvData contains the arrays data pointer, and the array
1098 * Failure: An HRESULT error code indicating the error.
1103 HRESULT WINAPI
SafeArrayAccessData(SAFEARRAY
*psa
, void **ppvData
)
1105 TRACE("(%p,%p)\n", psa
, ppvData
);
1107 if(!psa
|| !ppvData
)
1108 return E_INVALIDARG
;
1110 if (SUCCEEDED(SafeArrayLock(psa
)))
1112 *ppvData
= psa
->pvData
;
1116 return E_UNEXPECTED
;
1120 /*************************************************************************
1121 * SafeArrayUnaccessData (OLEAUT32.24)
1123 * Unlock a SafeArray after accessing its data.
1126 * psa [I] Array to unlock
1129 * Success: S_OK. The array is unlocked.
1130 * Failure: An HRESULT error code indicating the error.
1135 HRESULT WINAPI
SafeArrayUnaccessData(SAFEARRAY
*psa
)
1137 TRACE("(%p)\n", psa
);
1138 return SafeArrayUnlock(psa
);
1141 /************************************************************************
1142 * SafeArrayPtrOfIndex (OLEAUT32.148)
1144 * Get the address of an item in a SafeArray.
1147 * psa [I] Array to get the items address from
1148 * rgIndices [I] Index of the item in the array
1149 * ppvData [O] Destination for item address
1152 * Success: S_OK. ppvData contains a pointer to the item.
1153 * Failure: An HRESULT error code indicating the error.
1156 * This function does not lock the array.
1161 HRESULT WINAPI
SafeArrayPtrOfIndex(SAFEARRAY
*psa
, LONG
*rgIndices
, void **ppvData
)
1164 ULONG cell
= 0, dimensionSize
= 1;
1165 SAFEARRAYBOUND
* psab
;
1168 TRACE("(%p,%p,%p)\n", psa
, rgIndices
, ppvData
);
1170 /* The general formula for locating the cell number of an entry in an n
1171 * dimensional array (where cn = coordinate in dimension dn) is:
1173 * c1 + c2 * sizeof(d1) + c3 * sizeof(d2) ... + cn * sizeof(c(n-1))
1175 * We calculate the size of the last dimension at each step through the
1176 * dimensions to avoid recursing to calculate the last dimensions size.
1178 if (!psa
|| !rgIndices
|| !ppvData
)
1179 return E_INVALIDARG
;
1181 psab
= psa
->rgsabound
+ psa
->cDims
- 1;
1184 if (c1
< psab
->lLbound
|| c1
>= psab
->lLbound
+ (LONG
)psab
->cElements
)
1185 return DISP_E_BADINDEX
; /* Initial index out of bounds */
1187 for (dim
= 1; dim
< psa
->cDims
; dim
++)
1189 dimensionSize
*= psab
->cElements
;
1193 if (!psab
->cElements
||
1194 *rgIndices
< psab
->lLbound
||
1195 *rgIndices
>= psab
->lLbound
+ (LONG
)psab
->cElements
)
1196 return DISP_E_BADINDEX
; /* Index out of bounds */
1198 cell
+= (*rgIndices
- psab
->lLbound
) * dimensionSize
;
1202 cell
+= (c1
- psa
->rgsabound
[psa
->cDims
- 1].lLbound
);
1204 *ppvData
= (char*)psa
->pvData
+ cell
* psa
->cbElements
;
1208 /************************************************************************
1209 * SafeArrayDestroyData (OLEAUT32.39)
1211 * Destroy the data associated with a SafeArray.
1214 * psa [I] Array to delete the data from
1217 * Success: S_OK. All items and the item data are freed.
1218 * Failure: An HRESULT error code indicating the error.
1223 HRESULT WINAPI
SafeArrayDestroyData(SAFEARRAY
*psa
)
1225 TRACE("(%p)\n", psa
);
1228 return E_INVALIDARG
;
1231 return DISP_E_ARRAYISLOCKED
; /* Can't delete a locked array */
1233 /* Delete the actual item data */
1234 if (FAILED(SAFEARRAY_DestroyData(psa
, 0)))
1235 return E_UNEXPECTED
;
1239 if (psa
->fFeatures
& FADF_STATIC
)
1241 ZeroMemory(psa
->pvData
, SAFEARRAY_GetCellCount(psa
) * psa
->cbElements
);
1244 /* If this is not a vector, free the data memory block */
1245 if (!(psa
->fFeatures
& FADF_CREATEVECTOR
))
1247 if (!SAFEARRAY_Free(psa
->pvData
))
1248 return E_UNEXPECTED
;
1252 psa
->fFeatures
|= FADF_DATADELETED
; /* Mark the data deleted */
1258 /************************************************************************
1259 * SafeArrayCopyData (OLEAUT32.412)
1261 * Copy all data from one SafeArray to another.
1264 * psaSource [I] Source for copy
1265 * psaTarget [O] Destination for copy
1268 * Success: S_OK. psaTarget contains a copy of psaSource.
1269 * Failure: An HRESULT error code indicating the error.
1272 * The two arrays must have the same number of dimensions and elements.
1277 HRESULT WINAPI
SafeArrayCopyData(SAFEARRAY
*psaSource
, SAFEARRAY
*psaTarget
)
1281 TRACE("(%p,%p)\n", psaSource
, psaTarget
);
1283 if (!psaSource
|| !psaTarget
||
1284 psaSource
->cDims
!= psaTarget
->cDims
||
1285 psaSource
->cbElements
!= psaTarget
->cbElements
)
1286 return E_INVALIDARG
;
1288 /* Each dimension must be the same size */
1289 for (dim
= psaSource
->cDims
- 1; dim
>= 0 ; dim
--)
1290 if (psaSource
->rgsabound
[dim
].cElements
!=
1291 psaTarget
->rgsabound
[dim
].cElements
)
1292 return E_INVALIDARG
;
1294 if (SUCCEEDED(SAFEARRAY_DestroyData(psaTarget
, 0)) &&
1295 SUCCEEDED(SAFEARRAY_CopyData(psaSource
, psaTarget
)))
1297 return E_UNEXPECTED
;
1300 /************************************************************************
1301 * SafeArrayDestroy (OLEAUT32.16)
1303 * Destroy a SafeArray.
1306 * psa [I] Array to destroy
1309 * Success: S_OK. All resources used by the array are freed.
1310 * Failure: An HRESULT error code indicating the error.
1315 HRESULT WINAPI
SafeArrayDestroy(SAFEARRAY
*psa
)
1317 TRACE("(%p)\n", psa
);
1323 return DISP_E_ARRAYISLOCKED
;
1325 /* Native doesn't check to see if the free succeeds */
1326 SafeArrayDestroyData(psa
);
1327 SafeArrayDestroyDescriptor(psa
);
1331 /************************************************************************
1332 * SafeArrayCopy (OLEAUT32.27)
1334 * Make a duplicate of a SafeArray.
1337 * psa [I] Source for copy
1338 * ppsaOut [O] Destination for new copy
1341 * Success: S_OK. ppsaOut contains a copy of the array.
1342 * Failure: An HRESULT error code indicating the error.
1347 HRESULT WINAPI
SafeArrayCopy(SAFEARRAY
*psa
, SAFEARRAY
**ppsaOut
)
1351 TRACE("(%p,%p)\n", psa
, ppsaOut
);
1354 return E_INVALIDARG
;
1359 return S_OK
; /* Handles copying of NULL arrays */
1361 if (!psa
->cbElements
)
1362 return E_INVALIDARG
;
1364 if (psa
->fFeatures
& (FADF_RECORD
|FADF_HAVEIID
|FADF_HAVEVARTYPE
))
1367 if (FAILED(SafeArrayGetVartype(psa
, &vt
)))
1368 hRet
= E_UNEXPECTED
;
1370 hRet
= SafeArrayAllocDescriptorEx(vt
, psa
->cDims
, ppsaOut
);
1374 hRet
= SafeArrayAllocDescriptor(psa
->cDims
, ppsaOut
);
1375 if (SUCCEEDED(hRet
))
1377 (*ppsaOut
)->fFeatures
= psa
->fFeatures
& ~FADF_CREATEVECTOR
;
1378 (*ppsaOut
)->cbElements
= psa
->cbElements
;
1382 if (SUCCEEDED(hRet
))
1384 /* Copy dimension bounds */
1385 memcpy((*ppsaOut
)->rgsabound
, psa
->rgsabound
, psa
->cDims
* sizeof(SAFEARRAYBOUND
));
1387 (*ppsaOut
)->pvData
= SAFEARRAY_Malloc(SAFEARRAY_GetCellCount(psa
) * psa
->cbElements
);
1389 if ((*ppsaOut
)->pvData
)
1391 hRet
= SAFEARRAY_CopyData(psa
, *ppsaOut
);
1393 if (SUCCEEDED(hRet
))
1396 SAFEARRAY_Free((*ppsaOut
)->pvData
);
1398 SafeArrayDestroyDescriptor(*ppsaOut
);
1404 /************************************************************************
1405 * SafeArrayRedim (OLEAUT32.40)
1407 * Changes the characteristics of the last dimension of a SafeArray
1410 * psa [I] Array to change
1411 * psabound [I] New bound details for the last dimension
1414 * Success: S_OK. psa is updated to reflect the new bounds.
1415 * Failure: An HRESULT error code indicating the error.
1420 HRESULT WINAPI
SafeArrayRedim(SAFEARRAY
*psa
, SAFEARRAYBOUND
*psabound
)
1422 SAFEARRAYBOUND
*oldBounds
;
1424 TRACE("(%p,%p)\n", psa
, psabound
);
1426 if (!psa
|| psa
->fFeatures
& FADF_FIXEDSIZE
|| !psabound
)
1427 return E_INVALIDARG
;
1429 if (psa
->cLocks
> 0)
1430 return DISP_E_ARRAYISLOCKED
;
1432 if (FAILED(SafeArrayLock(psa
)))
1433 return E_UNEXPECTED
;
1435 oldBounds
= psa
->rgsabound
;
1436 oldBounds
->lLbound
= psabound
->lLbound
;
1438 if (psabound
->cElements
!= oldBounds
->cElements
)
1440 if (psabound
->cElements
< oldBounds
->cElements
)
1442 /* Shorten the final dimension. */
1443 ULONG ulStartCell
= psabound
->cElements
*
1444 (SAFEARRAY_GetCellCount(psa
) / oldBounds
->cElements
);
1445 SAFEARRAY_DestroyData(psa
, ulStartCell
);
1449 /* Lengthen the final dimension */
1450 ULONG ulOldSize
, ulNewSize
;
1453 ulOldSize
= SAFEARRAY_GetCellCount(psa
) * psa
->cbElements
;
1455 ulNewSize
= (ulOldSize
/ oldBounds
->cElements
) * psabound
->cElements
;
1457 int oldelems
= oldBounds
->cElements
;
1458 oldBounds
->cElements
= psabound
->cElements
;
1459 ulNewSize
= SAFEARRAY_GetCellCount(psa
) * psa
->cbElements
;
1460 oldBounds
->cElements
= oldelems
;
1463 if (!(pvNewData
= SAFEARRAY_Malloc(ulNewSize
)))
1465 SafeArrayUnlock(psa
);
1466 return E_UNEXPECTED
;
1469 memcpy(pvNewData
, psa
->pvData
, ulOldSize
);
1470 SAFEARRAY_Free(psa
->pvData
);
1471 psa
->pvData
= pvNewData
;
1473 oldBounds
->cElements
= psabound
->cElements
;
1476 SafeArrayUnlock(psa
);
1480 /************************************************************************
1481 * SafeArrayGetVartype (OLEAUT32.77)
1483 * Get the type of the items in a SafeArray.
1486 * psa [I] Array to get the type from
1487 * pvt [O] Destination for the type
1490 * Success: S_OK. pvt contains the type of the items.
1491 * Failure: An HRESULT error code indicating the error.
1496 HRESULT WINAPI
SafeArrayGetVartype(SAFEARRAY
* psa
, VARTYPE
* pvt
)
1498 TRACE("(%p,%p)\n", psa
, pvt
);
1501 return E_INVALIDARG
;
1503 if (psa
->fFeatures
& FADF_RECORD
)
1505 else if ((psa
->fFeatures
& (FADF_HAVEIID
|FADF_DISPATCH
)) == (FADF_HAVEIID
|FADF_DISPATCH
))
1507 else if (psa
->fFeatures
& FADF_HAVEIID
)
1509 else if (psa
->fFeatures
& FADF_HAVEVARTYPE
)
1511 VARTYPE vt
= SAFEARRAY_GetHiddenDWORD(psa
);
1515 return E_INVALIDARG
;
1520 /************************************************************************
1521 * SafeArraySetRecordInfo (OLEAUT32.@)
1523 * Set the record info for a SafeArray.
1526 * psa [I] Array to set the record info for
1527 * pRinfo [I] Record info
1530 * Success: S_OK. The record info is stored with the array.
1531 * Failure: An HRESULT error code indicating the error.
1536 HRESULT WINAPI
SafeArraySetRecordInfo(SAFEARRAY
*psa
, IRecordInfo
*pRinfo
)
1538 IRecordInfo
** dest
= (IRecordInfo
**)psa
;
1540 TRACE("(%p,%p)\n", psa
, pRinfo
);
1542 if (!psa
|| !(psa
->fFeatures
& FADF_RECORD
))
1543 return E_INVALIDARG
;
1546 IRecordInfo_AddRef(pRinfo
);
1549 IRecordInfo_Release(dest
[-1]);
1555 /************************************************************************
1556 * SafeArrayGetRecordInfo (OLEAUT32.@)
1558 * Get the record info from a SafeArray.
1561 * psa [I] Array to get the record info from
1562 * pRinfo [O] Destination for the record info
1565 * Success: S_OK. pRinfo contains the record info, or NULL if there was none.
1566 * Failure: An HRESULT error code indicating the error.
1571 HRESULT WINAPI
SafeArrayGetRecordInfo(SAFEARRAY
*psa
, IRecordInfo
**pRinfo
)
1573 IRecordInfo
** src
= (IRecordInfo
**)psa
;
1575 TRACE("(%p,%p)\n", psa
, pRinfo
);
1577 if (!psa
|| !pRinfo
|| !(psa
->fFeatures
& FADF_RECORD
))
1578 return E_INVALIDARG
;
1583 IRecordInfo_AddRef(*pRinfo
);
1587 /************************************************************************
1588 * SafeArraySetIID (OLEAUT32.@)
1590 * Set the IID for a SafeArray.
1593 * psa [I] Array to set the IID from
1597 * Success: S_OK. The IID is stored with the array
1598 * Failure: An HRESULT error code indicating the error.
1603 HRESULT WINAPI
SafeArraySetIID(SAFEARRAY
*psa
, REFGUID guid
)
1605 GUID
* dest
= (GUID
*)psa
;
1607 TRACE("(%p,%s)\n", psa
, debugstr_guid(guid
));
1609 if (!psa
|| !guid
|| !(psa
->fFeatures
& FADF_HAVEIID
))
1610 return E_INVALIDARG
;
1616 /************************************************************************
1617 * SafeArrayGetIID (OLEAUT32.@)
1619 * Get the IID from a SafeArray.
1622 * psa [I] Array to get the ID from
1623 * pGuid [O] Destination for the IID
1626 * Success: S_OK. pRinfo contains the IID, or NULL if there was none.
1627 * Failure: An HRESULT error code indicating the error.
1632 HRESULT WINAPI
SafeArrayGetIID(SAFEARRAY
*psa
, GUID
*pGuid
)
1634 GUID
* src
= (GUID
*)psa
;
1636 TRACE("(%p,%p)\n", psa
, pGuid
);
1638 if (!psa
|| !pGuid
|| !(psa
->fFeatures
& FADF_HAVEIID
))
1639 return E_INVALIDARG
;
1645 /************************************************************************
1646 * VectorFromBstr (OLEAUT32.@)
1648 * Create a SafeArray Vector from the bytes of a BSTR.
1651 * bstr [I] String to get bytes from
1652 * ppsa [O] Destination for the array
1655 * Success: S_OK. ppsa contains the strings bytes as a VT_UI1 array.
1656 * Failure: An HRESULT error code indicating the error.
1661 HRESULT WINAPI
VectorFromBstr(BSTR bstr
, SAFEARRAY
**ppsa
)
1665 TRACE("(%p,%p)\n", bstr
, ppsa
);
1668 return E_INVALIDARG
;
1671 sab
.cElements
= SysStringByteLen(bstr
);
1673 *ppsa
= SAFEARRAY_Create(VT_UI1
, 1, &sab
, 0);
1677 memcpy((*ppsa
)->pvData
, bstr
, sab
.cElements
);
1680 return E_OUTOFMEMORY
;
1683 /************************************************************************
1684 * BstrFromVector (OLEAUT32.@)
1686 * Create a BSTR from a SafeArray.
1689 * psa [I] Source array
1690 * pbstr [O] Destination for output BSTR
1693 * Success: S_OK. pbstr contains the arrays data.
1694 * Failure: An HRESULT error code indicating the error.
1697 * psa must be a 1 dimensional array of a 1 byte type.
1702 HRESULT WINAPI
BstrFromVector(SAFEARRAY
*psa
, BSTR
*pbstr
)
1704 TRACE("(%p,%p)\n", psa
, pbstr
);
1707 return E_INVALIDARG
;
1711 if (!psa
|| psa
->cbElements
!= 1 || psa
->cDims
!= 1)
1712 return E_INVALIDARG
;
1714 *pbstr
= SysAllocStringByteLen(psa
->pvData
, psa
->rgsabound
[0].cElements
);
1716 return E_OUTOFMEMORY
;