Commit c2d6a6b4 authored by Jon Griffiths's avatar Jon Griffiths Committed by Alexandre Julliard

Rewrite: Support I8/UI8,RECORD.

Store array bounds in the same order as native. Add CreateEx, CreateVectorEx, VectorFromBstr, BstrFromVector.
parent 599b0b73
......@@ -39,8 +39,8 @@
39 stdcall SafeArrayDestroyData(ptr)
40 stdcall SafeArrayRedim(ptr ptr)
41 stdcall SafeArrayAllocDescriptorEx(long long ptr)
42 stub SafeArrayCreateEx
43 stub SafeArrayCreateVectorEx
42 stdcall SafeArrayCreateEx(long long ptr ptr)
43 stdcall SafeArrayCreateVectorEx(long long long ptr)
44 stdcall SafeArraySetRecordInfo(ptr ptr)
45 stdcall SafeArrayGetRecordInfo(ptr ptr)
46 stdcall VarParseNumFromStr(wstr long long ptr ptr)
......@@ -385,8 +385,8 @@
410 stdcall -private DllCanUnloadNow() OLEAUT32_DllCanUnloadNow
411 stdcall SafeArrayCreateVector(long long long)
412 stdcall SafeArrayCopyData(ptr ptr)
413 stub VectorFromBstr
414 stub BstrFromVector
413 stdcall VectorFromBstr(ptr ptr)
414 stdcall BstrFromVector(ptr ptr)
415 stdcall OleIconToCursor(long long)
416 stdcall OleCreatePropertyFrameIndirect(ptr)
417 stdcall OleCreatePropertyFrame(ptr long long ptr long ptr long ptr ptr long ptr)
......
/*************************************************************************
* OLE Automation
* SafeArray Implementation
* OLE Automation - SafeArray
*
* This file contains the implementation of the SafeArray interface.
* This file contains the implementation of the SafeArray functions.
*
* Copyright 1999 Sylvain St-Germain
* Copyright 2003 Jon Griffiths
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
......@@ -23,1307 +23,1702 @@
/* Memory Layout of a SafeArray:
*
* -0x10: start of memory.
* -0x10: GUID for VT_DISPATCH and VT_UNKNOWN safearrays (if FADF_HAVEIID)
* -0x10: GUID for VT_DISPATCH and VT_UNKNOWN safearrays (if FADF_HAVEIID)
* -0x04: DWORD varianttype; (for all others, except VT_RECORD) (if FADF_HAVEVARTYPE)
* -0x4: IRecordInfo* iface; (if FADF_RECORD, for VT_RECORD (can be NULL))
* -0x4: IRecordInfo* iface; (if FADF_RECORD, for VT_RECORD (can be NULL))
* 0x00: SAFEARRAY,
* 0x10: SAFEARRAYBOUNDS[0...]
*/
#include "config.h"
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "windef.h"
#include "winerror.h"
#include "winbase.h"
#include "oleauto.h"
#include "wine/debug.h"
#include "variant.h"
WINE_DEFAULT_DEBUG_CHANNEL(ole);
#define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
/************************************************************************
* SafeArray {OLEAUT32}
*
* NOTES
* The SafeArray data type provides the underlying interface for Ole
* Automations arrays, used for example to represent array types in
* Visual Basic(tm) and to gather user defined parameters for invocation through
* an IDispatch interface.
*
* Safe arrays provide bounds checking and automatically manage the data
* types they contain, for example handing reference counting and copying
* of interface pointers. User defined types can be stored in arrays
* using the IRecordInfo interface.
*
* There are two types of SafeArray, normal and vectors. Normal arrays can have
* multiple dimensions and the data for the array is allocated seperately from
* the array header. This is the most flexable type of array. Vectors, on the
* other hand, are fixed in size and consist of a single allocated block, and a
* single dimension.
*
* DATATYPES
* The following types of data can be stored within a SafeArray.
* Numeric:
*| VT_I1, VT_UI1, VT_I2, VT_UI2, VT_I4, VT_UI4, VT_I8, VT_UI8, VT_INT, VT_UINT,
*| VT_R4, VT_R8, VT_CY, VT_DECIMAL
* Interfaces:
*| VT_DISPATCH, VT_UNKNOWN, VT_RECORD
* Other:
*| VT_VARIANT, VT_INT_PTR, VT_UINT_PTR, VT_BOOL, VT_ERROR, VT_DATE, VT_BSTR
*
* FUNCTIONS
* BstrFromVector()
* VectorFromBstr()
*/
/* Undocumented hidden space before the start of a SafeArray descriptor */
#define SAFEARRAY_HIDDEN_SIZE sizeof(GUID)
/* Value returned by SAFEARRAY_GetCellCount if a dimension is invalid */
#define SAFEARRAY_INVALID_CELLS ~0UL
/* Allocate memory */
static inline LPVOID SAFEARRAY_Malloc(ULONG ulSize)
{
/* FIXME: Memory should be allocated and freed using a per-thread IMalloc
* instance returned from CoGetMalloc().
*/
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulSize);
}
/* Free memory */
static inline BOOL SAFEARRAY_Free(LPVOID lpData)
{
return HeapFree(GetProcessHeap(), 0, lpData);
}
/* Get the size of a supported VT type (0 means unsupported) */
static DWORD SAFEARRAY_GetVTSize(VARTYPE vt)
{
switch (vt)
{
case VT_I1:
case VT_UI1: return sizeof(BYTE);
case VT_BOOL:
case VT_I2:
case VT_UI2: return sizeof(SHORT);
case VT_I4:
case VT_UI4:
case VT_R4:
case VT_ERROR: return sizeof(LONG);
case VT_R8:
case VT_I8:
case VT_UI8: return sizeof(LONG64);
case VT_INT:
case VT_UINT: return sizeof(INT);
case VT_INT_PTR:
case VT_UINT_PTR: return sizeof(UINT_PTR);
case VT_CY: return sizeof(CY);
case VT_DATE: return sizeof(DATE);
case VT_BSTR: return sizeof(BSTR);
case VT_DISPATCH: return sizeof(LPDISPATCH);
case VT_VARIANT: return sizeof(VARIANT);
case VT_UNKNOWN: return sizeof(LPUNKNOWN);
case VT_DECIMAL: return sizeof(DECIMAL);
/* Note: Return a non-zero size to indicate vt is valid. The actual size
* of a UDT is taken from the result of IRecordInfo_GetSize().
*/
case VT_RECORD: return 32;
}
return 0;
}
/* Set the hidden data for an array */
static inline void SAFEARRAY_SetHiddenDWORD(SAFEARRAY* psa, DWORD dw)
{
/* Implementation data is stored in the 4 bytes before the header */
LPDWORD lpDw = (LPDWORD)psa;
lpDw[-1] = dw;
}
/* Get the hidden data from an array */
static inline DWORD SAFEARRAY_GetHiddenDWORD(SAFEARRAY* psa)
{
LPDWORD lpDw = (LPDWORD)psa;
return lpDw[-1];
}
/* Get the number of cells in a SafeArray */
static ULONG SAFEARRAY_GetCellCount(const SAFEARRAY *psa)
{
SAFEARRAYBOUND* psab = psa->rgsabound;
USHORT cCount = psa->cDims;
ULONG ulNumCells = 1;
/* Locally used methods */
static ULONG
calcDisplacement(LONG *coor, SAFEARRAYBOUND *mat, LONG dim);
while (cCount--)
{
if (!psab->cElements)
{
ERR("Dimension has size=0! Please report.\n");
return SAFEARRAY_INVALID_CELLS;
}
ulNumCells *= psab->cElements;
psab++;
}
return ulNumCells;
}
static BOOL
isPointer(USHORT feature);
/* Get the 0 based index of an index into a dimension */
static inline ULONG SAFEARRAY_GetDimensionIndex(SAFEARRAYBOUND *psab, ULONG ulIndex)
{
return ulIndex - psab->lLbound;
}
static INT
getFeatures(VARTYPE vt);
/* Get the size of a dimension in cells */
static inline ULONG SAFEARRAY_GetDimensionCells(SAFEARRAY *psa, ULONG ulDim)
{
ULONG size = psa->rgsabound[0].cElements;
static BOOL
validCoordinate(LONG *coor, SAFEARRAY *psa);
while (ulDim)
{
size *= psa->rgsabound[ulDim].cElements;
ulDim--;
}
return size;
}
/* Allocate a descriptor for an array */
static HRESULT SAFEARRAY_AllocDescriptor(ULONG ulSize, SAFEARRAY **ppsaOut)
{
*ppsaOut = (SAFEARRAY*)((char*)SAFEARRAY_Malloc(ulSize + SAFEARRAY_HIDDEN_SIZE) + SAFEARRAY_HIDDEN_SIZE);
if (!*ppsaOut)
return E_UNEXPECTED;
return S_OK;
}
/* Set the features of an array */
static void SAFEARRAY_SetFeatures(VARTYPE vt, SAFEARRAY *psa)
{
/* Set the IID if we have one, otherwise set the type */
if (vt == VT_DISPATCH)
{
psa->fFeatures = FADF_HAVEIID;
SafeArraySetIID(psa, &IID_IDispatch);
}
else if (vt == VT_UNKNOWN)
{
psa->fFeatures = FADF_HAVEIID;
SafeArraySetIID(psa, &IID_IUnknown);
}
else if (vt == VT_RECORD)
psa->fFeatures = FADF_RECORD;
else
{
psa->fFeatures = FADF_HAVEVARTYPE;
SAFEARRAY_SetHiddenDWORD(psa, vt);
}
}
/* Create an array */
static SAFEARRAY* SAFEARRAY_Create(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound, ULONG ulSize)
{
SAFEARRAY *psa = NULL;
if (!rgsabound)
return NULL;
if (SUCCEEDED(SafeArrayAllocDescriptorEx(vt, cDims, &psa)))
{
switch (vt)
{
case VT_BSTR: psa->fFeatures |= FADF_BSTR; break;
case VT_UNKNOWN: psa->fFeatures |= FADF_UNKNOWN; break;
case VT_DISPATCH: psa->fFeatures |= FADF_DISPATCH; break;
case VT_VARIANT: psa->fFeatures |= FADF_VARIANT; break;
}
memcpy(psa->rgsabound, rgsabound, cDims * sizeof(SAFEARRAYBOUND));
if (ulSize)
psa->cbElements = ulSize;
if (FAILED(SafeArrayAllocData(psa)))
{
SafeArrayDestroyDescriptor(psa);
psa = NULL;
}
}
return psa;
}
/* Create an array as a vector */
static SAFEARRAY* SAFEARRAY_CreateVector(VARTYPE vt, LONG lLbound, ULONG cElements, ULONG ulSize)
{
SAFEARRAY *psa = NULL;
if (cElements && (vt == VT_RECORD || ulSize))
{
/* Allocate the header and data together */
if (SUCCEEDED(SAFEARRAY_AllocDescriptor(sizeof(SAFEARRAY) + ulSize * cElements, &psa)))
{
SAFEARRAY_SetFeatures(vt, psa);
psa->cDims = 1;
psa->fFeatures |= FADF_CREATEVECTOR;
psa->pvData = &psa[1]; /* Data follows the header */
psa->cbElements = ulSize;
psa->rgsabound[0].cElements = cElements;
psa->rgsabound[0].lLbound = lLbound;
switch (vt)
{
case VT_BSTR: psa->fFeatures |= FADF_BSTR; break;
case VT_UNKNOWN: psa->fFeatures |= FADF_UNKNOWN; break;
case VT_DISPATCH: psa->fFeatures |= FADF_DISPATCH; break;
case VT_VARIANT: psa->fFeatures |= FADF_VARIANT; break;
}
}
}
else if (!cElements)
{
ERR("Creating vector of size 0! Please report.\n");
}
return psa;
}
static BOOL
resizeSafeArray(SAFEARRAY *psa, LONG lDelta);
/* Free data items in an array */
static HRESULT SAFEARRAY_DestroyData(SAFEARRAY *psa, ULONG ulStartCell)
{
if (psa->pvData && !(psa->fFeatures & FADF_DATADELETED))
{
ULONG ulCellCount = SAFEARRAY_GetCellCount(psa);
static BOOL
validArg(SAFEARRAY *psa);
if (ulCellCount == SAFEARRAY_INVALID_CELLS || ulStartCell > ulCellCount)
return E_UNEXPECTED;
static ULONG
getArraySize(SAFEARRAY *psa);
ulCellCount -= ulStartCell;
static HRESULT
duplicateData(SAFEARRAY *psa, SAFEARRAY *ppsaOut);
if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
{
LPUNKNOWN *lpUnknown = (LPUNKNOWN *)psa->pvData + ulStartCell * psa->cbElements;
/* Association between VARTYPE and their size.
A size of zero is defined for the unsupported types. */
while(ulCellCount--)
{
if (*lpUnknown)
IUnknown_Release(*lpUnknown);
lpUnknown++;
}
}
else if (psa->fFeatures & (FADF_RECORD))
{
IRecordInfo *lpRecInfo;
if (SUCCEEDED(SafeArrayGetRecordInfo(psa, &lpRecInfo)))
{
PBYTE pRecordData = (PBYTE)psa->pvData;
while(ulCellCount--)
{
IRecordInfo_RecordClear(lpRecInfo, pRecordData);
pRecordData += psa->cbElements;
}
IRecordInfo_Release(lpRecInfo);
}
}
else if (psa->fFeatures & FADF_BSTR)
{
BSTR* lpBstr = (BSTR*)psa->pvData + ulStartCell * psa->cbElements;
while(ulCellCount--)
{
if (*lpBstr)
SysFreeString(*lpBstr);
lpBstr++;
}
}
else if (psa->fFeatures & FADF_VARIANT)
{
VARIANT* lpVariant = (VARIANT*)psa->pvData + ulStartCell * psa->cbElements;
while(ulCellCount--)
{
VariantClear(lpVariant);
lpVariant++;
}
}
}
return S_OK;
}
#define VARTYPE_NOT_SUPPORTED 0
static const ULONG VARTYPE_SIZE[] =
/* Copy data items from one array to another */
static HRESULT SAFEARRAY_CopyData(SAFEARRAY *psa, SAFEARRAY *dest)
{
/* this is taken from wtypes.h. Only [S]es are supported by the SafeArray */
VARTYPE_NOT_SUPPORTED, /* VT_EMPTY [V] [P] nothing */
VARTYPE_NOT_SUPPORTED, /* VT_NULL [V] [P] SQL style Nul */
2, /* VT_I2 [V][T][P][S] 2 byte signed int */
4, /* VT_I4 [V][T][P][S] 4 byte signed int */
4, /* VT_R4 [V][T][P][S] 4 byte real */
8, /* VT_R8 [V][T][P][S] 8 byte real */
8, /* VT_CY [V][T][P][S] currency */
8, /* VT_DATE [V][T][P][S] date */
sizeof(BSTR), /* VT_BSTR [V][T][P][S] OLE Automation string*/
sizeof(LPDISPATCH), /* VT_DISPATCH [V][T][P][S] IDispatch * */
4, /* VT_ERROR [V][T] [S] SCODE */
2, /* VT_BOOL [V][T][P][S] True=-1, False=0*/
sizeof(VARIANT), /* VT_VARIANT [V][T][P][S] VARIANT * */
sizeof(LPUNKNOWN), /* VT_UNKNOWN [V][T] [S] IUnknown * */
sizeof(DECIMAL), /* VT_DECIMAL [V][T] [S] 16 byte fixed point */
VARTYPE_NOT_SUPPORTED, /* no VARTYPE here..... */
1, /* VT_I1 [T] [S] signed char */
1, /* VT_UI1 [V][T][P][S] unsigned char */
2, /* VT_UI2 [T][P][S] unsigned short */
4, /* VT_UI4 [T][P][S] unsigned int */
VARTYPE_NOT_SUPPORTED, /* VT_I8 [T][P] signed 64-bit int */
VARTYPE_NOT_SUPPORTED, /* VT_UI8 [T][P] unsigned 64-bit int */
sizeof(INT), /* VT_INT [T] signed machine int */
sizeof(UINT), /* VT_UINT [T] unsigned machine int */
VARTYPE_NOT_SUPPORTED, /* VT_VOID [T] C style void */
VARTYPE_NOT_SUPPORTED, /* VT_HRESULT [T] Standard return type */
VARTYPE_NOT_SUPPORTED, /* VT_PTR [T] pointer type */
VARTYPE_NOT_SUPPORTED, /* VT_SAFEARRAY [T] (use VT_ARRAY in VARIANT)*/
VARTYPE_NOT_SUPPORTED, /* VT_CARRAY [T] C style array */
VARTYPE_NOT_SUPPORTED, /* VT_USERDEFINED [T] user defined type */
VARTYPE_NOT_SUPPORTED, /* VT_LPSTR [T][P] null terminated string */
VARTYPE_NOT_SUPPORTED, /* VT_LPWSTR [T][P] wide null term string */
VARTYPE_NOT_SUPPORTED, /* 32 */
VARTYPE_NOT_SUPPORTED, /* 33 */
VARTYPE_NOT_SUPPORTED, /* 34 */
VARTYPE_NOT_SUPPORTED, /* 35 */
VARTYPE_NOT_SUPPORTED, /* VT_RECORD record */
VARTYPE_NOT_SUPPORTED, /* 37 */
VARTYPE_NOT_SUPPORTED, /* 38 */
VARTYPE_NOT_SUPPORTED, /* 39 */
VARTYPE_NOT_SUPPORTED, /* 40 */
VARTYPE_NOT_SUPPORTED, /* 41 */
VARTYPE_NOT_SUPPORTED, /* 42 */
VARTYPE_NOT_SUPPORTED, /* 43 */
VARTYPE_NOT_SUPPORTED, /* 44 */
VARTYPE_NOT_SUPPORTED, /* 45 */
VARTYPE_NOT_SUPPORTED, /* 46 */
VARTYPE_NOT_SUPPORTED, /* 47 */
VARTYPE_NOT_SUPPORTED, /* 48 */
VARTYPE_NOT_SUPPORTED, /* 49 */
VARTYPE_NOT_SUPPORTED, /* 50 */
VARTYPE_NOT_SUPPORTED, /* 51 */
VARTYPE_NOT_SUPPORTED, /* 52 */
VARTYPE_NOT_SUPPORTED, /* 53 */
VARTYPE_NOT_SUPPORTED, /* 54 */
VARTYPE_NOT_SUPPORTED, /* 55 */
VARTYPE_NOT_SUPPORTED, /* 56 */
VARTYPE_NOT_SUPPORTED, /* 57 */
VARTYPE_NOT_SUPPORTED, /* 58 */
VARTYPE_NOT_SUPPORTED, /* 59 */
VARTYPE_NOT_SUPPORTED, /* 60 */
VARTYPE_NOT_SUPPORTED, /* 61 */
VARTYPE_NOT_SUPPORTED, /* 62 */
VARTYPE_NOT_SUPPORTED, /* 63 */
VARTYPE_NOT_SUPPORTED, /* VT_FILETIME [P] FILETIME */
VARTYPE_NOT_SUPPORTED, /* VT_BLOB [P] Length prefixed bytes */
VARTYPE_NOT_SUPPORTED, /* VT_STREAM [P] Name of stream follows */
VARTYPE_NOT_SUPPORTED, /* VT_STORAGE [P] Name of storage follows */
VARTYPE_NOT_SUPPORTED, /* VT_STREAMED_OBJECT[P] Stream contains an object*/
VARTYPE_NOT_SUPPORTED, /* VT_STORED_OBJECT [P] Storage contains object*/
VARTYPE_NOT_SUPPORTED, /* VT_BLOB_OBJECT [P] Blob contains an object*/
VARTYPE_NOT_SUPPORTED, /* VT_CF [P] Clipboard format */
VARTYPE_NOT_SUPPORTED, /* VT_CLSID [P] A Class ID */
};
static const int LAST_VARTYPE = sizeof(VARTYPE_SIZE)/sizeof(VARTYPE_SIZE[0]);
if (!psa->pvData || !dest->pvData || psa->fFeatures & FADF_DATADELETED)
return E_INVALIDARG;
else
{
ULONG ulCellCount = SAFEARRAY_GetCellCount(psa);
if (ulCellCount == SAFEARRAY_INVALID_CELLS)
return E_UNEXPECTED;
dest->fFeatures = (dest->fFeatures & FADF_CREATEVECTOR) |
(psa->fFeatures & ~(FADF_CREATEVECTOR|FADF_DATADELETED));
if (psa->fFeatures & FADF_VARIANT)
{
VARIANT* lpVariant = (VARIANT*)psa->pvData;
VARIANT* lpDest = (VARIANT*)dest->pvData;
while(ulCellCount--)
{
VariantCopy(lpDest, lpVariant);
lpVariant++;
lpDest++;
}
}
else if (psa->fFeatures & FADF_BSTR)
{
BSTR* lpBstr = (BSTR*)psa->pvData;
BSTR* lpDest = (BSTR*)dest->pvData;
while(ulCellCount--)
{
if (*lpBstr)
{
*lpDest = SysAllocStringLen(*lpBstr, SysStringLen(*lpBstr));
if (!*lpDest)
return E_OUTOFMEMORY;
}
else
*lpDest = NULL;
lpBstr++;
lpDest++;
}
}
else
{
/* Copy the data over */
memcpy(dest->pvData, psa->pvData, ulCellCount * psa->cbElements);
if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
{
LPUNKNOWN *lpUnknown = (LPUNKNOWN *)dest->pvData;
while(ulCellCount--)
{
if (*lpUnknown)
IUnknown_AddRef(*lpUnknown);
lpUnknown++;
}
}
}
if (psa->fFeatures & FADF_RECORD)
{
IRecordInfo* pRecInfo = NULL;
SafeArrayGetRecordInfo(psa, &pRecInfo);
SafeArraySetRecordInfo(dest, pRecInfo);
if (pRecInfo)
{
/* Release because Get() adds a reference */
IRecordInfo_Release(pRecInfo);
}
}
else if (psa->fFeatures & FADF_HAVEIID)
{
GUID guid;
SafeArrayGetIID(psa, &guid);
SafeArraySetIID(dest, &guid);
}
else if (psa->fFeatures & FADF_HAVEVARTYPE)
{
SAFEARRAY_SetHiddenDWORD(dest, SAFEARRAY_GetHiddenDWORD(psa));
}
}
return S_OK;
}
/*************************************************************************
* SafeArrayAllocDescriptor (OLEAUT32.36)
* Allocate the appropriate amount of memory for the SafeArray descriptor
*
* Allocate and initialise a descriptor for a SafeArray.
*
* PARAMS
* cDims [I] Number of dimensions of the array
* ppsaOut [O] Destination for new descriptor
*
* RETURNS
* Success: S_OK. ppsaOut is filled with a newly allocated descriptor.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* See SafeArray.
*/
HRESULT WINAPI SafeArrayAllocDescriptor(
UINT cDims,
SAFEARRAY **ppsaOut)
HRESULT WINAPI SafeArrayAllocDescriptor(UINT cDims, SAFEARRAY **ppsaOut)
{
SAFEARRAYBOUND *sab;
LONG allocSize = 0;
char *ptr;
LONG allocSize;
if (!cDims || cDims >= 0x10000) /* 65536 appears to be the limit */
TRACE("(%d,%p)\n", cDims, ppsaOut);
if (!cDims || cDims >= 0x10000) /* Maximum 65535 dimensions */
return E_INVALIDARG;
if (!ppsaOut)
return E_POINTER;
/* GUID + SAFEARRAY + SAFEARRAYBOUND * (cDims -1)
* ( -1 because there is already one ( in SAFEARRAY struct
*/
allocSize = sizeof(GUID) + sizeof(**ppsaOut) + (sizeof(*sab) * (cDims-1));
/* We need enough space for the header and its bounds */
allocSize = sizeof(SAFEARRAY) + sizeof(SAFEARRAYBOUND) * (cDims - 1);
/* Allocate memory for SAFEARRAY struc */
ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, allocSize);
if (!ptr)
return E_OUTOFMEMORY;
*ppsaOut = (SAFEARRAY *)(ptr + sizeof(GUID));
(*ppsaOut)->cDims = cDims;
TRACE("(%d): %lu bytes allocated for descriptor.\n", cDims, allocSize);
if (FAILED(SAFEARRAY_AllocDescriptor(allocSize, ppsaOut)))
return E_UNEXPECTED;
return(S_OK);
(*ppsaOut)->cDims = cDims;
TRACE("(%d): %lu bytes allocated for descriptor.\n", cDims, allocSize);
return S_OK;
}
/*************************************************************************
* SafeArrayAllocDescriptorEx (OLEAUT32.41)
* Allocate the appropriate amount of memory for the SafeArray descriptor
* and also store information about the vartype before the returned pointer.
*
* Allocate and initialise a descriptor for a SafeArray of a given type.
*
* PARAMS
* vt [I] The type of items to store in the array
* cDims [I] Number of dimensions of the array
* ppsaOut [O] Destination for new descriptor
*
* RETURNS
* Success: S_OK. ppsaOut is filled with a newly allocated descriptor.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* - This function does not chack that vt is an allowed VARTYPE.
* - Unlike SafeArrayAllocDescriptor(), vt is associated with the array.
* See SafeArray.
*/
HRESULT WINAPI SafeArrayAllocDescriptorEx(
VARTYPE vt,
UINT cDims,
SAFEARRAY **ppsaOut)
HRESULT WINAPI SafeArrayAllocDescriptorEx(VARTYPE vt, UINT cDims, SAFEARRAY **ppsaOut)
{
HRESULT hres;
hres = SafeArrayAllocDescriptor (cDims, ppsaOut);
if (FAILED(hres))
return hres;
switch (vt) {
case VT_DISPATCH:
(*ppsaOut)->fFeatures = FADF_HAVEIID;
SafeArraySetIID( *ppsaOut, &IID_IDispatch);
break;
case VT_UNKNOWN:
(*ppsaOut)->fFeatures = FADF_HAVEIID;
SafeArraySetIID( *ppsaOut, &IID_IUnknown);
break;
case VT_RECORD:
(*ppsaOut)->fFeatures = FADF_RECORD;
break;
default:
(*ppsaOut)->fFeatures = FADF_HAVEVARTYPE;
((DWORD*)*ppsaOut)[-1] = vt;
break;
ULONG cbElements;
HRESULT hRet = E_UNEXPECTED;
TRACE("(%d->%s,%d,%p)\n", vt, debugstr_vt(vt), cDims, ppsaOut);
cbElements = SAFEARRAY_GetVTSize(vt);
if (!cbElements)
WARN("Creating a descriptor with an invalid VARTYPE!\n");
hRet = SafeArrayAllocDescriptor(cDims, ppsaOut);
if (SUCCEEDED(hRet))
{
SAFEARRAY_SetFeatures(vt, *ppsaOut);
(*ppsaOut)->cbElements = cbElements;
}
return S_OK;
return hRet;
}
/*************************************************************************
* SafeArrayAllocData (OLEAUT32.37)
* Allocate the appropriate amount of data for the SafeArray data
*
* Allocate the data area of a SafeArray.
*
* PARAMS
* psa [I] SafeArray to allocate the data area of.
*
* RETURNS
* Success: S_OK. The data area is allocated and initialised.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* See SafeArray.
*/
HRESULT WINAPI SafeArrayAllocData(
SAFEARRAY *psa)
HRESULT WINAPI SafeArrayAllocData(SAFEARRAY *psa)
{
ULONG ulWholeArraySize; /* to store the size of the whole thing */
if(! validArg(psa))
return E_INVALIDARG;
ulWholeArraySize = getArraySize(psa);
HRESULT hRet = E_INVALIDARG;
TRACE("(%p)\n", psa);
if (psa)
{
ULONG ulSize = SAFEARRAY_GetCellCount(psa);
/* Allocate memory for the data itself */
if((psa->pvData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
psa->cbElements*ulWholeArraySize)) == NULL)
return(E_UNEXPECTED);
hRet = E_OUTOFMEMORY;
TRACE("SafeArray: %lu bytes allocated for data at %p (%lu objects).\n",
psa->cbElements*ulWholeArraySize, psa->pvData, ulWholeArraySize);
if (ulSize != SAFEARRAY_INVALID_CELLS && psa->cbElements)
{
psa->pvData = SAFEARRAY_Malloc(ulSize * psa->cbElements);
return(S_OK);
if (psa->pvData)
{
hRet = S_OK;
TRACE("%lu bytes allocated for data at %p (%lu objects).\n",
ulSize * psa->cbElements, psa->pvData, ulSize);
}
}
}
return hRet;
}
/*************************************************************************
* SafeArrayCreate (OLEAUT32.15)
* Create a SafeArray object by encapsulating AllocDescriptor and AllocData
*
* Create a new SafeArray.
*
* PARAMS
* vt [I] Type to store in the safe array
* cDims [I] Number of array dimensions
* rgsabound [I] Bounds of the array dimensions
*
* RETURNS
* Success: A pointer to a new array object.
* Failure: NULL, if any parameter is invalid or memory allocation fails.
*
* NOTES
* Win32 allows arrays with 0 sized dimensions. This bug is not reproduced
* in the Wine implementation.
* See SafeArray.
*/
SAFEARRAY* WINAPI SafeArrayCreate(
VARTYPE vt,
UINT cDims,
SAFEARRAYBOUND *rgsabound)
SAFEARRAY* WINAPI SafeArrayCreate(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound)
{
SAFEARRAY *psa;
HRESULT hRes;
USHORT cDim;
TRACE("(%d->%s,%d,%p)\n", vt, debugstr_vt(vt), cDims, rgsabound);
TRACE("(%d, %d, %p)\n", vt, cDims, rgsabound);
/* Validate supported VARTYPE */
if ( (vt >= LAST_VARTYPE) ||
( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
if (vt == VT_RECORD)
return NULL;
/* Allocate memory for the array descriptor */
if( FAILED( hRes = SafeArrayAllocDescriptorEx(vt, cDims, &psa)))
return NULL;
return SAFEARRAY_Create(vt, cDims, rgsabound, 0);
}
/* setup data members... */
psa->cDims = cDims;
switch (vt) {
case VT_BSTR: psa->fFeatures |= FADF_BSTR;break;
case VT_UNKNOWN: psa->fFeatures |= FADF_UNKNOWN;break;
case VT_DISPATCH: psa->fFeatures |= FADF_DISPATCH;break;
case VT_VARIANT: psa->fFeatures |= FADF_VARIANT;break;
default: break;
/*************************************************************************
* SafeArrayCreateEx (OLEAUT32.15)
*
* Create a new SafeArray.
*
* PARAMS
* vt [I] Type to store in the safe array
* cDims [I] Number of array dimensions
* rgsabound [I] Bounds of the array dimensions
* pvExtra [I] Extra data
*
* RETURNS
* Success: A pointer to a new array object.
* Failure: NULL, if any parameter is invalid or memory allocation fails.
*
* NOTES
* See SafeArray.
*/
SAFEARRAY* WINAPI SafeArrayCreateEx(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound, LPVOID pvExtra)
{
ULONG ulSize = 0;
IRecordInfo* iRecInfo = (IRecordInfo*)pvExtra;
SAFEARRAY* psa;
TRACE("(%d->%s,%d,%p,%p)\n", vt, debugstr_vt(vt), cDims, rgsabound, pvExtra);
if (vt == VT_RECORD)
{
if (!iRecInfo)
return NULL;
IRecordInfo_GetSize(iRecInfo, &ulSize);
}
psa->cLocks = 0;
psa->pvData = NULL;
psa->cbElements= VARTYPE_SIZE[vt];
/* Invert the bounds ... */
for(cDim=0; cDim < psa->cDims; cDim++) {
psa->rgsabound[cDim].cElements = rgsabound[psa->cDims-cDim-1].cElements;
psa->rgsabound[cDim].lLbound = rgsabound[psa->cDims-cDim-1].lLbound;
psa = SAFEARRAY_Create(vt, cDims, rgsabound, ulSize);
if (pvExtra)
{
switch(vt)
{
case VT_RECORD:
SafeArraySetRecordInfo(psa, pvExtra);
break;
case VT_UNKNOWN:
case VT_DISPATCH:
SafeArraySetIID(psa, pvExtra);
break;
}
}
return psa;
}
/* allocate memory for the data... */
if( FAILED( hRes = SafeArrayAllocData(psa))) {
SafeArrayDestroyDescriptor(psa);
ERR("() : Failed to allocate the Safe Array data\n");
/************************************************************************
* SafeArrayCreateVector (OLEAUT32.411)
*
* Create a one dimensional, contigous SafeArray.
*
* PARAMS
* vt [I] Type to store in the safe array
* lLbound [I] Lower bound of the array
* cElements [I] Number of elements in the array
*
* RETURNS
* Success: A pointer to a new array object.
* Failure: NULL, if any parameter is invalid or memory allocation fails.
*
* NOTES
* See SafeArray.
*/
SAFEARRAY* WINAPI SafeArrayCreateVector(VARTYPE vt, LONG lLbound, ULONG cElements)
{
TRACE("(%d->%s,%ld,%ld\n", vt, debugstr_vt(vt), lLbound, cElements);
if (vt == VT_RECORD)
return NULL;
return SAFEARRAY_CreateVector(vt, lLbound, cElements, SAFEARRAY_GetVTSize(vt));
}
/************************************************************************
* SafeArrayCreateVectorEx (OLEAUT32.411)
*
* Create a one dimensional, contigous SafeArray.
*
* PARAMS
* vt [I] Type to store in the safe array
* lLbound [I] Lower bound of the array
* cElements [I] Number of elements in the array
* pvExtra [I] Extra data
*
* RETURNS
* Success: A pointer to a new array object.
* Failure: NULL, if any parameter is invalid or memory allocation fails.
*
* NOTES
* See SafeArray.
*/
SAFEARRAY* WINAPI SafeArrayCreateVectorEx(VARTYPE vt, LONG lLbound, ULONG cElements, LPVOID pvExtra)
{
ULONG ulSize;
IRecordInfo* iRecInfo = (IRecordInfo*)pvExtra;
SAFEARRAY* psa;
TRACE("(%d->%s,%ld,%ld,%p\n", vt, debugstr_vt(vt), lLbound, cElements, pvExtra);
if (vt == VT_RECORD)
{
if (!iRecInfo)
return NULL;
IRecordInfo_GetSize(iRecInfo, &ulSize);
}
else
ulSize = SAFEARRAY_GetVTSize(vt);
psa = SAFEARRAY_CreateVector(vt, lLbound, cElements, ulSize);
return(psa);
if (pvExtra)
{
switch(vt)
{
case VT_RECORD:
SafeArraySetRecordInfo(psa, iRecInfo);
break;
case VT_UNKNOWN:
case VT_DISPATCH:
SafeArraySetIID(psa, pvExtra);
break;
}
}
return psa;
}
/*************************************************************************
* SafeArrayDestroyDescriptor (OLEAUT32.38)
* Frees the memory associated with the descriptor.
*
* Destroy a SafeArray.
*
* PARAMS
* psa [I] SafeArray to destroy.
*
* RETURNS
* Success: S_OK. The resources used by the array are freed.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* See SafeArray.
*/
HRESULT WINAPI SafeArrayDestroyDescriptor(
SAFEARRAY *psa)
HRESULT WINAPI SafeArrayDestroyDescriptor(SAFEARRAY *psa)
{
LPVOID ptr;
TRACE("(%p)\n", psa);
if (psa)
{
LPVOID lpv = (char*)psa - SAFEARRAY_HIDDEN_SIZE;
/* Check for lockness before to free... */
if(psa->cLocks > 0)
return DISP_E_ARRAYISLOCKED;
if (psa->cLocks)
return DISP_E_ARRAYISLOCKED; /* Can't destroy a locked array */
/* The array is unlocked, then, deallocate memory */
ptr = ((IID*)psa)-1;
if(HeapFree( GetProcessHeap(), 0, ptr) == FALSE)
return E_UNEXPECTED;
return(S_OK);
}
if (psa->fFeatures & FADF_RECORD)
SafeArraySetRecordInfo(psa, NULL);
if (psa->fFeatures & FADF_CREATEVECTOR &&
!(psa->fFeatures & FADF_DATADELETED))
SAFEARRAY_DestroyData(psa, 0); /* Data not previously deleted */
if (!SAFEARRAY_Free(lpv))
return E_UNEXPECTED;
}
return S_OK;
}
/*************************************************************************
* SafeArrayLock (OLEAUT32.21)
* Increment the lock counter
*
* Doc says (MSDN Library ) that psa->pvData should be made available (!= NULL)
* only when psa->cLocks is > 0... I don't get it since pvData is allocated
* before the array is locked, therefore
* Increment the lock counter of a SafeArray.
*
* PARAMS
* psa [O] SafeArray to lock
*
* RETURNS
* Success: S_OK. The array lock is incremented.
* Failure: E_INVALIDARG if psa is NULL, or E_UNEXPECTED if too many locks
* are held on the array at once.
*
* NOTES
* In Win32 these locks are not thread safe.
* See SafeArray.
*/
HRESULT WINAPI SafeArrayLock(
SAFEARRAY *psa)
HRESULT WINAPI SafeArrayLock(SAFEARRAY *psa)
{
if(! validArg(psa))
ULONG ulLocks;
TRACE("(%p)\n", psa);
if (!psa)
return E_INVALIDARG;
psa->cLocks++;
ulLocks = InterlockedIncrement(&psa->cLocks);
return(S_OK);
if (ulLocks > 0xffff) /* Maximum of 16384 locks at a time */
{
WARN("Out of locks!\n");
InterlockedDecrement(&psa->cLocks);
return E_UNEXPECTED;
}
return S_OK;
}
/*************************************************************************
* SafeArrayUnlock (OLEAUT32.22)
* Decrement the lock counter
*
* Decrement the lock counter of a SafeArray.
*
* PARAMS
* psa [O] SafeArray to unlock
*
* RETURNS
* Success: S_OK. The array lock is decremented.
* Failure: E_INVALIDARG if psa is NULL, or E_UNEXPECTED if no locks are
* held on the array.
*
* NOTES
* See SafeArray.
*/
HRESULT WINAPI SafeArrayUnlock(
SAFEARRAY *psa)
HRESULT WINAPI SafeArrayUnlock(SAFEARRAY *psa)
{
if(! validArg(psa))
TRACE("(%p)\n", psa);
if (!psa)
return E_INVALIDARG;
if (psa->cLocks > 0)
psa->cLocks--;
return(S_OK);
if ((LONG)InterlockedDecrement(&psa->cLocks) < 0)
{
WARN("Unlocked but no lock held!\n");
InterlockedIncrement(&psa->cLocks);
return E_UNEXPECTED;
}
return S_OK;
}
/*************************************************************************
* SafeArrayPutElement (OLEAUT32.26)
* Set the data at the given coordinate
*
* Put an item into a SafeArray.
*
* PARAMS
* psa [I] SafeArray to insert into
* rgIndices [I] Indices to insert at
* pvData [I] Data to insert
*
* RETURNS
* Success: S_OK. The item is inserted
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* See SafeArray.
*/
HRESULT WINAPI SafeArrayPutElement(
SAFEARRAY *psa,
LONG *rgIndices,
void *pv)
HRESULT WINAPI SafeArrayPutElement(SAFEARRAY *psa, LONG *rgIndices, void *pvData)
{
ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
the desired one... */
PVOID elementStorageAddress = NULL; /* Address to store the data */
HRESULT hRet;
/* Validate the index given */
if(! validCoordinate(rgIndices, psa))
return DISP_E_BADINDEX;
if(! validArg(psa))
return E_INVALIDARG;
TRACE("(%p,%p,%p)\n", psa, rgIndices, pvData);
if( SafeArrayLock(psa) == S_OK) {
if (!psa || !rgIndices)
return E_INVALIDARG;
/* Figure out the number of items to skip */
stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
if (!pvData)
{
ERR("Invalid pvData would crash under Win32!\n");
return E_INVALIDARG;
}
/* Figure out the number of byte to skip ... */
elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
hRet = SafeArrayLock(psa);
if(isPointer(psa->fFeatures)) { /* increment ref count for this pointer */
if (SUCCEEDED(hRet))
{
PVOID lpvDest;
*((PVOID*)elementStorageAddress) = *(PVOID*)pv;
IUnknown_AddRef( *(IUnknown**)pv);
hRet = SafeArrayPtrOfIndex(psa, rgIndices, &lpvDest);
} else {
if (SUCCEEDED(hRet))
{
if (psa->fFeatures & FADF_VARIANT)
{
VARIANT* lpVariant = (VARIANT*)pvData;
VARIANT* lpDest = (VARIANT*)lpvDest;
if(psa->fFeatures & FADF_BSTR) { /* Create a new object */
BSTR pbstrReAllocStr = NULL;
if(pv &&
((pbstrReAllocStr = SYSDUPSTRING( (OLECHAR*)pv )) == NULL)) {
SafeArrayUnlock(psa);
return E_OUTOFMEMORY;
} else
*((BSTR*)elementStorageAddress) = pbstrReAllocStr;
VariantClear(lpDest);
VariantCopy(lpDest, lpVariant);
}
else if(psa->fFeatures & FADF_VARIANT) {
HRESULT hr = VariantCopy(elementStorageAddress, pv);
if (FAILED(hr)) {
SafeArrayUnlock(psa);
return hr;
else if (psa->fFeatures & FADF_BSTR)
{
BSTR* lpBstr = (BSTR*)pvData;
BSTR* lpDest = (BSTR*)lpvDest;
if (*lpDest)
SysFreeString(*lpDest);
if (*lpBstr)
{
*lpDest = SysAllocStringLen(*lpBstr, SysStringLen(*lpBstr));
if (!*lpDest)
hRet = E_OUTOFMEMORY;
}
else
*lpDest = NULL;
}
else
{
if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
{
LPUNKNOWN *lpUnknown = (LPUNKNOWN *)pvData;
LPUNKNOWN *lpDest = (LPUNKNOWN *)lpvDest;
if (*lpUnknown)
IUnknown_AddRef(*lpUnknown);
if (*lpDest)
IUnknown_Release(*lpDest);
}
/* Copy the data over */
memcpy(lpvDest, pvData, psa->cbElements);
}
else /* duplicate the memory */
memcpy(elementStorageAddress, pv, SafeArrayGetElemsize(psa) );
}
} else {
ERR("SafeArray: Cannot lock array....\n");
return E_UNEXPECTED; /* UNDOC error condition */
SafeArrayUnlock(psa);
}
TRACE("SafeArray: item put at address %p.\n",elementStorageAddress);
return SafeArrayUnlock(psa);
return hRet;
}
/*************************************************************************
* SafeArrayGetElement (OLEAUT32.25)
* Return the data element corresponding the the given coordinate
*
* Get an item from a SafeArray.
*
* PARAMS
* psa [I] SafeArray to get from
* rgIndices [I] Indices to get from
* pvData [O] Destination for data
*
* RETURNS
* Success: S_OK. The item data is returned in pvData.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* See SafeArray.
*/
HRESULT WINAPI SafeArrayGetElement(
SAFEARRAY *psa,
LONG *rgIndices,
void *pv)
HRESULT WINAPI SafeArrayGetElement(SAFEARRAY *psa, LONG *rgIndices, void *pvData)
{
ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
the desired one... */
PVOID elementStorageAddress = NULL; /* Address to store the data */
HRESULT hRet;
if(! validArg(psa))
TRACE("(%p,%p,%p)\n", psa, rgIndices, pvData);
if (!psa || !rgIndices || !pvData)
return E_INVALIDARG;
if(! validCoordinate(rgIndices, psa)) /* Validate the index given */
return(DISP_E_BADINDEX);
hRet = SafeArrayLock(psa);
if( SafeArrayLock(psa) == S_OK) {
if (SUCCEEDED(hRet))
{
PVOID lpvSrc;
/* Figure out the number of items to skip */
stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
hRet = SafeArrayPtrOfIndex(psa, rgIndices, &lpvSrc);
/* Figure out the number of byte to skip ... */
elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
if (SUCCEEDED(hRet))
{
if (psa->fFeatures & FADF_VARIANT)
{
VARIANT* lpVariant = (VARIANT*)lpvSrc;
VARIANT* lpDest = (VARIANT*)pvData;
if( psa->fFeatures & FADF_BSTR) { /* reallocate the obj */
BSTR pbstrStoredStr = *(OLECHAR**)elementStorageAddress;
BSTR pbstrReturnedStr = NULL;
if( pbstrStoredStr &&
((pbstrReturnedStr = SYSDUPSTRING( pbstrStoredStr )) == NULL) ) {
SafeArrayUnlock(psa);
return E_OUTOFMEMORY;
} else
*((BSTR*)pv) = pbstrReturnedStr;
}
else if( psa->fFeatures & FADF_VARIANT) {
HRESULT hr;
VariantInit(pv);
hr = VariantCopy(pv, elementStorageAddress);
if (FAILED(hr)) {
SafeArrayUnlock(psa);
return hr;
VariantCopy(lpDest, lpVariant);
}
else if (psa->fFeatures & FADF_BSTR)
{
BSTR* lpBstr = (BSTR*)lpvSrc;
BSTR* lpDest = (BSTR*)pvData;
if (*lpBstr)
{
*lpDest = SysAllocStringLen(*lpBstr, SysStringLen(*lpBstr));
if (!*lpBstr)
hRet = E_OUTOFMEMORY;
}
else
*lpDest = NULL;
}
else
{
if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
{
LPUNKNOWN *lpUnknown = (LPUNKNOWN *)lpvSrc;
if (*lpUnknown)
IUnknown_AddRef(*lpUnknown);
}
/* Copy the data over */
memcpy(pvData, lpvSrc, psa->cbElements);
}
}
else if( isPointer(psa->fFeatures) ) /* simply copy the pointer */
*(PVOID*)pv = *((PVOID*)elementStorageAddress);
else /* copy the bytes */
memcpy(pv, elementStorageAddress, psa->cbElements );
} else {
ERR("SafeArray: Cannot lock array....\n");
return E_UNEXPECTED; /* UNDOC error condition */
SafeArrayUnlock(psa);
}
return( SafeArrayUnlock(psa) );
return hRet;
}
/*************************************************************************
* SafeArrayGetUBound (OLEAUT32.19)
* return the UP bound for a given array dimension
* Note: [0] is the right most (least significant) array index!
*
* Get the upper bound for a given SafeArray dimension
*
* PARAMS
* psa [I] Array to get dimension upper bound from
* nDim [I] The dimension number to get the upper bound of
* plUbound [O] Destination for the upper bound
*
* RETURNS
* Success: S_OK. plUbound contains the dimensions upper bound.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* See SafeArray.
*/
HRESULT WINAPI SafeArrayGetUBound(
SAFEARRAY *psa,
UINT nDim,
LONG *plUbound)
HRESULT WINAPI SafeArrayGetUBound(SAFEARRAY *psa, UINT nDim, LONG *plUbound)
{
if(! validArg(psa))
TRACE("(%p,%d,%p)\n", psa, nDim, plUbound);
if (!psa || !plUbound)
return E_INVALIDARG;
if(nDim > psa->cDims)
return DISP_E_BADINDEX;
if(0 == nDim)
if(!nDim || nDim > psa->cDims || !psa->rgsabound[nDim - 1].cElements)
return DISP_E_BADINDEX;
*plUbound = psa->rgsabound[psa->cDims - nDim].lLbound +
psa->rgsabound[psa->cDims - nDim].cElements - 1;
*plUbound = psa->rgsabound[nDim - 1].lLbound +
psa->rgsabound[nDim - 1].cElements - 1;
return S_OK;
}
/*************************************************************************
* SafeArrayGetLBound (OLEAUT32.20)
* Return the LO bound for a given array dimension
* Note: [0] is the right most (least significant) array index!
*
* Get the lower bound for a given SafeArray dimension
*
* PARAMS
* psa [I] Array to get dimension lower bound from
* nDim [I] The dimension number to get the lowe bound of
* plLbound [O] Destination for the lower bound
*
* RETURNS
* Success: S_OK. plUbound contains the dimensions lower bound.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* See SafeArray.
*/
HRESULT WINAPI SafeArrayGetLBound(
SAFEARRAY *psa,
UINT nDim,
LONG *plLbound)
HRESULT WINAPI SafeArrayGetLBound(SAFEARRAY *psa, UINT nDim, LONG *plLbound)
{
if(! validArg(psa))
return E_INVALIDARG;
TRACE("(%p,%d,%p)\n", psa, nDim, plLbound);
if(nDim > psa->cDims)
return DISP_E_BADINDEX;
if (!psa || !plLbound)
return E_INVALIDARG;
if(0 == nDim)
if(!nDim || nDim > psa->cDims || !psa->rgsabound[nDim - 1].cElements)
return DISP_E_BADINDEX;
*plLbound = psa->rgsabound[psa->cDims - nDim].lLbound;
*plLbound = psa->rgsabound[nDim - 1].lLbound;
return S_OK;
}
/*************************************************************************
* SafeArrayGetDim (OLEAUT32.17)
* returns the number of dimension in the array
*
* Get the number of dimensions in a SafeArray.
*
* PARAMS
* psa [I] Array to get the dimensions of
*
* RETURNS
* The number of array dimensions in psa, or 0 if psa is NULL.
*
* NOTES
* See SafeArray.
*/
UINT WINAPI SafeArrayGetDim(
SAFEARRAY * psa)
UINT WINAPI SafeArrayGetDim(SAFEARRAY *psa)
{
/*
* A quick test in Windows shows that the behavior here for an invalid
* pointer is to return 0.
*/
if(! validArg(psa))
return 0;
return psa->cDims;
TRACE("(%p) returning %ld\n", psa, psa ? psa->cDims : 0ul);
return psa ? psa->cDims : 0;
}
/*************************************************************************
* SafeArrayGetElemsize (OLEAUT32.18)
* Return the size of the element in the array
*
* Get the size of an element in a SafeArray.
*
* PARAMS
* psa [I] Array to get the element size from
*
* RETURNS
* The size of a single element in psa, or 0 if psa is NULL.
*
* NOTES
* See SafeArray.
*/
UINT WINAPI SafeArrayGetElemsize(
SAFEARRAY * psa)
UINT WINAPI SafeArrayGetElemsize(SAFEARRAY *psa)
{
/*
* A quick test in Windows shows that the behavior here for an invalid
* pointer is to return 0.
*/
if(! validArg(psa))
return 0;
return psa->cbElements;
TRACE("(%p) returning %ld\n", psa, psa ? psa->cbElements : 0ul);
return psa ? psa->cbElements : 0;
}
/*************************************************************************
* SafeArrayAccessData (OLEAUT32.23)
* increment the access count and return the data
*
* Lock a SafeArray and return a pointer to its data.
*
* PARAMS
* psa [I] Array to get the data pointer from
* ppvData [O] Destination for the arrays data pointer
*
* RETURNS
* Success: S_OK. ppvData contains the arrays data pointer, and the array
* is locked.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* See SafeArray.
*/
HRESULT WINAPI SafeArrayAccessData(
SAFEARRAY *psa,
void **ppvData)
HRESULT WINAPI SafeArrayAccessData(SAFEARRAY *psa, void **ppvData)
{
HRESULT hRes;
TRACE("(%p,%p)\n", psa, ppvData);
if(! validArg(psa))
if(!psa || !ppvData)
return E_INVALIDARG;
hRes = SafeArrayLock(psa);
switch (hRes) {
case S_OK:
(*ppvData) = psa->pvData;
break;
case E_INVALIDARG:
(*ppvData) = NULL;
return E_INVALIDARG;
if (SUCCEEDED(SafeArrayLock(psa)))
{
*ppvData = psa->pvData;
return S_OK;
}
return S_OK;
*ppvData = NULL;
return E_UNEXPECTED;
}
/*************************************************************************
* SafeArrayUnaccessData (OLEAUT32.24)
* Decrement the access count
*/
HRESULT WINAPI SafeArrayUnaccessData(
SAFEARRAY * psa)
{
if(! validArg(psa))
return E_INVALIDARG;
return(SafeArrayUnlock(psa));
}
/************************************************************************
* SafeArrayPtrOfIndex (OLEAUT32.148)
* Return a pointer to the element at rgIndices
*
* Unlock a SafeArray after accessing its data.
*
* PARAMS
* psa [I] Array to unlock
*
* RETURNS
* Success: S_OK. The array is unlocked.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* See SafeArray.
*/
HRESULT WINAPI SafeArrayPtrOfIndex(
SAFEARRAY *psa,
LONG *rgIndices,
void **ppvData)
HRESULT WINAPI SafeArrayUnaccessData(SAFEARRAY *psa)
{
ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
the desired one... */
if(! validArg(psa))
return E_INVALIDARG;
if(! validCoordinate(rgIndices, psa))
return DISP_E_BADINDEX;
/* Although it is dangerous to do this without having a lock, it is not
* illegal. Microsoft do warn of the danger.
*/
/* Figure out the number of items to skip */
stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
*ppvData = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
return S_OK;
TRACE("(%p)\n", psa);
return SafeArrayUnlock(psa);
}
/************************************************************************
* SafeArrayDestroyData (OLEAUT32.39)
* Frees the memory data bloc
* SafeArrayPtrOfIndex (OLEAUT32.148)
*
* Get the address of an item in a SafeArray.
*
* PARAMS
* psa [I] Array to get the items address from
* rgIndices [I] Index of the item in the array
* ppvData [O] Destination for item address
*
* RETURNS
* Success: S_OK. ppvData contains a pointer to the item.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* This function does not lock the array.
*
* NOTES
* See SafeArray.
*/
HRESULT WINAPI SafeArrayDestroyData(
SAFEARRAY *psa)
HRESULT WINAPI SafeArrayPtrOfIndex(SAFEARRAY *psa, LONG *rgIndices, void **ppvData)
{
HRESULT hRes;
ULONG ulWholeArraySize; /* count spot in array */
ULONG ulDataIter; /* to iterate the data space */
if(! validArg(psa))
USHORT dim;
ULONG cell = 0, dimensionSize = 1;
SAFEARRAYBOUND* psab;
LONG c1;
TRACE("(%p,%p,%p)\n", psa, rgIndices, ppvData);
/* The general formula for locating the cell number of an entry in an n
* dimensional array (where cn = coordinate in dimension dn) is:
*
* c1 + c2 * sizeof(d1) + c3 * sizeof(d2) ... + cn * sizeof(c(n-1))
*
* We calculate the size of the last dimension at each step through the
* dimensions to avoid recursing to calculate the last dimensions size.
*/
if (!psa || !rgIndices || !ppvData)
return E_INVALIDARG;
if(psa->cLocks > 0)
return DISP_E_ARRAYISLOCKED;
if(psa->pvData==NULL)
return S_OK;
psab = psa->rgsabound;
c1 = *rgIndices++;
ulWholeArraySize = getArraySize(psa);
if (c1 < psab->lLbound || c1 >= psab->lLbound + (LONG)psab->cElements)
return DISP_E_BADINDEX; /* Initial index out of bounds */
if(isPointer(psa->fFeatures)) { /* release the pointers */
IUnknown *punk;
for (dim = 1; dim < psa->cDims; dim++)
{
dimensionSize *= psab->cElements;
for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
punk = *(IUnknown**)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
psab++;
if( punk != NULL)
IUnknown_Release(punk);
}
if (!psab->cElements ||
*rgIndices < psab->lLbound ||
*rgIndices >= psab->lLbound + (LONG)psab->cElements)
return DISP_E_BADINDEX; /* Index out of bounds */
cell += (*rgIndices - psab->lLbound) * dimensionSize;
rgIndices++;
}
else if(psa->fFeatures & FADF_BSTR) { /* deallocate the obj */
BSTR bstr;
for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
bstr = *(BSTR*)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
cell += (c1 - psa->rgsabound[0].lLbound);
if( bstr != NULL)
SysFreeString( bstr );
}
}
else if(psa->fFeatures & FADF_VARIANT) { /* deallocate the obj */
*ppvData = (char*)psa->pvData + cell * psa->cbElements;
return S_OK;
}
for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
VariantClear((VARIANT*)((char *) psa->pvData+(ulDataIter*(psa->cbElements))));
}
}
/************************************************************************
* SafeArrayDestroyData (OLEAUT32.39)
*
* Destroy the data associated with a SafeArray.
*
* PARAMS
* psa [I] Array to delete the data from
*
* RETURNS
* Success: S_OK. All items and the item data are freed.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* See SafeArray.
*/
HRESULT WINAPI SafeArrayDestroyData(SAFEARRAY *psa)
{
TRACE("(%p)\n", psa);
if (!psa)
return E_INVALIDARG;
/* check if this array is a Vector, in which case do not free the data
block since it has been allocated by AllocDescriptor and therefore
deserve to be freed by DestroyDescriptor */
if(!(psa->fFeatures & FADF_CREATEVECTOR)) { /* Set when we do CreateVector */
if (psa->cLocks)
return DISP_E_ARRAYISLOCKED; /* Cant delete a locked array */
/* free the whole chunk */
if((hRes = HeapFree( GetProcessHeap(), 0, psa->pvData)) == 0) /*failed*/
return E_UNEXPECTED; /* UNDOC error condition */
if (psa->pvData)
{
/* Delete the actual item data */
if (FAILED(SAFEARRAY_DestroyData(psa, 0)))
return E_UNEXPECTED;
/* If this is not a vector, free the data memory block */
if (!(psa->fFeatures & FADF_CREATEVECTOR))
{
if (!SAFEARRAY_Free(psa->pvData))
return E_UNEXPECTED;
psa->pvData = NULL;
}
else
psa->fFeatures |= FADF_DATADELETED; /* Mark the data deleted */
psa->pvData = NULL;
}
return S_OK;
}
/************************************************************************
* SafeArrayCopyData (OLEAUT32.412)
* Copy the psaSource's data block into psaTarget if dimension and size
* permits it.
*
* Copy all data from one SafeArray to another.
*
* PARAMS
* psaSource [I] Source for copy
* psaTarget [O] Destination for copy
*
* RETURNS
* Success: S_OK. psaTarget contains a copy of psaSource.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* The two arrays must have the same number of dimensions and elements.
*
* NOTES
* See SafeArray.
*/
HRESULT WINAPI SafeArrayCopyData(
SAFEARRAY *psaSource,
SAFEARRAY *psaTarget)
HRESULT WINAPI SafeArrayCopyData(SAFEARRAY *psaSource, SAFEARRAY *psaTarget)
{
USHORT cDimCount; /* looper */
LONG lDelta; /* looper */
IUnknown *punk;
ULONG ulWholeArraySize; /* Number of item in SA */
BSTR bstr;
if(! (validArg(psaSource) && validArg(psaTarget)) )
return E_INVALIDARG;
int dim;
if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(psaTarget))
TRACE("(%p,%p)\n", psaSource, psaTarget);
if (!psaSource || !psaTarget ||
psaSource->cDims != psaTarget->cDims ||
psaSource->cbElements != psaTarget->cbElements)
return E_INVALIDARG;
ulWholeArraySize = getArraySize(psaSource);
/* The two arrays boundaries must be of same length */
for(cDimCount=0;cDimCount < psaSource->cDims; cDimCount++)
if( psaSource->rgsabound[cDimCount].cElements !=
psaTarget->rgsabound[cDimCount].cElements)
/* Each dimension must be the same size */
for (dim = psaSource->cDims - 1; dim >= 0 ; dim--)
if (psaSource->rgsabound[dim].cElements !=
psaTarget->rgsabound[dim].cElements)
return E_INVALIDARG;
if( isPointer(psaTarget->fFeatures) ) { /* the target contains ptr
that must be released */
for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
punk = *(IUnknown**)
((char *) psaTarget->pvData + (lDelta * psaTarget->cbElements));
if( punk != NULL)
IUnknown_Release(punk);
}
}
else if( psaTarget->fFeatures & FADF_BSTR) { /* the target contain BSTR
that must be freed */
for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
bstr =
*(BSTR*)((char *) psaTarget->pvData + (lDelta * psaTarget->cbElements));
if( bstr != NULL)
SysFreeString( bstr );
}
}
else if( psaTarget->fFeatures & FADF_VARIANT) {
for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
VariantClear((VARIANT*)((char *) psaTarget->pvData + (lDelta * psaTarget->cbElements)));
}
}
return duplicateData(psaSource, psaTarget);
if (SUCCEEDED(SAFEARRAY_DestroyData(psaTarget, 0)) &&
SUCCEEDED(SAFEARRAY_CopyData(psaSource, psaTarget)))
return S_OK;
return E_UNEXPECTED;
}
/************************************************************************
* SafeArrayDestroy (OLEAUT32.16)
* Deallocates all memory reserved for the SafeArray
*
* Destroy a SafeArray.
*
* PARAMS
* psa [I] Array to destroy
*
* RETURNS
* Success: S_OK. All resources used by the array are freed.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* See SafeArray.
*/
HRESULT WINAPI SafeArrayDestroy(
SAFEARRAY * psa)
HRESULT WINAPI SafeArrayDestroy(SAFEARRAY *psa)
{
HRESULT hRes;
TRACE("(%p)\n", psa);
if(! validArg(psa))
if(!psa)
return E_INVALIDARG;
if(psa->cLocks > 0)
return DISP_E_ARRAYISLOCKED;
if((hRes = SafeArrayDestroyData( psa )) == S_OK)
if((hRes = SafeArrayDestroyDescriptor( psa )) == S_OK)
return S_OK;
return E_UNEXPECTED; /* UNDOC error condition */
/* Native doesn't check to see if the free succeeds */
SafeArrayDestroyData(psa);
SafeArrayDestroyDescriptor(psa);
return S_OK;
}
/************************************************************************
* SafeArrayCopy (OLEAUT32.27)
* Make a dupplicate of a SafeArray
*
* Make a duplicate of a SafeArray.
*
* PARAMS
* psa [I] Source for copy
* ppsaOut [O] Destination for new copy
*
* RETURNS
* Success: S_OK. ppsaOut contains a copy of the array.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* See SafeArray.
*/
HRESULT WINAPI SafeArrayCopy(
SAFEARRAY *psa,
SAFEARRAY **ppsaOut)
HRESULT WINAPI SafeArrayCopy(SAFEARRAY *psa, SAFEARRAY **ppsaOut)
{
HRESULT hRes;
DWORD dAllocSize;
ULONG ulWholeArraySize; /* size of the thing */
if(! validArg(psa))
return E_INVALIDARG;
HRESULT hRet;
if((hRes=SafeArrayAllocDescriptor(psa->cDims, ppsaOut)) == S_OK){
TRACE("(%p,%p)\n", psa, ppsaOut);
/* Duplicate the SAFEARRAY struct */
memcpy(*ppsaOut, psa,
sizeof(*psa)+(sizeof(*(psa->rgsabound))*(psa->cDims-1)));
if (!ppsaOut)
return E_INVALIDARG;
/* If the features that use storage before the SAFEARRAY struct are
* enabled, also copy this memory range. Flags have been copied already.
*/
if (psa->fFeatures & (FADF_HAVEIID | FADF_HAVEVARTYPE))
memcpy(((GUID*)*ppsaOut)-1, ((GUID*)psa)-1, sizeof(GUID));
*ppsaOut = NULL;
/* Copy the IRecordInfo* reference */
if (psa->fFeatures & FADF_RECORD) {
IRecordInfo *ri;
if (!psa)
return S_OK; /* Handles copying of NULL arrays */
ri = ((IRecordInfo**)psa)[-1];
if (ri) {
((IRecordInfo**)*ppsaOut)[-1] = ri;
IRecordInfo_AddRef(ri);
}
if (psa->fFeatures & (FADF_RECORD|FADF_HAVEIID|FADF_HAVEVARTYPE))
{
VARTYPE vt;
if (FAILED(SafeArrayGetVartype(psa, &vt)))
hRet = E_UNEXPECTED;
else
hRet = SafeArrayAllocDescriptorEx(vt, psa->cDims, ppsaOut);
}
else
{
hRet = SafeArrayAllocDescriptor(psa->cDims, ppsaOut);
if (SUCCEEDED(hRet))
{
(*ppsaOut)->fFeatures = psa->fFeatures & ~FADF_CREATEVECTOR;
(*ppsaOut)->cbElements = psa->cbElements;
}
}
(*ppsaOut)->pvData = NULL; /* do not point to the same data area */
/* make sure the new safe array doesn't have the FADF_CREATEVECTOR flag,
because the data has not been allocated with the descriptor. */
(*ppsaOut)->fFeatures &= ~FADF_CREATEVECTOR;
/* Get the allocated memory size for source and allocate it for target */
ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
dAllocSize = ulWholeArraySize*psa->cbElements;
if (SUCCEEDED(hRet))
{
/* Copy dimension bounds */
memcpy((*ppsaOut)->rgsabound, psa->rgsabound, psa->cDims * sizeof(SAFEARRAYBOUND));
(*ppsaOut)->pvData =
HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dAllocSize);
if( (*ppsaOut)->pvData != NULL) { /* HeapAlloc succeed */
(*ppsaOut)->pvData = SAFEARRAY_Malloc(SAFEARRAY_GetCellCount(psa) * psa->cbElements);
if( (hRes=duplicateData(psa, *ppsaOut)) != S_OK) { /* E_OUTOFMEMORY */
HeapFree(GetProcessHeap(), 0, (*ppsaOut)->pvData);
(*ppsaOut)->pvData = NULL;
SafeArrayDestroyDescriptor(*ppsaOut);
return hRes;
}
if ((*ppsaOut)->pvData)
{
hRet = SAFEARRAY_CopyData(psa, *ppsaOut);
if (SUCCEEDED(hRet))
return hRet;
} else { /* failed to allocate or dupplicate... */
SafeArrayDestroyDescriptor(*ppsaOut);
return E_UNEXPECTED; /* UNDOC error condition */
SAFEARRAY_Free((*ppsaOut)->pvData);
}
} else { /* failed to allocate mem for descriptor */
return E_OUTOFMEMORY; /* UNDOC error condiftion */
SafeArrayDestroyDescriptor(*ppsaOut);
}
return S_OK;
}
/************************************************************************
* SafeArrayCreateVector (OLEAUT32.411)
* Creates a one dimension safearray where the data is next to the
* SAFEARRAY structure.
*/
SAFEARRAY* WINAPI SafeArrayCreateVector(
VARTYPE vt,
LONG lLbound,
ULONG cElements)
{
SAFEARRAY *psa;
BYTE *ptr;
TRACE("%d, %ld, %ld\n", vt, lLbound, cElements);
/* Validate supported VARTYPE */
if ( (vt >= LAST_VARTYPE) ||
( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
return NULL;
/* Allocate memory for the array descriptor and data contiguously */
ptr = HeapAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY,
(sizeof(GUID)+sizeof(*psa)+(VARTYPE_SIZE[vt]*cElements)));
if (!ptr)
return NULL;
psa = (SAFEARRAY*)(ptr+sizeof(GUID));
/* setup data members... */
psa->cDims = 1; /* always and forever */
psa->fFeatures = getFeatures(vt) | FADF_CREATEVECTOR; /* undocumented flag used by Microsoft */
psa->cLocks = 0;
psa->pvData = (BYTE*)psa + sizeof(*psa);
psa->cbElements = VARTYPE_SIZE[vt];
psa->rgsabound[0].cElements = cElements;
psa->rgsabound[0].lLbound = lLbound;
return(psa);
*ppsaOut = NULL;
return hRet;
}
/************************************************************************
* SafeArrayRedim (OLEAUT32.40)
* Changes the caracteristics of the last dimension of the SafeArray
*
* Changes the characteristics of the last dimension of a SafeArray
*
* PARAMS
* psa [I] Array to change
* psabound [I] New bound details for the last dimension
*
* RETURNS
* Success: S_OK. psa is updated to reflect the new bounds.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* See SafeArray.
*/
HRESULT WINAPI SafeArrayRedim(
SAFEARRAY *psa,
SAFEARRAYBOUND *psaboundNew)
HRESULT WINAPI SafeArrayRedim(SAFEARRAY *psa, SAFEARRAYBOUND *psabound)
{
LONG lDelta; /* hold difference in size */
USHORT cDims=1; /* dims counter */
SAFEARRAYBOUND *oldBounds;
if( !validArg(psa) )
TRACE("(%p,%p)\n", psa, psabound);
if (!psa || psa->fFeatures & FADF_FIXEDSIZE || !psabound || !psabound->cElements)
return E_INVALIDARG;
if( psa->cLocks > 0 )
if (psa->cLocks > 0)
return DISP_E_ARRAYISLOCKED;
if( psa->fFeatures & FADF_FIXEDSIZE )
return E_INVALIDARG;
if( SafeArrayLock(psa)==E_UNEXPECTED )
return E_UNEXPECTED;/* UNDOC error condition */
/* find the delta in number of array spot to apply to the new array */
lDelta = psaboundNew->cElements - psa->rgsabound[0].cElements;
for(; cDims < psa->cDims; cDims++)
/* delta in number of spot implied by modifying the last dimension */
lDelta *= psa->rgsabound[cDims].cElements;
if (FAILED(SafeArrayLock(psa)))
return E_UNEXPECTED;
TRACE("elements=%ld, Lbound=%ld (delta=%ld)\n", psaboundNew->cElements, psaboundNew->lLbound, lDelta);
oldBounds = &psa->rgsabound[psa->cDims - 1];
oldBounds->lLbound = psabound->lLbound;
if (lDelta == 0) { ;/* same size, maybe a change of lLbound, just set it */
if (psabound->cElements != oldBounds->cElements)
{
if (psabound->cElements < oldBounds->cElements)
{
/* Shorten the final dimension. */
ULONG ulStartCell = psa->cDims == 1 ? 0 : SAFEARRAY_GetDimensionCells(psa, psa->cDims - 1);
} else /* need to enlarge (lDelta +) reduce (lDelta -) */
if(! resizeSafeArray(psa, lDelta))
return E_UNEXPECTED; /* UNDOC error condition */
ulStartCell += psabound->cElements;
SAFEARRAY_DestroyData(psa, ulStartCell);
}
else
{
/* Lengthen the final dimension */
ULONG ulOldSize, ulNewSize;
PVOID pvNewData;
ulOldSize = SAFEARRAY_GetCellCount(psa);
ulNewSize = (ulOldSize / oldBounds->cElements) * psabound->cElements;
if (ulOldSize == SAFEARRAY_INVALID_CELLS ||
!(pvNewData = SAFEARRAY_Malloc(ulNewSize)))
{
SafeArrayUnlock(psa);
return E_UNEXPECTED;
}
/* the only modifyable dimension sits in [0] as the dimensions were reversed
at array creation time... */
psa->rgsabound[0].cElements = psaboundNew->cElements;
psa->rgsabound[0].lLbound = psaboundNew->lLbound;
memcpy(pvNewData, psa->pvData, ulOldSize);
SAFEARRAY_Free(psa->pvData);
psa->pvData = pvNewData;
}
oldBounds->cElements = psabound->cElements;
}
return SafeArrayUnlock(psa);
SafeArrayUnlock(psa);
return S_OK;
}
/************************************************************************
* NOT WINDOWS API - SafeArray* Utility functions
************************************************************************/
/************************************************************************
* Used to validate the SAFEARRAY type of arg
* SafeArrayGetVartype (OLEAUT32.77)
*
* Get the type of the items in a SafeArray.
*
* PARAMS
* psa [I] Array to get the type from
* pvt [O] Destination for the type
*
* RETURNS
* Success: S_OK. pvt contains the type of the items.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* See SafeArray.
*/
static BOOL validArg(
SAFEARRAY *psa)
HRESULT WINAPI SafeArrayGetVartype(SAFEARRAY* psa, VARTYPE* pvt)
{
SAFEARRAYBOUND *sab;
LONG psaSize = 0;
LONG descSize = 0;
LONG fullSize = 0;
/*
* Let's check for the null pointer just in case.
*/
if (psa == NULL)
return FALSE;
/* Check whether the size of the chunk makes sense... That's the only thing
I can think of now... */
TRACE("(%p,%p)\n", psa, pvt);
psaSize = HeapSize(GetProcessHeap(), 0, ((IID*)psa)-1);
if (psaSize == -1)
/* uh, foreign heap. Better don't mess with it ! */
return TRUE;
/* size of the descriptor when the SA is not created with CreateVector */
descSize = sizeof(GUID) + sizeof(*psa) + (sizeof(*sab) * (psa->cDims-1));
if (!psa || !pvt)
return E_INVALIDARG;
/* size of the descriptor + data when created with CreateVector */
fullSize = sizeof(*psa) + (psa->cbElements * psa->rgsabound[0].cElements);
if (psa->fFeatures & FADF_RECORD)
*pvt = VT_RECORD;
else if (psa->fFeatures & FADF_HAVEIID)
*pvt = VT_UNKNOWN;
else if (psa->fFeatures & FADF_HAVEVARTYPE)
{
VARTYPE vt = SAFEARRAY_GetHiddenDWORD(psa);
*pvt = vt;
}
else
return E_INVALIDARG;
return((psaSize >= descSize) || (psaSize >= fullSize));
return S_OK;
}
/************************************************************************
* Used to reallocate memory
* SafeArraySetRecordInfo (OLEAUT32.@)
*
* Set the record info for a SafeArray.
*
* PARAMS
* psa [I] Array to set the record info for
* pRinfo [I] Record info
*
* RETURNS
* Success: S_OK. The record info is stored with the array.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* See SafeArray.
*/
static BOOL resizeSafeArray(
SAFEARRAY *psa,
LONG lDelta)
HRESULT WINAPI SafeArraySetRecordInfo(SAFEARRAY *psa, IRecordInfo *pRinfo)
{
ULONG ulWholeArraySize; /* use as multiplicator */
PVOID pvNewBlock = NULL;
IUnknown *punk;
BSTR bstr;
ulWholeArraySize = getArraySize(psa);
if(lDelta < 0) { /* array needs to be shorthen */
if( isPointer(psa->fFeatures)) /* ptr that need to be released */
for(;lDelta < 0; lDelta++) {
punk = *(IUnknown**)
((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
if( punk != NULL )
IUnknown_Release(punk);
}
else if(psa->fFeatures & FADF_BSTR) /* BSTR that need to be freed */
for(;lDelta < 0; lDelta++) {
bstr = *(BSTR*)
((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
if( bstr != NULL )
SysFreeString( bstr );
}
else if(psa->fFeatures & FADF_VARIANT)
for(;lDelta < 0; lDelta++) {
VariantClear((VARIANT*)((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements)));
}
}
if (!(psa->fFeatures & FADF_CREATEVECTOR))
{
/* Ok now, if we are enlarging the array, we *MUST* move the whole block
pointed to by pvData. If we are shorthening the array, this move is
optional but we do it anyway becuase the benefit is that we are
releasing to the system the unused memory */
if((pvNewBlock = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, psa->pvData,
(ulWholeArraySize + lDelta) * psa->cbElements)) == NULL)
return FALSE; /* TODO If we get here it means:
SHRINK situation : we've deleted the undesired
data and did not release the memory
GROWING situation: we've been unable to grow the array
*/
}
else
{
/* Allocate a new block, because the previous data has been allocated with
the descriptor in SafeArrayCreateVector function. */
IRecordInfo** dest = (IRecordInfo**)psa;
if((pvNewBlock = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
ulWholeArraySize * psa->cbElements)) == NULL)
return FALSE;
TRACE("(%p,%p)\n", psa, pRinfo);
if (!psa || !(psa->fFeatures & FADF_RECORD))
return E_INVALIDARG;
psa->fFeatures &= ~FADF_CREATEVECTOR;
}
/* reassign to the new block of data */
psa->pvData = pvNewBlock;
return TRUE;
}
if (pRinfo)
IRecordInfo_AddRef(pRinfo);
/************************************************************************
* Used to set the fFeatures data member of the SAFEARRAY structure.
*/
static INT getFeatures(VARTYPE vt) {
switch (vt) {
case VT_BSTR: return FADF_BSTR;
case VT_UNKNOWN: return FADF_UNKNOWN;
case VT_DISPATCH: return FADF_DISPATCH;
case VT_VARIANT: return FADF_VARIANT;
}
return 0;
}
if (dest[-1])
IRecordInfo_Release(dest[-1]);
/************************************************************************
* Used to figure out if the fFeatures data member of the SAFEARRAY
* structure contain any information about the type of data stored...
*/
static BOOL isPointer(
USHORT feature)
{
switch(feature) {
case FADF_UNKNOWN: return TRUE; /* those are pointers */
case FADF_DISPATCH: return TRUE;
}
return FALSE;
dest[-1] = pRinfo;
return S_OK;
}
/************************************************************************
* Used to calculate the displacement when accessing or modifying
* safearray data set.
*
* Parameters: - LONG *coor is the desired location in the multidimension
* table. Ex for a 3 dim table: coor[] = {1,2,3};
* - ULONG *mat is the format of the table. Ex for a 3 dim
* table mat[] = {4,4,4};
* - USHORT dim is the number of dimension of the SafeArray
* SafeArrayGetRecordInfo (OLEAUT32.@)
*
* Get the record info from a SafeArray.
*
* PARAMS
* psa [I] Array to get the record info from
* pRinfo [O] Destination for the record info
*
* RETURNS
* Success: S_OK. pRinfo contains the record info, or NULL if there was none.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* See SafeArray.
*/
static ULONG calcDisplacement(
LONG *coor,
SAFEARRAYBOUND *mat,
LONG dim)
HRESULT WINAPI SafeArrayGetRecordInfo(SAFEARRAY *psa, IRecordInfo **pRinfo)
{
ULONG res = 0;
LONG iterDim;
IRecordInfo** src = (IRecordInfo**)psa;
TRACE("dims is %ld\n", dim);
TRACE("(%p,%p)\n", psa, pRinfo);
for (iterDim = dim-1; iterDim >= 0; iterDim--) {
TRACE("%ld: lbound is %ld, adding %ld\n", iterDim, mat[dim-iterDim-1].lLbound,(coor[iterDim] - mat[dim-iterDim-1].lLbound));
res += (coor[iterDim] - mat[dim-iterDim-1].lLbound);
if (!psa || !pRinfo || !(psa->fFeatures & FADF_RECORD))
return E_INVALIDARG;
if (iterDim > 0)
res *= mat[dim-iterDim].cElements;
}
*pRinfo = src[-1];
TRACE("SafeArray: calculated displacement is %lu.\n", res);
return(res);
if (*pRinfo)
IRecordInfo_AddRef(*pRinfo);
return S_OK;
}
/************************************************************************
* Method used to validate the coordinate received in Put and Get
* methods.
* SafeArraySetIID (OLEAUT32.@)
*
* Set the IID for a SafeArray.
*
* PARAMS
* psa [I] Array to set the IID from
* guid [I] IID
*
* RETURNS
* Success: S_OK. The IID is stored with the array
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* See SafeArray.
*/
static BOOL validCoordinate(
LONG *coor,
SAFEARRAY *psa)
HRESULT WINAPI SafeArraySetIID(SAFEARRAY *psa, REFGUID guid)
{
INT iter=0;
LONG lUBound;
LONG lLBound;
HRESULT hRes;
if (!psa->cDims) { FIXME("no dims?\n");return FALSE; }
for(; iter<psa->cDims; iter++) {
TRACE("coor[%d]=%ld\n", iter, coor[iter]);
if((hRes = SafeArrayGetLBound(psa, (iter+1), &lLBound)) != S_OK) {
FIXME("No lbound?\n");
return FALSE;
}
if((hRes = SafeArrayGetUBound(psa, (iter+1), &lUBound)) != S_OK) {
FIXME("No ubound?\n");
return FALSE;
}
if(lLBound > lUBound) {
FIXME("lbound larger than ubound?\n");
return FALSE;
}
if((coor[iter] < lLBound) || (coor[iter] > lUBound)) {
FIXME("coordinate %ld not within %ld - %ld\n",coor[iter], lLBound, lUBound);
return FALSE;
}
}
return TRUE;
}
GUID* dest = (GUID*)psa;
/************************************************************************
* Method used to calculate the number of cells of the SA
*/
static ULONG getArraySize(
SAFEARRAY *psa)
{
USHORT cCount;
ULONG ulWholeArraySize = 1;
TRACE("(%p,%s)\n", psa, debugstr_guid(guid));
for(cCount=0; cCount < psa->cDims; cCount++) /* foreach dimensions... */
ulWholeArraySize *= psa->rgsabound[cCount].cElements;
if (!psa || !guid || !(psa->fFeatures & FADF_HAVEIID))
return E_INVALIDARG;
return ulWholeArraySize;
dest[-1] = *guid;
return S_OK;
}
/************************************************************************
* Method used to handle data space dupplication for Copy32 and CopyData32
* SafeArrayGetIID (OLEAUT32.@)
*
* Get the IID from a SafeArray.
*
* PARAMS
* psa [I] Array to get the ID from
* pGuid [O] Destination for the IID
*
* RETURNS
* Success: S_OK. pRinfo contains the IID, or NULL if there was none.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* See SafeArray.
*/
static HRESULT duplicateData(
SAFEARRAY *psa,
SAFEARRAY *ppsaOut)
HRESULT WINAPI SafeArrayGetIID(SAFEARRAY *psa, GUID *pGuid)
{
ULONG ulWholeArraySize; /* size of the thing */
LONG lDelta;
ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
SafeArrayLock(ppsaOut);
if( isPointer(psa->fFeatures) ) { /* If datatype is object increment
object's reference count */
IUnknown *punk;
for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
punk = *(IUnknown**)((char *) psa->pvData+(lDelta * psa->cbElements));
if( punk != NULL)
IUnknown_AddRef(punk);
}
/* Copy the source array data into target array */
memcpy(ppsaOut->pvData, psa->pvData, ulWholeArraySize*psa->cbElements);
}
else if( psa->fFeatures & FADF_BSTR ) { /* if datatype is BSTR allocate
the BSTR in the new array */
BSTR pbstrReAllocStr = NULL;
GUID* src = (GUID*)psa;
for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
if(( pbstrReAllocStr = SYSDUPSTRING(
*(BSTR*)((char *) psa->pvData+(lDelta * psa->cbElements)))) == NULL) {
TRACE("(%p,%p)\n", psa, pGuid);
SafeArrayUnlock(ppsaOut);
return E_OUTOFMEMORY;
}
*((BSTR*)((char *)ppsaOut->pvData+(lDelta * psa->cbElements))) =
pbstrReAllocStr;
}
}
else if( psa->fFeatures & FADF_VARIANT ) {
for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
VariantCopy((VARIANT*)((char *) ppsaOut->pvData+(lDelta * psa->cbElements)),
(VARIANT*)((char *) psa->pvData+(lDelta * psa->cbElements)));
}
if (!psa || !pGuid || !(psa->fFeatures & FADF_HAVEIID))
return E_INVALIDARG;
} else { /* Simply copy the source array data into target array */
memcpy(ppsaOut->pvData, psa->pvData, ulWholeArraySize*psa->cbElements);
}
SafeArrayUnlock(ppsaOut);
*pGuid = src[-1];
return S_OK;
}
/************************************************************************
* SafeArrayGetVartype (OLEAUT32.77)
* Returns the VARTYPE stored in the given safearray
* VectorFromBstr (OLEAUT32.@)
*
* Create a SafeArray Vector from the bytes of a BSTR.
*
* PARAMS
* bstr [I] String to get bytes from
* ppsa [O] Destination for the array
*
* RETURNS
* Success: S_OK. ppsa contains the strings bytes as a VT_UI1 array.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* See SafeArray.
*/
HRESULT WINAPI SafeArrayGetVartype(
SAFEARRAY* psa,
VARTYPE* pvt)
HRESULT WINAPI VectorFromBstr(BSTR bstr, SAFEARRAY **ppsa)
{
if (psa->fFeatures & FADF_HAVEVARTYPE)
{
/* VT tag @ negative offset 4 in the array descriptor */
*pvt = ((DWORD*)psa)[-1];
return S_OK;
}
if (psa->fFeatures & FADF_RECORD)
{
*pvt = VT_RECORD;
return S_OK;
}
SAFEARRAYBOUND sab;
if (psa->fFeatures & FADF_BSTR)
{
*pvt = VT_BSTR;
return S_OK;
}
TRACE("(%p,%p)\n", bstr, ppsa);
if (!ppsa)
return E_INVALIDARG;
if (psa->fFeatures & FADF_UNKNOWN)
{
*pvt = VT_UNKNOWN;
return S_OK;
}
sab.lLbound = 0;
sab.cElements = SysStringByteLen(bstr);
if (psa->fFeatures & FADF_DISPATCH)
{
*pvt = VT_UNKNOWN; /* Yes, checked against windows */
return S_OK;
}
*ppsa = SAFEARRAY_Create(VT_UI1, 1, &sab, 0);
if (psa->fFeatures & FADF_VARIANT)
{
*pvt = VT_VARIANT;
return S_OK;
}
if (psa->fFeatures & FADF_HAVEIID)
if (*ppsa)
{
/* We could check the IID here, but Windows apparently does not
* do that and returns VT_UNKNOWN for VT_DISPATCH too.
*/
*pvt = VT_UNKNOWN;
memcpy((*ppsa)->pvData, bstr, sab.cElements);
return S_OK;
}
WARN("No vt found for safearray\n");
return E_INVALIDARG;
}
/************************************************************************
* SafeArraySetIID (OLEAUT32.57)
*/
HRESULT WINAPI SafeArraySetIID(SAFEARRAY *arr, REFIID riid) {
IID *xiid = ((IID*)arr)-1;
TRACE("(%p, %s).\n",arr,debugstr_guid(riid));
if (!arr || !(arr->fFeatures & FADF_HAVEIID))
return E_INVALIDARG;
memcpy(xiid, riid, sizeof(GUID));
return S_OK;
return E_OUTOFMEMORY;
}
/************************************************************************
* SafeArrayGetIID (OLEAUT32.67)
* BstrFromVector (OLEAUT32.@)
*
* Create a BSTR from a SafeArray.
*
* PARAMS
* psa [I] Source array
* pbstr [O] Destination for output BSTR
*
* RETURNS
* Success: S_OK. pbstr contains the arrays data.
* Failure: An HRESULT error code indicating the error.
*
* NOTES
* psa must be a 1 dimensional array of a 1 byte type.
*
* NOTES
* See SafeArray.
*/
HRESULT WINAPI SafeArrayGetIID(SAFEARRAY *arr, IID *riid) {
IID *xiid = ((IID*)arr)-1;
TRACE("(%p, %s).\n",arr,debugstr_guid(riid));
HRESULT WINAPI BstrFromVector(SAFEARRAY *psa, BSTR *pbstr)
{
TRACE("(%p,%p)\n", psa, pbstr);
if (!arr || !(arr->fFeatures & FADF_HAVEIID))
if (!pbstr)
return E_INVALIDARG;
memcpy(riid, xiid, sizeof(GUID));
return S_OK;
}
/************************************************************************
* SafeArraySetRecordInfo (OLEAUT32.44)
*/
HRESULT WINAPI SafeArraySetRecordInfo(SAFEARRAY *arr, IRecordInfo *iface) {
LPRECORDINFO oldiface;
*pbstr = NULL;
if (!arr || !(arr->fFeatures & FADF_RECORD))
if (!psa || psa->cbElements != 1 || psa->cDims != 1)
return E_INVALIDARG;
oldiface = ((IRecordInfo**)arr)[-1];
if (oldiface)
IRecordInfo_Release(oldiface);
((IRecordInfo**)arr)[-1] = iface;
if (iface)
IRecordInfo_AddRef(iface);
return S_OK;
}
/************************************************************************
* SafeArrayGetRecordInfo (OLEAUT32.45)
*/
HRESULT WINAPI SafeArrayGetRecordInfo(SAFEARRAY *arr, IRecordInfo** iface) {
if (!arr || !(arr->fFeatures & FADF_RECORD))
return E_INVALIDARG;
*iface = ((IRecordInfo**)arr)[-1];
if (*iface)
IRecordInfo_AddRef(*iface);
*pbstr = SysAllocStringByteLen(psa->pvData, psa->rgsabound[0].cElements);
if (!*pbstr)
return E_OUTOFMEMORY;
return S_OK;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment