Modify widl to put the C COM macros inside an #ifdef COBJMACROS block
[wine/wine-kai.git] / dlls / oleaut32 / safearray.c
blob88763233181ee5132f0057254a1d354f41eb9d46
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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))
30 * 0x00: SAFEARRAY,
31 * 0x10: SAFEARRAYBOUNDS[0...]
34 #include "config.h"
36 #include <string.h>
37 #include <stdarg.h>
38 #include <stdio.h>
40 #define COBJMACROS
42 #include "windef.h"
43 #include "winerror.h"
44 #include "winbase.h"
45 #include "oleauto.h"
46 #include "wine/debug.h"
47 #include "variant.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(variant);
51 /************************************************************************
52 * SafeArray {OLEAUT32}
54 * NOTES
55 * The SafeArray data type provides the underlying interface for Ole
56 * Automations arrays, used for example to represent array types in
57 * Visual Basic(tm) and to gather user defined parameters for invocation through
58 * an IDispatch interface.
60 * Safe arrays provide bounds checking and automatically manage the data
61 * types they contain, for example handing reference counting and copying
62 * of interface pointers. User defined types can be stored in arrays
63 * using the IRecordInfo interface.
65 * There are two types of SafeArray, normal and vectors. Normal arrays can have
66 * multiple dimensions and the data for the array is allocated separately from
67 * the array header. This is the most flexible type of array. Vectors, on the
68 * other hand, are fixed in size and consist of a single allocated block, and a
69 * single dimension.
71 * DATATYPES
72 * The following types of data can be stored within a SafeArray.
73 * Numeric:
74 *| VT_I1, VT_UI1, VT_I2, VT_UI2, VT_I4, VT_UI4, VT_I8, VT_UI8, VT_INT, VT_UINT,
75 *| VT_R4, VT_R8, VT_CY, VT_DECIMAL
76 * Interfaces:
77 *| VT_DISPATCH, VT_UNKNOWN, VT_RECORD
78 * Other:
79 *| VT_VARIANT, VT_INT_PTR, VT_UINT_PTR, VT_BOOL, VT_ERROR, VT_DATE, VT_BSTR
81 * FUNCTIONS
82 * BstrFromVector()
83 * VectorFromBstr()
86 /* Undocumented hidden space before the start of a SafeArray descriptor */
87 #define SAFEARRAY_HIDDEN_SIZE sizeof(GUID)
89 /* Allocate memory */
90 static inline LPVOID SAFEARRAY_Malloc(ULONG ulSize)
92 /* FIXME: Memory should be allocated and freed using a per-thread IMalloc
93 * instance returned from CoGetMalloc().
95 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulSize);
98 /* Free memory */
99 static inline BOOL SAFEARRAY_Free(LPVOID lpData)
101 return HeapFree(GetProcessHeap(), 0, lpData);
104 /* Get the size of a supported VT type (0 means unsupported) */
105 static DWORD SAFEARRAY_GetVTSize(VARTYPE vt)
107 switch (vt)
109 case VT_I1:
110 case VT_UI1: return sizeof(BYTE);
111 case VT_BOOL:
112 case VT_I2:
113 case VT_UI2: return sizeof(SHORT);
114 case VT_I4:
115 case VT_UI4:
116 case VT_R4:
117 case VT_ERROR: return sizeof(LONG);
118 case VT_R8:
119 case VT_I8:
120 case VT_UI8: return sizeof(LONG64);
121 case VT_INT:
122 case VT_UINT: return sizeof(INT);
123 case VT_INT_PTR:
124 case VT_UINT_PTR: return sizeof(UINT_PTR);
125 case VT_CY: return sizeof(CY);
126 case VT_DATE: return sizeof(DATE);
127 case VT_BSTR: return sizeof(BSTR);
128 case VT_DISPATCH: return sizeof(LPDISPATCH);
129 case VT_VARIANT: return sizeof(VARIANT);
130 case VT_UNKNOWN: return sizeof(LPUNKNOWN);
131 case VT_DECIMAL: return sizeof(DECIMAL);
132 /* Note: Return a non-zero size to indicate vt is valid. The actual size
133 * of a UDT is taken from the result of IRecordInfo_GetSize().
135 case VT_RECORD: return 32;
137 return 0;
140 /* Set the hidden data for an array */
141 static inline void SAFEARRAY_SetHiddenDWORD(SAFEARRAY* psa, DWORD dw)
143 /* Implementation data is stored in the 4 bytes before the header */
144 LPDWORD lpDw = (LPDWORD)psa;
145 lpDw[-1] = dw;
148 /* Get the hidden data from an array */
149 static inline DWORD SAFEARRAY_GetHiddenDWORD(SAFEARRAY* psa)
151 LPDWORD lpDw = (LPDWORD)psa;
152 return lpDw[-1];
155 /* Get the number of cells in a SafeArray */
156 static ULONG SAFEARRAY_GetCellCount(const SAFEARRAY *psa)
158 SAFEARRAYBOUND* psab = psa->rgsabound;
159 USHORT cCount = psa->cDims;
160 ULONG ulNumCells = 1;
162 while (cCount--)
164 /* This is a valid bordercase. See testcases. -Marcus */
165 if (!psab->cElements)
166 return 0;
167 ulNumCells *= psab->cElements;
168 psab++;
170 return ulNumCells;
173 /* Get the 0 based index of an index into a dimension */
174 static inline ULONG SAFEARRAY_GetDimensionIndex(SAFEARRAYBOUND *psab, ULONG ulIndex)
176 return ulIndex - psab->lLbound;
179 /* Get the size of a dimension in cells */
180 static inline ULONG SAFEARRAY_GetDimensionCells(SAFEARRAY *psa, ULONG ulDim)
182 ULONG size = psa->rgsabound[0].cElements;
184 while (ulDim)
186 size *= psa->rgsabound[ulDim].cElements;
187 ulDim--;
189 return size;
192 /* Allocate a descriptor for an array */
193 static HRESULT SAFEARRAY_AllocDescriptor(ULONG ulSize, SAFEARRAY **ppsaOut)
195 *ppsaOut = (SAFEARRAY*)((char*)SAFEARRAY_Malloc(ulSize + SAFEARRAY_HIDDEN_SIZE) + SAFEARRAY_HIDDEN_SIZE);
197 if (!*ppsaOut)
198 return E_UNEXPECTED;
200 return S_OK;
203 /* Set the features of an array */
204 static void SAFEARRAY_SetFeatures(VARTYPE vt, SAFEARRAY *psa)
206 /* Set the IID if we have one, otherwise set the type */
207 if (vt == VT_DISPATCH)
209 psa->fFeatures = FADF_HAVEIID;
210 SafeArraySetIID(psa, &IID_IDispatch);
212 else if (vt == VT_UNKNOWN)
214 psa->fFeatures = FADF_HAVEIID;
215 SafeArraySetIID(psa, &IID_IUnknown);
217 else if (vt == VT_RECORD)
218 psa->fFeatures = FADF_RECORD;
219 else
221 psa->fFeatures = FADF_HAVEVARTYPE;
222 SAFEARRAY_SetHiddenDWORD(psa, vt);
226 /* Create an array */
227 static SAFEARRAY* SAFEARRAY_Create(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound, ULONG ulSize)
229 SAFEARRAY *psa = NULL;
231 if (!rgsabound)
232 return NULL;
234 if (SUCCEEDED(SafeArrayAllocDescriptorEx(vt, cDims, &psa)))
236 switch (vt)
238 case VT_BSTR: psa->fFeatures |= FADF_BSTR; break;
239 case VT_UNKNOWN: psa->fFeatures |= FADF_UNKNOWN; break;
240 case VT_DISPATCH: psa->fFeatures |= FADF_DISPATCH; break;
241 case VT_VARIANT: psa->fFeatures |= FADF_VARIANT; break;
244 memcpy(psa->rgsabound, rgsabound, cDims * sizeof(SAFEARRAYBOUND));
246 if (ulSize)
247 psa->cbElements = ulSize;
249 if (FAILED(SafeArrayAllocData(psa)))
251 SafeArrayDestroyDescriptor(psa);
252 psa = NULL;
255 return psa;
258 /* Create an array as a vector */
259 static SAFEARRAY* SAFEARRAY_CreateVector(VARTYPE vt, LONG lLbound, ULONG cElements, ULONG ulSize)
261 SAFEARRAY *psa = NULL;
263 if (ulSize || (vt == VT_RECORD))
265 /* Allocate the header and data together */
266 if (SUCCEEDED(SAFEARRAY_AllocDescriptor(sizeof(SAFEARRAY) + ulSize * cElements, &psa)))
268 SAFEARRAY_SetFeatures(vt, psa);
270 psa->cDims = 1;
271 psa->fFeatures |= FADF_CREATEVECTOR;
272 psa->pvData = &psa[1]; /* Data follows the header */
273 psa->cbElements = ulSize;
274 psa->rgsabound[0].cElements = cElements;
275 psa->rgsabound[0].lLbound = lLbound;
277 switch (vt)
279 case VT_BSTR: psa->fFeatures |= FADF_BSTR; break;
280 case VT_UNKNOWN: psa->fFeatures |= FADF_UNKNOWN; break;
281 case VT_DISPATCH: psa->fFeatures |= FADF_DISPATCH; break;
282 case VT_VARIANT: psa->fFeatures |= FADF_VARIANT; break;
286 return psa;
289 /* Free data items in an array */
290 static HRESULT SAFEARRAY_DestroyData(SAFEARRAY *psa, ULONG ulStartCell)
292 if (psa->pvData && !(psa->fFeatures & FADF_DATADELETED))
294 ULONG ulCellCount = SAFEARRAY_GetCellCount(psa);
296 if (ulStartCell > ulCellCount) {
297 FIXME("unexpted ulcellcount %ld, start %ld\n",ulCellCount,ulStartCell);
298 return E_UNEXPECTED;
301 ulCellCount -= ulStartCell;
303 if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
305 LPUNKNOWN *lpUnknown = (LPUNKNOWN *)psa->pvData + ulStartCell * psa->cbElements;
307 while(ulCellCount--)
309 if (*lpUnknown)
310 IUnknown_Release(*lpUnknown);
311 lpUnknown++;
314 else if (psa->fFeatures & (FADF_RECORD))
316 IRecordInfo *lpRecInfo;
318 if (SUCCEEDED(SafeArrayGetRecordInfo(psa, &lpRecInfo)))
320 PBYTE pRecordData = (PBYTE)psa->pvData;
321 while(ulCellCount--)
323 IRecordInfo_RecordClear(lpRecInfo, pRecordData);
324 pRecordData += psa->cbElements;
326 IRecordInfo_Release(lpRecInfo);
329 else if (psa->fFeatures & FADF_BSTR)
331 BSTR* lpBstr = (BSTR*)psa->pvData + ulStartCell * psa->cbElements;
333 while(ulCellCount--)
335 if (*lpBstr)
336 SysFreeString(*lpBstr);
337 lpBstr++;
340 else if (psa->fFeatures & FADF_VARIANT)
342 VARIANT* lpVariant = (VARIANT*)psa->pvData + ulStartCell * psa->cbElements;
344 while(ulCellCount--)
346 VariantClear(lpVariant);
347 lpVariant++;
351 return S_OK;
354 /* Copy data items from one array to another */
355 static HRESULT SAFEARRAY_CopyData(SAFEARRAY *psa, SAFEARRAY *dest)
357 if (!psa->pvData || !dest->pvData || psa->fFeatures & FADF_DATADELETED)
358 return E_INVALIDARG;
359 else
361 ULONG ulCellCount = SAFEARRAY_GetCellCount(psa);
363 dest->fFeatures = (dest->fFeatures & FADF_CREATEVECTOR) |
364 (psa->fFeatures & ~(FADF_CREATEVECTOR|FADF_DATADELETED));
366 if (psa->fFeatures & FADF_VARIANT)
368 VARIANT* lpVariant = (VARIANT*)psa->pvData;
369 VARIANT* lpDest = (VARIANT*)dest->pvData;
371 while(ulCellCount--)
373 VariantCopy(lpDest, lpVariant);
374 lpVariant++;
375 lpDest++;
378 else if (psa->fFeatures & FADF_BSTR)
380 BSTR* lpBstr = (BSTR*)psa->pvData;
381 BSTR* lpDest = (BSTR*)dest->pvData;
383 while(ulCellCount--)
385 if (*lpBstr)
387 *lpDest = SysAllocStringByteLen((char*)*lpBstr, SysStringByteLen(*lpBstr));
388 if (!*lpDest)
389 return E_OUTOFMEMORY;
391 else
392 *lpDest = NULL;
393 lpBstr++;
394 lpDest++;
397 else
399 /* Copy the data over */
400 memcpy(dest->pvData, psa->pvData, ulCellCount * psa->cbElements);
402 if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
404 LPUNKNOWN *lpUnknown = (LPUNKNOWN *)dest->pvData;
406 while(ulCellCount--)
408 if (*lpUnknown)
409 IUnknown_AddRef(*lpUnknown);
410 lpUnknown++;
415 if (psa->fFeatures & FADF_RECORD)
417 IRecordInfo* pRecInfo = NULL;
419 SafeArrayGetRecordInfo(psa, &pRecInfo);
420 SafeArraySetRecordInfo(dest, pRecInfo);
422 if (pRecInfo)
424 /* Release because Get() adds a reference */
425 IRecordInfo_Release(pRecInfo);
428 else if (psa->fFeatures & FADF_HAVEIID)
430 GUID guid;
431 SafeArrayGetIID(psa, &guid);
432 SafeArraySetIID(dest, &guid);
434 else if (psa->fFeatures & FADF_HAVEVARTYPE)
436 SAFEARRAY_SetHiddenDWORD(dest, SAFEARRAY_GetHiddenDWORD(psa));
439 return S_OK;
442 /*************************************************************************
443 * SafeArrayAllocDescriptor (OLEAUT32.36)
445 * Allocate and initialise a descriptor for a SafeArray.
447 * PARAMS
448 * cDims [I] Number of dimensions of the array
449 * ppsaOut [O] Destination for new descriptor
451 * RETURNS
452 * Success: S_OK. ppsaOut is filled with a newly allocated descriptor.
453 * Failure: An HRESULT error code indicating the error.
455 * NOTES
456 * See SafeArray.
458 HRESULT WINAPI SafeArrayAllocDescriptor(UINT cDims, SAFEARRAY **ppsaOut)
460 LONG allocSize;
462 TRACE("(%d,%p)\n", cDims, ppsaOut);
464 if (!cDims || cDims >= 0x10000) /* Maximum 65535 dimensions */
465 return E_INVALIDARG;
467 if (!ppsaOut)
468 return E_POINTER;
470 /* We need enough space for the header and its bounds */
471 allocSize = sizeof(SAFEARRAY) + sizeof(SAFEARRAYBOUND) * (cDims - 1);
473 if (FAILED(SAFEARRAY_AllocDescriptor(allocSize, ppsaOut)))
474 return E_UNEXPECTED;
476 (*ppsaOut)->cDims = cDims;
478 TRACE("(%d): %lu bytes allocated for descriptor.\n", cDims, allocSize);
479 return S_OK;
482 /*************************************************************************
483 * SafeArrayAllocDescriptorEx (OLEAUT32.41)
485 * Allocate and initialise a descriptor for a SafeArray of a given type.
487 * PARAMS
488 * vt [I] The type of items to store in the array
489 * cDims [I] Number of dimensions of the array
490 * ppsaOut [O] Destination for new descriptor
492 * RETURNS
493 * Success: S_OK. ppsaOut is filled with a newly allocated descriptor.
494 * Failure: An HRESULT error code indicating the error.
496 * NOTES
497 * - This function does not chack that vt is an allowed VARTYPE.
498 * - Unlike SafeArrayAllocDescriptor(), vt is associated with the array.
499 * See SafeArray.
501 HRESULT WINAPI SafeArrayAllocDescriptorEx(VARTYPE vt, UINT cDims, SAFEARRAY **ppsaOut)
503 ULONG cbElements;
504 HRESULT hRet = E_UNEXPECTED;
506 TRACE("(%d->%s,%d,%p)\n", vt, debugstr_vt(vt), cDims, ppsaOut);
508 cbElements = SAFEARRAY_GetVTSize(vt);
509 if (!cbElements)
510 WARN("Creating a descriptor with an invalid VARTYPE!\n");
512 hRet = SafeArrayAllocDescriptor(cDims, ppsaOut);
514 if (SUCCEEDED(hRet))
516 SAFEARRAY_SetFeatures(vt, *ppsaOut);
517 (*ppsaOut)->cbElements = cbElements;
519 return hRet;
522 /*************************************************************************
523 * SafeArrayAllocData (OLEAUT32.37)
525 * Allocate the data area of a SafeArray.
527 * PARAMS
528 * psa [I] SafeArray to allocate the data area of.
530 * RETURNS
531 * Success: S_OK. The data area is allocated and initialised.
532 * Failure: An HRESULT error code indicating the error.
534 * NOTES
535 * See SafeArray.
537 HRESULT WINAPI SafeArrayAllocData(SAFEARRAY *psa)
539 HRESULT hRet = E_INVALIDARG;
541 TRACE("(%p)\n", psa);
543 if (psa)
545 ULONG ulSize = SAFEARRAY_GetCellCount(psa);
547 hRet = E_OUTOFMEMORY;
549 if (psa->cbElements)
551 psa->pvData = SAFEARRAY_Malloc(ulSize * psa->cbElements);
553 if (psa->pvData)
555 hRet = S_OK;
556 TRACE("%lu bytes allocated for data at %p (%lu objects).\n",
557 ulSize * psa->cbElements, psa->pvData, ulSize);
561 return hRet;
564 /*************************************************************************
565 * SafeArrayCreate (OLEAUT32.15)
567 * Create a new SafeArray.
569 * PARAMS
570 * vt [I] Type to store in the safe array
571 * cDims [I] Number of array dimensions
572 * rgsabound [I] Bounds of the array dimensions
574 * RETURNS
575 * Success: A pointer to a new array object.
576 * Failure: NULL, if any parameter is invalid or memory allocation fails.
578 * NOTES
579 * Win32 allows arrays with 0 sized dimensions. This bug is not reproduced
580 * in the Wine implementation.
581 * See SafeArray.
583 SAFEARRAY* WINAPI SafeArrayCreate(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound)
585 TRACE("(%d->%s,%d,%p)\n", vt, debugstr_vt(vt), cDims, rgsabound);
587 if (vt == VT_RECORD)
588 return NULL;
590 return SAFEARRAY_Create(vt, cDims, rgsabound, 0);
593 /*************************************************************************
594 * SafeArrayCreateEx (OLEAUT32.15)
596 * Create a new SafeArray.
598 * PARAMS
599 * vt [I] Type to store in the safe array
600 * cDims [I] Number of array dimensions
601 * rgsabound [I] Bounds of the array dimensions
602 * pvExtra [I] Extra data
604 * RETURNS
605 * Success: A pointer to a new array object.
606 * Failure: NULL, if any parameter is invalid or memory allocation fails.
608 * NOTES
609 * See SafeArray.
611 SAFEARRAY* WINAPI SafeArrayCreateEx(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound, LPVOID pvExtra)
613 ULONG ulSize = 0;
614 IRecordInfo* iRecInfo = (IRecordInfo*)pvExtra;
615 SAFEARRAY* psa;
617 TRACE("(%d->%s,%d,%p,%p)\n", vt, debugstr_vt(vt), cDims, rgsabound, pvExtra);
619 if (vt == VT_RECORD)
621 if (!iRecInfo)
622 return NULL;
623 IRecordInfo_GetSize(iRecInfo, &ulSize);
625 psa = SAFEARRAY_Create(vt, cDims, rgsabound, ulSize);
627 if (pvExtra)
629 switch(vt)
631 case VT_RECORD:
632 SafeArraySetRecordInfo(psa, pvExtra);
633 break;
634 case VT_UNKNOWN:
635 case VT_DISPATCH:
636 SafeArraySetIID(psa, pvExtra);
637 break;
640 return psa;
643 /************************************************************************
644 * SafeArrayCreateVector (OLEAUT32.411)
646 * Create a one dimensional, contigous SafeArray.
648 * PARAMS
649 * vt [I] Type to store in the safe array
650 * lLbound [I] Lower bound of the array
651 * cElements [I] Number of elements in the array
653 * RETURNS
654 * Success: A pointer to a new array object.
655 * Failure: NULL, if any parameter is invalid or memory allocation fails.
657 * NOTES
658 * See SafeArray.
660 SAFEARRAY* WINAPI SafeArrayCreateVector(VARTYPE vt, LONG lLbound, ULONG cElements)
662 TRACE("(%d->%s,%ld,%ld\n", vt, debugstr_vt(vt), lLbound, cElements);
664 if (vt == VT_RECORD)
665 return NULL;
667 return SAFEARRAY_CreateVector(vt, lLbound, cElements, SAFEARRAY_GetVTSize(vt));
670 /************************************************************************
671 * SafeArrayCreateVectorEx (OLEAUT32.411)
673 * Create a one dimensional, contigous SafeArray.
675 * PARAMS
676 * vt [I] Type to store in the safe array
677 * lLbound [I] Lower bound of the array
678 * cElements [I] Number of elements in the array
679 * pvExtra [I] Extra data
681 * RETURNS
682 * Success: A pointer to a new array object.
683 * Failure: NULL, if any parameter is invalid or memory allocation fails.
685 * NOTES
686 * See SafeArray.
688 SAFEARRAY* WINAPI SafeArrayCreateVectorEx(VARTYPE vt, LONG lLbound, ULONG cElements, LPVOID pvExtra)
690 ULONG ulSize;
691 IRecordInfo* iRecInfo = (IRecordInfo*)pvExtra;
692 SAFEARRAY* psa;
694 TRACE("(%d->%s,%ld,%ld,%p\n", vt, debugstr_vt(vt), lLbound, cElements, pvExtra);
696 if (vt == VT_RECORD)
698 if (!iRecInfo)
699 return NULL;
700 IRecordInfo_GetSize(iRecInfo, &ulSize);
702 else
703 ulSize = SAFEARRAY_GetVTSize(vt);
705 psa = SAFEARRAY_CreateVector(vt, lLbound, cElements, ulSize);
707 if (pvExtra)
709 switch(vt)
711 case VT_RECORD:
712 SafeArraySetRecordInfo(psa, iRecInfo);
713 break;
714 case VT_UNKNOWN:
715 case VT_DISPATCH:
716 SafeArraySetIID(psa, pvExtra);
717 break;
720 return psa;
723 /*************************************************************************
724 * SafeArrayDestroyDescriptor (OLEAUT32.38)
726 * Destroy a SafeArray.
728 * PARAMS
729 * psa [I] SafeArray to destroy.
731 * RETURNS
732 * Success: S_OK. The resources used by the array are freed.
733 * Failure: An HRESULT error code indicating the error.
735 * NOTES
736 * See SafeArray.
738 HRESULT WINAPI SafeArrayDestroyDescriptor(SAFEARRAY *psa)
740 TRACE("(%p)\n", psa);
742 if (psa)
744 LPVOID lpv = (char*)psa - SAFEARRAY_HIDDEN_SIZE;
746 if (psa->cLocks)
747 return DISP_E_ARRAYISLOCKED; /* Can't destroy a locked array */
749 if (psa->fFeatures & FADF_RECORD)
750 SafeArraySetRecordInfo(psa, NULL);
752 if (psa->fFeatures & FADF_CREATEVECTOR &&
753 !(psa->fFeatures & FADF_DATADELETED))
754 SAFEARRAY_DestroyData(psa, 0); /* Data not previously deleted */
756 if (!SAFEARRAY_Free(lpv))
757 return E_UNEXPECTED;
759 return S_OK;
762 /*************************************************************************
763 * SafeArrayLock (OLEAUT32.21)
765 * Increment the lock counter of a SafeArray.
767 * PARAMS
768 * psa [O] SafeArray to lock
770 * RETURNS
771 * Success: S_OK. The array lock is incremented.
772 * Failure: E_INVALIDARG if psa is NULL, or E_UNEXPECTED if too many locks
773 * are held on the array at once.
775 * NOTES
776 * In Win32 these locks are not thread safe.
777 * See SafeArray.
779 HRESULT WINAPI SafeArrayLock(SAFEARRAY *psa)
781 ULONG ulLocks;
783 TRACE("(%p)\n", psa);
785 if (!psa)
786 return E_INVALIDARG;
788 ulLocks = InterlockedIncrement(&psa->cLocks);
790 if (ulLocks > 0xffff) /* Maximum of 16384 locks at a time */
792 WARN("Out of locks!\n");
793 InterlockedDecrement(&psa->cLocks);
794 return E_UNEXPECTED;
796 return S_OK;
799 /*************************************************************************
800 * SafeArrayUnlock (OLEAUT32.22)
802 * Decrement the lock counter of a SafeArray.
804 * PARAMS
805 * psa [O] SafeArray to unlock
807 * RETURNS
808 * Success: S_OK. The array lock is decremented.
809 * Failure: E_INVALIDARG if psa is NULL, or E_UNEXPECTED if no locks are
810 * held on the array.
812 * NOTES
813 * See SafeArray.
815 HRESULT WINAPI SafeArrayUnlock(SAFEARRAY *psa)
817 TRACE("(%p)\n", psa);
819 if (!psa)
820 return E_INVALIDARG;
822 if ((LONG)InterlockedDecrement(&psa->cLocks) < 0)
824 WARN("Unlocked but no lock held!\n");
825 InterlockedIncrement(&psa->cLocks);
826 return E_UNEXPECTED;
828 return S_OK;
831 /*************************************************************************
832 * SafeArrayPutElement (OLEAUT32.26)
834 * Put an item into a SafeArray.
836 * PARAMS
837 * psa [I] SafeArray to insert into
838 * rgIndices [I] Indices to insert at
839 * pvData [I] Data to insert
841 * RETURNS
842 * Success: S_OK. The item is inserted
843 * Failure: An HRESULT error code indicating the error.
845 * NOTES
846 * See SafeArray.
848 HRESULT WINAPI SafeArrayPutElement(SAFEARRAY *psa, LONG *rgIndices, void *pvData)
850 HRESULT hRet;
852 TRACE("(%p,%p,%p)\n", psa, rgIndices, pvData);
854 if (!psa || !rgIndices)
855 return E_INVALIDARG;
857 if (!pvData)
859 ERR("Invalid pvData would crash under Win32!\n");
860 return E_INVALIDARG;
863 hRet = SafeArrayLock(psa);
865 if (SUCCEEDED(hRet))
867 PVOID lpvDest;
869 hRet = SafeArrayPtrOfIndex(psa, rgIndices, &lpvDest);
871 if (SUCCEEDED(hRet))
873 if (psa->fFeatures & FADF_VARIANT)
875 VARIANT* lpVariant = (VARIANT*)pvData;
876 VARIANT* lpDest = (VARIANT*)lpvDest;
878 VariantClear(lpDest);
879 VariantCopy(lpDest, lpVariant);
881 else if (psa->fFeatures & FADF_BSTR)
883 BSTR lpBstr = (BSTR)pvData;
884 BSTR* lpDest = (BSTR*)lpvDest;
886 if (*lpDest)
887 SysFreeString(*lpDest);
889 if (lpBstr)
891 *lpDest = SysAllocStringByteLen((char*)lpBstr, SysStringByteLen(lpBstr));
892 if (!*lpDest)
893 hRet = E_OUTOFMEMORY;
895 else
896 *lpDest = NULL;
898 else
900 if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
902 LPUNKNOWN lpUnknown = (LPUNKNOWN)pvData;
903 LPUNKNOWN *lpDest = (LPUNKNOWN *)lpvDest;
905 if (lpUnknown)
906 IUnknown_AddRef(lpUnknown);
907 if (*lpDest)
908 IUnknown_Release(*lpDest);
909 *lpDest = lpUnknown;
910 } else {
911 /* Copy the data over */
912 memcpy(lpvDest, pvData, psa->cbElements);
916 SafeArrayUnlock(psa);
918 return hRet;
922 /*************************************************************************
923 * SafeArrayGetElement (OLEAUT32.25)
925 * Get an item from a SafeArray.
927 * PARAMS
928 * psa [I] SafeArray to get from
929 * rgIndices [I] Indices to get from
930 * pvData [O] Destination for data
932 * RETURNS
933 * Success: S_OK. The item data is returned in pvData.
934 * Failure: An HRESULT error code indicating the error.
936 * NOTES
937 * See SafeArray.
939 HRESULT WINAPI SafeArrayGetElement(SAFEARRAY *psa, LONG *rgIndices, void *pvData)
941 HRESULT hRet;
943 TRACE("(%p,%p,%p)\n", psa, rgIndices, pvData);
945 if (!psa || !rgIndices || !pvData)
946 return E_INVALIDARG;
948 hRet = SafeArrayLock(psa);
950 if (SUCCEEDED(hRet))
952 PVOID lpvSrc;
954 hRet = SafeArrayPtrOfIndex(psa, rgIndices, &lpvSrc);
956 if (SUCCEEDED(hRet))
958 if (psa->fFeatures & FADF_VARIANT)
960 VARIANT* lpVariant = (VARIANT*)lpvSrc;
961 VARIANT* lpDest = (VARIANT*)pvData;
963 VariantCopy(lpDest, lpVariant);
965 else if (psa->fFeatures & FADF_BSTR)
967 BSTR* lpBstr = (BSTR*)lpvSrc;
968 BSTR* lpDest = (BSTR*)pvData;
970 if (*lpBstr)
972 *lpDest = SysAllocStringByteLen((char*)*lpBstr, SysStringByteLen(*lpBstr));
973 if (!*lpBstr)
974 hRet = E_OUTOFMEMORY;
976 else
977 *lpDest = NULL;
979 else
981 if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
983 LPUNKNOWN *lpUnknown = (LPUNKNOWN *)lpvSrc;
985 if (*lpUnknown)
986 IUnknown_AddRef(*lpUnknown);
988 /* Copy the data over */
989 memcpy(pvData, lpvSrc, psa->cbElements);
992 SafeArrayUnlock(psa);
994 return hRet;
997 /*************************************************************************
998 * SafeArrayGetUBound (OLEAUT32.19)
1000 * Get the upper bound for a given SafeArray dimension
1002 * PARAMS
1003 * psa [I] Array to get dimension upper bound from
1004 * nDim [I] The dimension number to get the upper bound of
1005 * plUbound [O] Destination for the upper bound
1007 * RETURNS
1008 * Success: S_OK. plUbound contains the dimensions upper bound.
1009 * Failure: An HRESULT error code indicating the error.
1011 * NOTES
1012 * See SafeArray.
1014 HRESULT WINAPI SafeArrayGetUBound(SAFEARRAY *psa, UINT nDim, LONG *plUbound)
1016 TRACE("(%p,%d,%p)\n", psa, nDim, plUbound);
1018 if (!psa || !plUbound)
1019 return E_INVALIDARG;
1021 if(!nDim || nDim > psa->cDims)
1022 return DISP_E_BADINDEX;
1024 *plUbound = psa->rgsabound[nDim - 1].lLbound +
1025 psa->rgsabound[nDim - 1].cElements - 1;
1027 return S_OK;
1030 /*************************************************************************
1031 * SafeArrayGetLBound (OLEAUT32.20)
1033 * Get the lower bound for a given SafeArray dimension
1035 * PARAMS
1036 * psa [I] Array to get dimension lower bound from
1037 * nDim [I] The dimension number to get the lowe bound of
1038 * plLbound [O] Destination for the lower bound
1040 * RETURNS
1041 * Success: S_OK. plUbound contains the dimensions lower bound.
1042 * Failure: An HRESULT error code indicating the error.
1044 * NOTES
1045 * See SafeArray.
1047 HRESULT WINAPI SafeArrayGetLBound(SAFEARRAY *psa, UINT nDim, LONG *plLbound)
1049 TRACE("(%p,%d,%p)\n", psa, nDim, plLbound);
1051 if (!psa || !plLbound)
1052 return E_INVALIDARG;
1054 if(!nDim || nDim > psa->cDims)
1055 return DISP_E_BADINDEX;
1057 *plLbound = psa->rgsabound[nDim - 1].lLbound;
1058 return S_OK;
1061 /*************************************************************************
1062 * SafeArrayGetDim (OLEAUT32.17)
1064 * Get the number of dimensions in a SafeArray.
1066 * PARAMS
1067 * psa [I] Array to get the dimensions of
1069 * RETURNS
1070 * The number of array dimensions in psa, or 0 if psa is NULL.
1072 * NOTES
1073 * See SafeArray.
1075 UINT WINAPI SafeArrayGetDim(SAFEARRAY *psa)
1077 TRACE("(%p) returning %ld\n", psa, psa ? psa->cDims : 0ul);
1078 return psa ? psa->cDims : 0;
1081 /*************************************************************************
1082 * SafeArrayGetElemsize (OLEAUT32.18)
1084 * Get the size of an element in a SafeArray.
1086 * PARAMS
1087 * psa [I] Array to get the element size from
1089 * RETURNS
1090 * The size of a single element in psa, or 0 if psa is NULL.
1092 * NOTES
1093 * See SafeArray.
1095 UINT WINAPI SafeArrayGetElemsize(SAFEARRAY *psa)
1097 TRACE("(%p) returning %ld\n", psa, psa ? psa->cbElements : 0ul);
1098 return psa ? psa->cbElements : 0;
1101 /*************************************************************************
1102 * SafeArrayAccessData (OLEAUT32.23)
1104 * Lock a SafeArray and return a pointer to its data.
1106 * PARAMS
1107 * psa [I] Array to get the data pointer from
1108 * ppvData [O] Destination for the arrays data pointer
1110 * RETURNS
1111 * Success: S_OK. ppvData contains the arrays data pointer, and the array
1112 * is locked.
1113 * Failure: An HRESULT error code indicating the error.
1115 * NOTES
1116 * See SafeArray.
1118 HRESULT WINAPI SafeArrayAccessData(SAFEARRAY *psa, void **ppvData)
1120 TRACE("(%p,%p)\n", psa, ppvData);
1122 if(!psa || !ppvData)
1123 return E_INVALIDARG;
1125 if (SUCCEEDED(SafeArrayLock(psa)))
1127 *ppvData = psa->pvData;
1128 return S_OK;
1130 *ppvData = NULL;
1131 return E_UNEXPECTED;
1135 /*************************************************************************
1136 * SafeArrayUnaccessData (OLEAUT32.24)
1138 * Unlock a SafeArray after accessing its data.
1140 * PARAMS
1141 * psa [I] Array to unlock
1143 * RETURNS
1144 * Success: S_OK. The array is unlocked.
1145 * Failure: An HRESULT error code indicating the error.
1147 * NOTES
1148 * See SafeArray.
1150 HRESULT WINAPI SafeArrayUnaccessData(SAFEARRAY *psa)
1152 TRACE("(%p)\n", psa);
1153 return SafeArrayUnlock(psa);
1156 /************************************************************************
1157 * SafeArrayPtrOfIndex (OLEAUT32.148)
1159 * Get the address of an item in a SafeArray.
1161 * PARAMS
1162 * psa [I] Array to get the items address from
1163 * rgIndices [I] Index of the item in the array
1164 * ppvData [O] Destination for item address
1166 * RETURNS
1167 * Success: S_OK. ppvData contains a pointer to the item.
1168 * Failure: An HRESULT error code indicating the error.
1170 * NOTES
1171 * This function does not lock the array.
1173 * NOTES
1174 * See SafeArray.
1176 HRESULT WINAPI SafeArrayPtrOfIndex(SAFEARRAY *psa, LONG *rgIndices, void **ppvData)
1178 USHORT dim;
1179 ULONG cell = 0, dimensionSize = 1;
1180 SAFEARRAYBOUND* psab;
1181 LONG c1;
1183 TRACE("(%p,%p,%p)\n", psa, rgIndices, ppvData);
1185 /* The general formula for locating the cell number of an entry in an n
1186 * dimensional array (where cn = coordinate in dimension dn) is:
1188 * c1 + c2 * sizeof(d1) + c3 * sizeof(d2) ... + cn * sizeof(c(n-1))
1190 * We calculate the size of the last dimension at each step through the
1191 * dimensions to avoid recursing to calculate the last dimensions size.
1193 if (!psa || !rgIndices || !ppvData)
1194 return E_INVALIDARG;
1196 psab = psa->rgsabound;
1197 c1 = *rgIndices++;
1199 if (c1 < psab->lLbound || c1 >= psab->lLbound + (LONG)psab->cElements)
1200 return DISP_E_BADINDEX; /* Initial index out of bounds */
1202 for (dim = 1; dim < psa->cDims; dim++)
1204 dimensionSize *= psab->cElements;
1206 psab++;
1208 if (!psab->cElements ||
1209 *rgIndices < psab->lLbound ||
1210 *rgIndices >= psab->lLbound + (LONG)psab->cElements)
1211 return DISP_E_BADINDEX; /* Index out of bounds */
1213 cell += (*rgIndices - psab->lLbound) * dimensionSize;
1214 rgIndices++;
1217 cell += (c1 - psa->rgsabound[0].lLbound);
1219 *ppvData = (char*)psa->pvData + cell * psa->cbElements;
1220 return S_OK;
1223 /************************************************************************
1224 * SafeArrayDestroyData (OLEAUT32.39)
1226 * Destroy the data associated with a SafeArray.
1228 * PARAMS
1229 * psa [I] Array to delete the data from
1231 * RETURNS
1232 * Success: S_OK. All items and the item data are freed.
1233 * Failure: An HRESULT error code indicating the error.
1235 * NOTES
1236 * See SafeArray.
1238 HRESULT WINAPI SafeArrayDestroyData(SAFEARRAY *psa)
1240 TRACE("(%p)\n", psa);
1242 if (!psa)
1243 return E_INVALIDARG;
1245 if (psa->cLocks)
1246 return DISP_E_ARRAYISLOCKED; /* Can't delete a locked array */
1248 if (psa->pvData)
1250 /* Delete the actual item data */
1251 if (FAILED(SAFEARRAY_DestroyData(psa, 0)))
1252 return E_UNEXPECTED;
1254 /* If this is not a vector, free the data memory block */
1255 if (!(psa->fFeatures & FADF_CREATEVECTOR))
1257 if (!SAFEARRAY_Free(psa->pvData))
1258 return E_UNEXPECTED;
1259 psa->pvData = NULL;
1261 else
1262 psa->fFeatures |= FADF_DATADELETED; /* Mark the data deleted */
1265 return S_OK;
1268 /************************************************************************
1269 * SafeArrayCopyData (OLEAUT32.412)
1271 * Copy all data from one SafeArray to another.
1273 * PARAMS
1274 * psaSource [I] Source for copy
1275 * psaTarget [O] Destination for copy
1277 * RETURNS
1278 * Success: S_OK. psaTarget contains a copy of psaSource.
1279 * Failure: An HRESULT error code indicating the error.
1281 * NOTES
1282 * The two arrays must have the same number of dimensions and elements.
1284 * NOTES
1285 * See SafeArray.
1287 HRESULT WINAPI SafeArrayCopyData(SAFEARRAY *psaSource, SAFEARRAY *psaTarget)
1289 int dim;
1291 TRACE("(%p,%p)\n", psaSource, psaTarget);
1293 if (!psaSource || !psaTarget ||
1294 psaSource->cDims != psaTarget->cDims ||
1295 psaSource->cbElements != psaTarget->cbElements)
1296 return E_INVALIDARG;
1298 /* Each dimension must be the same size */
1299 for (dim = psaSource->cDims - 1; dim >= 0 ; dim--)
1300 if (psaSource->rgsabound[dim].cElements !=
1301 psaTarget->rgsabound[dim].cElements)
1302 return E_INVALIDARG;
1304 if (SUCCEEDED(SAFEARRAY_DestroyData(psaTarget, 0)) &&
1305 SUCCEEDED(SAFEARRAY_CopyData(psaSource, psaTarget)))
1306 return S_OK;
1307 return E_UNEXPECTED;
1310 /************************************************************************
1311 * SafeArrayDestroy (OLEAUT32.16)
1313 * Destroy a SafeArray.
1315 * PARAMS
1316 * psa [I] Array to destroy
1318 * RETURNS
1319 * Success: S_OK. All resources used by the array are freed.
1320 * Failure: An HRESULT error code indicating the error.
1322 * NOTES
1323 * See SafeArray.
1325 HRESULT WINAPI SafeArrayDestroy(SAFEARRAY *psa)
1327 TRACE("(%p)\n", psa);
1329 if(!psa)
1330 return E_INVALIDARG;
1332 if(psa->cLocks > 0)
1333 return DISP_E_ARRAYISLOCKED;
1335 /* Native doesn't check to see if the free succeeds */
1336 SafeArrayDestroyData(psa);
1337 SafeArrayDestroyDescriptor(psa);
1338 return S_OK;
1341 /************************************************************************
1342 * SafeArrayCopy (OLEAUT32.27)
1344 * Make a duplicate of a SafeArray.
1346 * PARAMS
1347 * psa [I] Source for copy
1348 * ppsaOut [O] Destination for new copy
1350 * RETURNS
1351 * Success: S_OK. ppsaOut contains a copy of the array.
1352 * Failure: An HRESULT error code indicating the error.
1354 * NOTES
1355 * See SafeArray.
1357 HRESULT WINAPI SafeArrayCopy(SAFEARRAY *psa, SAFEARRAY **ppsaOut)
1359 HRESULT hRet;
1361 TRACE("(%p,%p)\n", psa, ppsaOut);
1363 if (!ppsaOut)
1364 return E_INVALIDARG;
1366 *ppsaOut = NULL;
1368 if (!psa)
1369 return S_OK; /* Handles copying of NULL arrays */
1371 if (psa->fFeatures & (FADF_RECORD|FADF_HAVEIID|FADF_HAVEVARTYPE))
1373 VARTYPE vt;
1374 if (FAILED(SafeArrayGetVartype(psa, &vt)))
1375 hRet = E_UNEXPECTED;
1376 else
1377 hRet = SafeArrayAllocDescriptorEx(vt, psa->cDims, ppsaOut);
1379 else
1381 hRet = SafeArrayAllocDescriptor(psa->cDims, ppsaOut);
1382 if (SUCCEEDED(hRet))
1384 (*ppsaOut)->fFeatures = psa->fFeatures & ~FADF_CREATEVECTOR;
1385 (*ppsaOut)->cbElements = psa->cbElements;
1389 if (SUCCEEDED(hRet))
1391 /* Copy dimension bounds */
1392 memcpy((*ppsaOut)->rgsabound, psa->rgsabound, psa->cDims * sizeof(SAFEARRAYBOUND));
1394 (*ppsaOut)->pvData = SAFEARRAY_Malloc(SAFEARRAY_GetCellCount(psa) * psa->cbElements);
1396 if ((*ppsaOut)->pvData)
1398 hRet = SAFEARRAY_CopyData(psa, *ppsaOut);
1400 if (SUCCEEDED(hRet))
1401 return hRet;
1403 SAFEARRAY_Free((*ppsaOut)->pvData);
1405 SafeArrayDestroyDescriptor(*ppsaOut);
1407 *ppsaOut = NULL;
1408 return hRet;
1411 /************************************************************************
1412 * SafeArrayRedim (OLEAUT32.40)
1414 * Changes the characteristics of the last dimension of a SafeArray
1416 * PARAMS
1417 * psa [I] Array to change
1418 * psabound [I] New bound details for the last dimension
1420 * RETURNS
1421 * Success: S_OK. psa is updated to reflect the new bounds.
1422 * Failure: An HRESULT error code indicating the error.
1424 * NOTES
1425 * See SafeArray.
1427 HRESULT WINAPI SafeArrayRedim(SAFEARRAY *psa, SAFEARRAYBOUND *psabound)
1429 SAFEARRAYBOUND *oldBounds;
1431 TRACE("(%p,%p)\n", psa, psabound);
1433 if (!psa || psa->fFeatures & FADF_FIXEDSIZE || !psabound)
1434 return E_INVALIDARG;
1436 if (psa->cLocks > 0)
1437 return DISP_E_ARRAYISLOCKED;
1439 if (FAILED(SafeArrayLock(psa)))
1440 return E_UNEXPECTED;
1442 oldBounds = &psa->rgsabound[psa->cDims - 1];
1443 oldBounds->lLbound = psabound->lLbound;
1445 if (psabound->cElements != oldBounds->cElements)
1447 if (psabound->cElements < oldBounds->cElements)
1449 /* Shorten the final dimension. */
1450 ULONG ulStartCell = psa->cDims == 1 ? 0 : SAFEARRAY_GetDimensionCells(psa, psa->cDims - 1);
1452 ulStartCell += psabound->cElements;
1453 SAFEARRAY_DestroyData(psa, ulStartCell);
1455 else
1457 /* Lengthen the final dimension */
1458 ULONG ulOldSize, ulNewSize;
1459 PVOID pvNewData;
1461 ulOldSize = SAFEARRAY_GetCellCount(psa) * psa->cbElements;
1462 if (ulOldSize)
1463 ulNewSize = (ulOldSize / oldBounds->cElements) * psabound->cElements;
1464 else {
1465 int oldelems = oldBounds->cElements;
1466 oldBounds->cElements = psabound->cElements;
1467 ulNewSize = SAFEARRAY_GetCellCount(psa) * psa->cbElements;
1468 oldBounds->cElements = oldelems;
1471 if (!(pvNewData = SAFEARRAY_Malloc(ulNewSize)))
1473 SafeArrayUnlock(psa);
1474 return E_UNEXPECTED;
1477 memcpy(pvNewData, psa->pvData, ulOldSize);
1478 SAFEARRAY_Free(psa->pvData);
1479 psa->pvData = pvNewData;
1481 oldBounds->cElements = psabound->cElements;
1484 SafeArrayUnlock(psa);
1485 return S_OK;
1488 /************************************************************************
1489 * SafeArrayGetVartype (OLEAUT32.77)
1491 * Get the type of the items in a SafeArray.
1493 * PARAMS
1494 * psa [I] Array to get the type from
1495 * pvt [O] Destination for the type
1497 * RETURNS
1498 * Success: S_OK. pvt contains the type of the items.
1499 * Failure: An HRESULT error code indicating the error.
1501 * NOTES
1502 * See SafeArray.
1504 HRESULT WINAPI SafeArrayGetVartype(SAFEARRAY* psa, VARTYPE* pvt)
1506 TRACE("(%p,%p)\n", psa, pvt);
1508 if (!psa || !pvt)
1509 return E_INVALIDARG;
1511 if (psa->fFeatures & FADF_RECORD)
1512 *pvt = VT_RECORD;
1513 else if (psa->fFeatures & FADF_HAVEIID)
1514 *pvt = VT_UNKNOWN;
1515 else if (psa->fFeatures & FADF_HAVEVARTYPE)
1517 VARTYPE vt = SAFEARRAY_GetHiddenDWORD(psa);
1518 *pvt = vt;
1520 else
1521 return E_INVALIDARG;
1523 return S_OK;
1526 /************************************************************************
1527 * SafeArraySetRecordInfo (OLEAUT32.@)
1529 * Set the record info for a SafeArray.
1531 * PARAMS
1532 * psa [I] Array to set the record info for
1533 * pRinfo [I] Record info
1535 * RETURNS
1536 * Success: S_OK. The record info is stored with the array.
1537 * Failure: An HRESULT error code indicating the error.
1539 * NOTES
1540 * See SafeArray.
1542 HRESULT WINAPI SafeArraySetRecordInfo(SAFEARRAY *psa, IRecordInfo *pRinfo)
1544 IRecordInfo** dest = (IRecordInfo**)psa;
1546 TRACE("(%p,%p)\n", psa, pRinfo);
1548 if (!psa || !(psa->fFeatures & FADF_RECORD))
1549 return E_INVALIDARG;
1551 if (pRinfo)
1552 IRecordInfo_AddRef(pRinfo);
1554 if (dest[-1])
1555 IRecordInfo_Release(dest[-1]);
1557 dest[-1] = pRinfo;
1558 return S_OK;
1561 /************************************************************************
1562 * SafeArrayGetRecordInfo (OLEAUT32.@)
1564 * Get the record info from a SafeArray.
1566 * PARAMS
1567 * psa [I] Array to get the record info from
1568 * pRinfo [O] Destination for the record info
1570 * RETURNS
1571 * Success: S_OK. pRinfo contains the record info, or NULL if there was none.
1572 * Failure: An HRESULT error code indicating the error.
1574 * NOTES
1575 * See SafeArray.
1577 HRESULT WINAPI SafeArrayGetRecordInfo(SAFEARRAY *psa, IRecordInfo **pRinfo)
1579 IRecordInfo** src = (IRecordInfo**)psa;
1581 TRACE("(%p,%p)\n", psa, pRinfo);
1583 if (!psa || !pRinfo || !(psa->fFeatures & FADF_RECORD))
1584 return E_INVALIDARG;
1586 *pRinfo = src[-1];
1588 if (*pRinfo)
1589 IRecordInfo_AddRef(*pRinfo);
1590 return S_OK;
1593 /************************************************************************
1594 * SafeArraySetIID (OLEAUT32.@)
1596 * Set the IID for a SafeArray.
1598 * PARAMS
1599 * psa [I] Array to set the IID from
1600 * guid [I] IID
1602 * RETURNS
1603 * Success: S_OK. The IID is stored with the array
1604 * Failure: An HRESULT error code indicating the error.
1606 * NOTES
1607 * See SafeArray.
1609 HRESULT WINAPI SafeArraySetIID(SAFEARRAY *psa, REFGUID guid)
1611 GUID* dest = (GUID*)psa;
1613 TRACE("(%p,%s)\n", psa, debugstr_guid(guid));
1615 if (!psa || !guid || !(psa->fFeatures & FADF_HAVEIID))
1616 return E_INVALIDARG;
1618 dest[-1] = *guid;
1619 return S_OK;
1622 /************************************************************************
1623 * SafeArrayGetIID (OLEAUT32.@)
1625 * Get the IID from a SafeArray.
1627 * PARAMS
1628 * psa [I] Array to get the ID from
1629 * pGuid [O] Destination for the IID
1631 * RETURNS
1632 * Success: S_OK. pRinfo contains the IID, or NULL if there was none.
1633 * Failure: An HRESULT error code indicating the error.
1635 * NOTES
1636 * See SafeArray.
1638 HRESULT WINAPI SafeArrayGetIID(SAFEARRAY *psa, GUID *pGuid)
1640 GUID* src = (GUID*)psa;
1642 TRACE("(%p,%p)\n", psa, pGuid);
1644 if (!psa || !pGuid || !(psa->fFeatures & FADF_HAVEIID))
1645 return E_INVALIDARG;
1647 *pGuid = src[-1];
1648 return S_OK;
1651 /************************************************************************
1652 * VectorFromBstr (OLEAUT32.@)
1654 * Create a SafeArray Vector from the bytes of a BSTR.
1656 * PARAMS
1657 * bstr [I] String to get bytes from
1658 * ppsa [O] Destination for the array
1660 * RETURNS
1661 * Success: S_OK. ppsa contains the strings bytes as a VT_UI1 array.
1662 * Failure: An HRESULT error code indicating the error.
1664 * NOTES
1665 * See SafeArray.
1667 HRESULT WINAPI VectorFromBstr(BSTR bstr, SAFEARRAY **ppsa)
1669 SAFEARRAYBOUND sab;
1671 TRACE("(%p,%p)\n", bstr, ppsa);
1673 if (!ppsa)
1674 return E_INVALIDARG;
1676 sab.lLbound = 0;
1677 sab.cElements = SysStringByteLen(bstr);
1679 *ppsa = SAFEARRAY_Create(VT_UI1, 1, &sab, 0);
1681 if (*ppsa)
1683 memcpy((*ppsa)->pvData, bstr, sab.cElements);
1684 return S_OK;
1686 return E_OUTOFMEMORY;
1689 /************************************************************************
1690 * BstrFromVector (OLEAUT32.@)
1692 * Create a BSTR from a SafeArray.
1694 * PARAMS
1695 * psa [I] Source array
1696 * pbstr [O] Destination for output BSTR
1698 * RETURNS
1699 * Success: S_OK. pbstr contains the arrays data.
1700 * Failure: An HRESULT error code indicating the error.
1702 * NOTES
1703 * psa must be a 1 dimensional array of a 1 byte type.
1705 * NOTES
1706 * See SafeArray.
1708 HRESULT WINAPI BstrFromVector(SAFEARRAY *psa, BSTR *pbstr)
1710 TRACE("(%p,%p)\n", psa, pbstr);
1712 if (!pbstr)
1713 return E_INVALIDARG;
1715 *pbstr = NULL;
1717 if (!psa || psa->cbElements != 1 || psa->cDims != 1)
1718 return E_INVALIDARG;
1720 *pbstr = SysAllocStringByteLen(psa->pvData, psa->rgsabound[0].cElements);
1721 if (!*pbstr)
1722 return E_OUTOFMEMORY;
1723 return S_OK;