* This file contains the implementation of the SafeArray functions.
*
* Copyright 1999 Sylvain St-Germain
+ * Copyright 2002-2003 Marcus Meissner
* Copyright 2003 Jon Griffiths
*
* This library is free software; you can redistribute it and/or
/* 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)
{
while (cCount--)
{
+ /* This is a valid bordercase. See testcases. -Marcus */
if (!psab->cElements)
- {
- ERR("Dimension has size=0! Please report.\n");
- return SAFEARRAY_INVALID_CELLS;
- }
+ return 0;
ulNumCells *= psab->cElements;
psab++;
}
{
SAFEARRAY *psa = NULL;
- if (cElements && (vt == VT_RECORD || ulSize))
+ if (ulSize || (vt == VT_RECORD))
{
/* Allocate the header and data together */
if (SUCCEEDED(SAFEARRAY_AllocDescriptor(sizeof(SAFEARRAY) + ulSize * cElements, &psa)))
}
}
}
- else if (!cElements)
- {
- ERR("Creating vector of size 0! Please report.\n");
- }
return psa;
}
{
ULONG ulCellCount = SAFEARRAY_GetCellCount(psa);
- if (ulCellCount == SAFEARRAY_INVALID_CELLS || ulStartCell > ulCellCount)
+ if (ulStartCell > ulCellCount) {
+ FIXME("unexpted ulcellcount %ld, start %ld\n",ulCellCount,ulStartCell);
return E_UNEXPECTED;
+ }
ulCellCount -= ulStartCell;
{
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));
hRet = E_OUTOFMEMORY;
- if (ulSize != SAFEARRAY_INVALID_CELLS && psa->cbElements)
+ if (psa->cbElements)
{
psa->pvData = SAFEARRAY_Malloc(ulSize * psa->cbElements);
}
else if (psa->fFeatures & FADF_BSTR)
{
- BSTR* lpBstr = (BSTR*)pvData;
+ BSTR lpBstr = (BSTR)pvData;
BSTR* lpDest = (BSTR*)lpvDest;
if (*lpDest)
SysFreeString(*lpDest);
- if (*lpBstr)
+ if (lpBstr)
{
- *lpDest = SysAllocStringLen(*lpBstr, SysStringLen(*lpBstr));
+ *lpDest = SysAllocStringLen(lpBstr, SysStringLen(lpBstr));
if (!*lpDest)
hRet = E_OUTOFMEMORY;
}
{
if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH))
{
- LPUNKNOWN *lpUnknown = (LPUNKNOWN *)pvData;
+ LPUNKNOWN lpUnknown = (LPUNKNOWN)pvData;
LPUNKNOWN *lpDest = (LPUNKNOWN *)lpvDest;
- if (*lpUnknown)
- IUnknown_AddRef(*lpUnknown);
+ if (lpUnknown)
+ IUnknown_AddRef(lpUnknown);
if (*lpDest)
IUnknown_Release(*lpDest);
- }
- /* Copy the data over */
- memcpy(lpvDest, pvData, psa->cbElements);
+ *lpDest = lpUnknown;
+ } else {
+ /* Copy the data over */
+ memcpy(lpvDest, pvData, psa->cbElements);
+ }
}
}
SafeArrayUnlock(psa);
if (!psa || !plUbound)
return E_INVALIDARG;
- if(!nDim || nDim > psa->cDims || !psa->rgsabound[nDim - 1].cElements)
+ if(!nDim || nDim > psa->cDims)
return DISP_E_BADINDEX;
*plUbound = psa->rgsabound[nDim - 1].lLbound +
if (!psa || !plLbound)
return E_INVALIDARG;
- if(!nDim || nDim > psa->cDims || !psa->rgsabound[nDim - 1].cElements)
+ if(!nDim || nDim > psa->cDims)
return DISP_E_BADINDEX;
*plLbound = psa->rgsabound[nDim - 1].lLbound;
TRACE("(%p,%p)\n", psa, psabound);
- if (!psa || psa->fFeatures & FADF_FIXEDSIZE || !psabound || !psabound->cElements)
+ if (!psa || psa->fFeatures & FADF_FIXEDSIZE || !psabound)
return E_INVALIDARG;
if (psa->cLocks > 0)
PVOID pvNewData;
ulOldSize = SAFEARRAY_GetCellCount(psa);
- ulNewSize = (ulOldSize / oldBounds->cElements) * psabound->cElements;
+ if (ulOldSize)
+ ulNewSize = (ulOldSize / oldBounds->cElements) * psabound->cElements;
+ else {
+ int oldelems = oldBounds->cElements;
+ oldBounds->cElements = psabound->cElements;
+ ulNewSize = SAFEARRAY_GetCellCount(psa);
+ oldBounds->cElements = oldelems;
+ }
- if (ulOldSize == SAFEARRAY_INVALID_CELLS ||
- !(pvNewData = SAFEARRAY_Malloc(ulNewSize)))
+ if (!(pvNewData = SAFEARRAY_Malloc(ulNewSize)))
{
SafeArrayUnlock(psa);
return E_UNEXPECTED;
a = SafeArrayCreate(-1, 1, &bound);
ok(NULL == a,"SAC(-1,1,[1,0]) not failed?\n");
+ bound.cElements = 0;
+ bound.lLbound = 42;
+ a = SafeArrayCreate(VT_I4, 1, &bound);
+ ok(NULL != a,"SAC(VT_I4,1,[0,0]) failed.\n");
+
+ hres = SafeArrayGetLBound(a, 1, &l);
+ ok(hres == S_OK, "SAGLB of 0 size dimensioned array failed with %lx\n",hres);
+ ok(l == 42, "SAGLB of 0 size dimensioned array failed to return 42, but returned %ld\n",l);
+ hres = SafeArrayGetUBound(a, 1, &l);
+ ok(hres == S_OK, "SAGUB of 0 size dimensioned array failed with %lx\n",hres);
+ ok(l == 41, "SAGUB of 0 size dimensioned array failed to return 41, but returned %ld\n",l);
+ bound.cElements = 2;
+ hres = SafeArrayRedim(a, &bound);
+ ok(hres == S_OK,"SAR of a 0 elements dimension failed with hres %lx\n", hres);
+ bound.cElements = 0;
+ hres = SafeArrayRedim(a, &bound);
+ ok(hres == S_OK,"SAR to a 0 elements dimension failed with hres %lx\n", hres);
+ hres = SafeArrayDestroy(a);
+ ok(hres == S_OK,"SAD of 0 dim array faild with hres %lx\n", hres);
+
+ bounds[0].cElements = 0; bounds[0].lLbound = 1;
+ bounds[1].cElements = 2; bounds[1].lLbound = 23;
+ a = SafeArrayCreate(VT_I4,2,bounds);
+ ok(a != NULL,"SAC(VT_INT32,2,...) with 0 element dim failed.\n");
+ bounds[0].cElements = 1; bounds[0].lLbound = 1;
+ bounds[1].cElements = 0; bounds[1].lLbound = 23;
+ a = SafeArrayCreate(VT_I4,2,bounds);
+ ok(a != NULL,"SAC(VT_INT32,2,...) with 0 element dim failed.\n");
bounds[0].cElements = 42; bounds[0].lLbound = 1;
bounds[1].cElements = 2; bounds[1].lLbound = 23;
VARTYPE vt;
int element;
-#if 0
- /* Native allows you to to create 0 sized vectors. Its an ERR in Wine, lets
- * see if anyone reports it before supporting this brain damage. Actually
- * using the returned array just crashes in native anyway.
- */
sa = SafeArrayCreateVector(VT_UI1, 0, 0);
- ok(sa == NULL, "0 elements didn't fail\n");
-#endif
+ ok(sa != NULL, "SACV with 0 elements failed.\n");
/* Test all VARTYPES in different lengths */
for (element = 1; element <= 101; element += 10)
SafeArrayDestroy(sa);
}
+static void test_SafeArrayGetPutElement_BSTR(void)
+{
+ SAFEARRAYBOUND sab;
+ LONG indices[1];
+ SAFEARRAY *sa;
+ HRESULT hres;
+ BSTR value = 0, gotvalue;
+ const OLECHAR szTest[5] = { 'T','e','s','t','\0' };
+
+ sab.lLbound = 1;
+ sab.cElements = 1;
+
+ sa = SafeArrayCreate(VT_BSTR, 1, &sab);
+ ok(sa != NULL, "BSTR test couldn't create array\n");
+ if (!sa)
+ return;
+
+ ok(sa->cbElements == sizeof(BSTR), "BSTR size mismatch\n");
+ if (sa->cbElements != sizeof(BSTR))
+ return;
+
+ indices[0] = sab.lLbound;
+ value = SysAllocString(szTest);
+ ok (value != NULL, "Expected non-NULL\n");
+ hres = SafeArrayPutElement(sa, indices, value);
+ ok(hres == S_OK, "Failed to put bstr element hres 0x%lx\n", hres);
+ gotvalue = NULL;
+ hres = SafeArrayGetElement(sa, indices, &gotvalue);
+ ok(hres == S_OK, "Failed to get bstr element at hres 0x%lx\n", hres);
+ if (hres == S_OK)
+ ok(SysStringLen(value) == SysStringLen(gotvalue), "Got len %d instead of %d\n", SysStringLen(gotvalue), SysStringLen(value));
+ SafeArrayDestroy(sa);
+}
+
+static int tunk_xref = 0;
+static HRESULT WINAPI tunk_QueryInterface(LPUNKNOWN punk,REFIID riid, LPVOID *x) {
+ return E_FAIL;
+}
+static ULONG WINAPI tunk_AddRef(LPUNKNOWN punk) {
+ return ++tunk_xref;
+}
+
+static ULONG WINAPI tunk_Release(LPUNKNOWN punk) {
+ return --tunk_xref;
+}
+
+static ICOM_VTABLE(IUnknown) xtunk_vtbl = {
+ ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+ tunk_QueryInterface,
+ tunk_AddRef,
+ tunk_Release
+};
+
+static struct xtunk_iface {
+ ICOM_VTABLE(IUnknown) *lpvtbl;
+} xtunk_iface;
+
+
+static void test_SafeArrayGetPutElement_IUnknown(void)
+{
+ SAFEARRAYBOUND sab;
+ LONG indices[1];
+ SAFEARRAY *sa;
+ HRESULT hres;
+ LPUNKNOWN value = 0, gotvalue;
+
+ sab.lLbound = 1;
+ sab.cElements = 1;
+ sa = SafeArrayCreate(VT_UNKNOWN, 1, &sab);
+ ok(sa != NULL, "UNKNOWN test couldn't create array\n");
+ if (!sa)
+ return;
+
+ ok(sa->cbElements == sizeof(LPUNKNOWN), "LPUNKNOWN size mismatch\n");
+ if (sa->cbElements != sizeof(LPUNKNOWN))
+ return;
+
+ indices[0] = sab.lLbound;
+ xtunk_iface.lpvtbl = &xtunk_vtbl;
+ value = (LPUNKNOWN)&xtunk_iface;
+ tunk_xref = 1;
+ ok (value != NULL, "Expected non-NULL\n");
+ hres = SafeArrayPutElement(sa, indices, value);
+ ok(hres == S_OK, "Failed to put bstr element hres 0x%lx\n", hres);
+ ok(tunk_xref == 2,"Failed to increment refcount of iface.\n");
+ gotvalue = NULL;
+ hres = SafeArrayGetElement(sa, indices, &gotvalue);
+ ok(tunk_xref == 3,"Failed to increment refcount of iface.\n");
+ ok(hres == S_OK, "Failed to get bstr element at hres 0x%lx\n", hres);
+ if (hres == S_OK)
+ ok(value == gotvalue, "Got %p instead of %p\n", gotvalue, value);
+ SafeArrayDestroy(sa);
+ ok(tunk_xref == 2,"Failed to decrement refcount of iface.\n");
+}
+
static void test_SafeArrayCopyData(void)
{
SAFEARRAYBOUND sab[4];
test_SafeArrayCreateEx();
test_SafeArrayCopyData();
test_SafeArrayGetPutElement();
+ test_SafeArrayGetPutElement_BSTR();
+ test_SafeArrayGetPutElement_IUnknown();
}