PATCH: safearray regression fixes

Marcus Meissner marcus at jet.franken.de
Mon Dec 29 16:18:53 CST 2003


Hi,

This fixes 3 InstallShield regressions introduced by the last safearray rewrite.

I have written testcases for all changed behaviour and verified with both
builtin and "WINEDLLOVERRIDES=oleaut32=n wine oleaut32_test.exe.so safearray".

The installshield Installer I use now fails the same way as before (and not with
safearray related errors).

Ciao, Marcus

Changelog:
	Dimensions with cElements=0 are valid and needed by InstallShield.
	SafeArrayGetElement: fixed BSTR and LPUNKNOWN handling.
	
	Added testcases for above cases.

Index: dlls/oleaut32/safearray.c
===================================================================
RCS file: /home/wine/wine/dlls/oleaut32/safearray.c,v
retrieving revision 1.29
diff -u -r1.29 safearray.c
--- dlls/oleaut32/safearray.c	15 Dec 2003 21:08:42 -0000	1.29
+++ dlls/oleaut32/safearray.c	29 Dec 2003 21:53:32 -0000
@@ -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 @@
 /* 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 @@
 
   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 @@
 {
   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 @@
       }
     }
   }
-  else if (!cElements)
-  {
-    ERR("Creating vector of size 0! Please report.\n");
-  }
   return psa;
 }
 
@@ -300,8 +292,10 @@
   {
     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 @@
   {
     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 @@
 
     hRet = E_OUTOFMEMORY;
 
-    if (ulSize != SAFEARRAY_INVALID_CELLS && psa->cbElements)
+    if (psa->cbElements)
     {
       psa->pvData = SAFEARRAY_Malloc(ulSize * psa->cbElements);
 
@@ -888,15 +879,15 @@
       }
       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 @@
       {
         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 @@
   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 @@
   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 +1426,7 @@
 
   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 +1455,16 @@
       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;
Index: dlls/oleaut32/tests/safearray.c
===================================================================
RCS file: /home/wine/wine/dlls/oleaut32/tests/safearray.c,v
retrieving revision 1.9
diff -u -r1.9 safearray.c
--- dlls/oleaut32/tests/safearray.c	15 Dec 2003 21:11:25 -0000	1.9
+++ dlls/oleaut32/tests/safearray.c	29 Dec 2003 21:53:36 -0000
@@ -251,6 +251,34 @@
 	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 @@
   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 @@
   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 @@
     test_SafeArrayCreateEx();
     test_SafeArrayCopyData();
     test_SafeArrayGetPutElement();
+    test_SafeArrayGetPutElement_BSTR();
+    test_SafeArrayGetPutElement_IUnknown();
 }
-- 



More information about the wine-patches mailing list