Dimensions with cElements=0 are valid and needed by InstallShield.

SafeArrayGetElement: fixed BSTR and LPUNKNOWN handling.
Added testcases for above cases.
This commit is contained in:
Marcus Meissner 2003-12-30 19:06:41 +00:00 committed by Alexandre Julliard
parent 09c8cc97f7
commit e12ef562a8
2 changed files with 157 additions and 39 deletions

View File

@ -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;

View File

@ -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();
}