diff --git a/dlls/oleaut32/safearray.c b/dlls/oleaut32/safearray.c index 142bda40a55..07264730eaa 100644 --- a/dlls/oleaut32/safearray.c +++ b/dlls/oleaut32/safearray.c @@ -4,6 +4,7 @@ * 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 @@ -84,9 +85,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); /* 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) { @@ -162,11 +160,9 @@ static ULONG SAFEARRAY_GetCellCount(const SAFEARRAY *psa) 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++; } @@ -263,7 +259,7 @@ static SAFEARRAY* SAFEARRAY_CreateVector(VARTYPE vt, LONG lLbound, ULONG cElemen { 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))) @@ -286,10 +282,6 @@ static SAFEARRAY* SAFEARRAY_CreateVector(VARTYPE vt, LONG lLbound, ULONG cElemen } } } - else if (!cElements) - { - ERR("Creating vector of size 0! Please report.\n"); - } return psa; } @@ -300,8 +292,10 @@ static HRESULT SAFEARRAY_DestroyData(SAFEARRAY *psa, ULONG ulStartCell) { 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; @@ -365,9 +359,6 @@ static HRESULT SAFEARRAY_CopyData(SAFEARRAY *psa, SAFEARRAY *dest) { 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)); @@ -554,7 +545,7 @@ HRESULT WINAPI SafeArrayAllocData(SAFEARRAY *psa) hRet = E_OUTOFMEMORY; - if (ulSize != SAFEARRAY_INVALID_CELLS && psa->cbElements) + if (psa->cbElements) { psa->pvData = SAFEARRAY_Malloc(ulSize * psa->cbElements); @@ -888,15 +879,15 @@ HRESULT WINAPI SafeArrayPutElement(SAFEARRAY *psa, LONG *rgIndices, void *pvData } 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; } @@ -907,16 +898,18 @@ HRESULT WINAPI SafeArrayPutElement(SAFEARRAY *psa, LONG *rgIndices, void *pvData { 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); @@ -1024,7 +1017,7 @@ HRESULT WINAPI SafeArrayGetUBound(SAFEARRAY *psa, UINT nDim, LONG *plUbound) 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 + @@ -1057,7 +1050,7 @@ HRESULT WINAPI SafeArrayGetLBound(SAFEARRAY *psa, UINT nDim, LONG *plLbound) 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; @@ -1436,7 +1429,7 @@ HRESULT WINAPI SafeArrayRedim(SAFEARRAY *psa, SAFEARRAYBOUND *psabound) 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) @@ -1465,10 +1458,16 @@ HRESULT WINAPI SafeArrayRedim(SAFEARRAY *psa, SAFEARRAYBOUND *psabound) 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; diff --git a/dlls/oleaut32/tests/safearray.c b/dlls/oleaut32/tests/safearray.c index 632fe5f954a..662bc3fc651 100644 --- a/dlls/oleaut32/tests/safearray.c +++ b/dlls/oleaut32/tests/safearray.c @@ -251,6 +251,34 @@ static void test_safearray(void) 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; @@ -689,14 +717,8 @@ static void test_VectorCreateLockDestroy(void) 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) @@ -922,6 +944,101 @@ static void test_SafeArrayGetPutElement(void) 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]; @@ -1346,4 +1463,6 @@ START_TEST(safearray) test_SafeArrayCreateEx(); test_SafeArrayCopyData(); test_SafeArrayGetPutElement(); + test_SafeArrayGetPutElement_BSTR(); + test_SafeArrayGetPutElement_IUnknown(); }