oleaut32:VatCat fixes initialization and conformance test

Benjamin Arai me at benjaminarai.com
Tue Jul 18 18:44:16 CDT 2006


Changelog:
  - Helps address http://bugs.winehq.com/show_bug.cgi?id=3628
  - Addresses variant initialization and missing conformance test
    issues brought up by Qingdoa Daoo
  - Fixes VarCat conformance test failures exposed by Rob Shearman: 
    "oleaut32: Test the return value of VarCat in the tests."

A test may pass on Windows because it returned without any errors
(S_OK) but on Wine that same test can technically fail but be 
misinterpeted as a correct result in Wine if the expected error code
is returned. Temporary variants may be uninitialized before usage in 
specific cases causing unexpected results.

-------------- next part --------------

---
 dlls/oleaut32/tests/vartest.c |  158 +++++++++++++++++------------------------
 dlls/oleaut32/variant.c       |  122 ++++++++++++++++++++++----------
 2 files changed, 150 insertions(+), 130 deletions(-)

diff --git a/dlls/oleaut32/tests/vartest.c b/dlls/oleaut32/tests/vartest.c
index 642bd94..79bbd9e 100644
--- a/dlls/oleaut32/tests/vartest.c
+++ b/dlls/oleaut32/tests/vartest.c
@@ -5109,6 +5109,7 @@ static void test_VarCat(void)
     TCHAR orig_date_format[128];
     VARTYPE leftvt, rightvt, resultvt;
     HRESULT hres;
+    HRESULT expected_error_num;
 
     /* Set date format for testing */
     lcid = LOCALE_USER_DEFAULT;
@@ -5128,52 +5129,70 @@ static void test_VarCat(void)
 
         for (rightvt = 0; rightvt <= VT_BSTR_BLOB; rightvt++)
         {
-            BOOL bFail = FALSE;
+
             SKIPTESTS(rightvt);
+            expected_error_num = S_OK;
+            resultvt = VT_EMPTY;
 
             if (leftvt == VT_DISPATCH || rightvt == VT_DISPATCH ||
-                leftvt == VT_UNKNOWN || rightvt == VT_UNKNOWN  ||
-                leftvt == VT_RECORD || rightvt == VT_RECORD  ||
-                leftvt == VT_CLSID || rightvt == VT_CLSID ||
-                leftvt == VT_BSTR_BLOB || rightvt == VT_BSTR_BLOB
-                )
-                    continue;
+                    leftvt == VT_UNKNOWN || rightvt == VT_UNKNOWN  ||
+                    leftvt == VT_RECORD || rightvt == VT_RECORD  ||
+                    leftvt == 15 || rightvt == 15 /* Undefined type */)
+                continue;
 
-            if (leftvt == VT_ERROR || rightvt == VT_ERROR)
-                resultvt = VT_EMPTY;
-            else if (leftvt == VT_NULL && rightvt == VT_NULL)
+            if (leftvt == VT_NULL && rightvt == VT_NULL)
                 resultvt = VT_NULL;
+            else if (leftvt == VT_VARIANT && (rightvt == VT_ERROR ||
+                    rightvt == VT_DATE || rightvt == VT_DECIMAL))
+                expected_error_num = DISP_E_TYPEMISMATCH;
             else if ((leftvt == VT_I2 || leftvt == VT_I4 ||
-                leftvt == VT_R4 || leftvt == VT_R8 ||
-                leftvt == VT_CY || leftvt == VT_BOOL ||
-                leftvt == VT_BSTR || leftvt == VT_I1 ||
-                leftvt == VT_UI1 || leftvt == VT_UI2 ||
-                leftvt == VT_UI4 || leftvt == VT_I8 ||
-                leftvt == VT_UI8 || leftvt == VT_INT ||
-                leftvt == VT_UINT || leftvt == VT_EMPTY ||
-                leftvt == VT_NULL || leftvt == VT_DECIMAL ||
-                leftvt == VT_DATE)
-                &&
-                (rightvt == VT_I2 || rightvt == VT_I4 ||
-                rightvt == VT_R4 || rightvt == VT_R8 ||
-                rightvt == VT_CY || rightvt == VT_BOOL ||
-                rightvt == VT_BSTR || rightvt == VT_I1 ||
-                rightvt == VT_UI1 || rightvt == VT_UI2 ||
-                rightvt == VT_UI4 || rightvt == VT_I8 ||
-                rightvt == VT_UI8 || rightvt == VT_INT ||
-                rightvt == VT_UINT || rightvt == VT_EMPTY ||
-                rightvt == VT_NULL || rightvt == VT_DECIMAL ||
-                rightvt == VT_DATE))
-            {
+                    leftvt == VT_R4 || leftvt == VT_R8 ||
+                    leftvt == VT_CY || leftvt == VT_BOOL ||
+                    leftvt == VT_BSTR || leftvt == VT_I1 ||
+                    leftvt == VT_UI1 || leftvt == VT_UI2 ||
+                    leftvt == VT_UI4 || leftvt == VT_I8 ||
+                    leftvt == VT_UI8 || leftvt == VT_INT ||
+                    leftvt == VT_UINT || leftvt == VT_EMPTY ||
+                    leftvt == VT_NULL || leftvt == VT_DECIMAL ||
+                    leftvt == VT_DATE)
+                    &&
+                    (rightvt == VT_I2 || rightvt == VT_I4 ||
+                    rightvt == VT_R4 || rightvt == VT_R8 ||
+                    rightvt == VT_CY || rightvt == VT_BOOL ||
+                    rightvt == VT_BSTR || rightvt == VT_I1 ||
+                    rightvt == VT_UI1 || rightvt == VT_UI2 ||
+                    rightvt == VT_UI4 || rightvt == VT_I8 ||
+                    rightvt == VT_UI8 || rightvt == VT_INT ||
+                    rightvt == VT_UINT || rightvt == VT_EMPTY ||
+                    rightvt == VT_NULL || rightvt == VT_DECIMAL ||
+                    rightvt == VT_DATE))
                 resultvt = VT_BSTR;
-            }
+            else if (rightvt == VT_ERROR && leftvt < VT_VOID)
+                expected_error_num = DISP_E_TYPEMISMATCH;
+            else if (leftvt == VT_ERROR && (rightvt == VT_DATE ||
+                    rightvt == VT_ERROR || rightvt == VT_DECIMAL))
+                expected_error_num = DISP_E_TYPEMISMATCH;
+            else if (rightvt == VT_DATE || rightvt == VT_ERROR ||
+                    rightvt == VT_DECIMAL)
+                expected_error_num = DISP_E_BADVARTYPE;
+            else if (leftvt == VT_ERROR || rightvt == VT_ERROR)
+                expected_error_num = DISP_E_TYPEMISMATCH;
+            else if (leftvt == VT_VARIANT)
+                expected_error_num = DISP_E_TYPEMISMATCH;
+            else if (rightvt == VT_VARIANT && (leftvt == VT_EMPTY ||
+                    leftvt == VT_NULL || leftvt ==  VT_I2 ||
+                    leftvt == VT_I4 || leftvt == VT_R4 ||
+                    leftvt == VT_R8 || leftvt == VT_CY ||
+                    leftvt == VT_DATE || leftvt == VT_BSTR ||
+                    leftvt == VT_BOOL ||  leftvt == VT_DECIMAL ||
+                    leftvt == VT_I1 || leftvt == VT_UI1 ||
+                    leftvt == VT_UI2 || leftvt == VT_UI4 ||
+                    leftvt == VT_I8 || leftvt == VT_UI8 ||
+                    leftvt == VT_INT || leftvt == VT_UINT
+                    ))
+                expected_error_num = DISP_E_TYPEMISMATCH;
             else
-                resultvt = VT_EMPTY;
-
-            if (leftvt == VT_ERROR || rightvt == VT_ERROR)
-            {
-                bFail = TRUE;
-            }
+                expected_error_num = DISP_E_BADVARTYPE;
 
             V_VT(&left) = leftvt;
             V_VT(&right) = rightvt;
@@ -5192,57 +5211,16 @@ static void test_VarCat(void)
                 VarDecFromR8(0.0, &V_DECIMAL(&right));
 
             hres = VarCat(&left, &right, &result);
-            if (bFail) {
-                /* Determine the error code for the vt combination */
-                HRESULT expected_error_num = S_OK;
-                if (rightvt == VT_ERROR && leftvt <= VT_VOID)
-                    expected_error_num = DISP_E_TYPEMISMATCH;
-                else if (leftvt == VT_ERROR && (rightvt == VT_DATE ||
-                    rightvt == VT_ERROR || rightvt == VT_DECIMAL))
-                    expected_error_num = DISP_E_TYPEMISMATCH;
-                else if (rightvt == VT_DATE || rightvt == VT_ERROR ||
-                    rightvt == VT_DECIMAL)
-                    expected_error_num = DISP_E_BADVARTYPE;
-                else if (leftvt == VT_ERROR || rightvt == VT_ERROR)
-                    expected_error_num = DISP_E_TYPEMISMATCH;
-
-                ok(hres == DISP_E_BADVARTYPE || hres == E_INVALIDARG ||
-                    hres == DISP_E_TYPEMISMATCH,
-                    "VarCat: %d, %d: Expected failure 0x%lX, got 0x%lX\n",
-                    leftvt, rightvt, expected_error_num, hres);
-            }
-            else
-            {
-                ok(V_VT(&result) == resultvt,
-                    "VarCat: %d, %d: expected vt %d, got vt %d\n",
-                    leftvt, rightvt, resultvt, V_VT(&result));
-                if (hres != S_OK)
-                {
-                    HRESULT expected_error_num;
-                    if (leftvt == VT_VARIANT && rightvt == VT_ERROR)
-                        expected_error_num = DISP_E_BADVARTYPE;
-                    else if (leftvt == VT_VARIANT)
-                        expected_error_num = DISP_E_TYPEMISMATCH;
-                    else if (rightvt == VT_VARIANT && (leftvt == VT_EMPTY ||
-                        leftvt == VT_NULL || leftvt ==  VT_I2 ||
-                        leftvt == VT_I4 || leftvt == VT_R4 ||
-                        leftvt == VT_R8 || leftvt == VT_CY ||
-                        leftvt == VT_DATE || leftvt == VT_BSTR ||
-                        leftvt == VT_BOOL ||  leftvt == VT_DECIMAL ||
-                        leftvt == VT_I1 || leftvt == VT_UI1 ||
-                        leftvt == VT_UI2 || leftvt == VT_UI4 ||
-                        leftvt == VT_I8 || leftvt == VT_UI8 ||
-                        leftvt == VT_INT || leftvt == VT_UINT
-                        ))
-                        expected_error_num = DISP_E_TYPEMISMATCH;
-                    else
-                        expected_error_num = DISP_E_BADVARTYPE;
 
-                    ok(hres == expected_error_num,
-                        "VarCat: %d, %d: Expected failure 0x%lX, got 0x%lX\n",
-                        leftvt, rightvt, expected_error_num, hres);
-                }
-            }
+            /* Determine the error code for the vt combination */
+            ok(hres == expected_error_num,
+                "VarCat: %d, %d returned error, 0x%lX expected 0x%lX.\n",
+                leftvt, rightvt, expected_error_num, hres);
+
+            /* Check types are correct */
+            ok(V_VT(&result) == resultvt,
+                "VarCat: %d, %d: expected vt %d, got vt %d\n",
+                leftvt, rightvt, resultvt, V_VT(&result));
 
             VariantClear(&left);
             VariantClear(&right);
@@ -5272,9 +5250,7 @@ static void test_VarCat(void)
     V_VT(&left) = VT_ERROR;
     V_VT(&right) = VT_BSTR;
     hres = VarCat(&left,&right,&result);
-    todo_wine {
     ok(hres == DISP_E_TYPEMISMATCH, "VarCat should have returned DISP_E_TYPEMISMATCH instead of 0x%08lx\n", hres);
-    }
     ok(V_VT(&result) == VT_EMPTY,
         "VarCat: VT_ERROR concat with VT_BSTR should have returned VT_EMPTY\n");
 
@@ -5285,9 +5261,7 @@ static void test_VarCat(void)
     V_VT(&left) = VT_BSTR;
     V_VT(&right) = VT_ERROR;
     hres = VarCat(&left,&right,&result);
-    todo_wine {
     ok(hres == DISP_E_TYPEMISMATCH, "VarCat should have returned DISP_E_TYPEMISMATCH instead of 0x%08lx\n", hres);
-    }
     ok(V_VT(&result) == VT_EMPTY,
         "VarCat: VT_BSTR concat with VT_ERROR should have returned VT_EMPTY\n");
 
diff --git a/dlls/oleaut32/variant.c b/dlls/oleaut32/variant.c
index 2de8550..c3691b6 100644
--- a/dlls/oleaut32/variant.c
+++ b/dlls/oleaut32/variant.c
@@ -2444,60 +2444,97 @@ VarNumFromParseNum_DecOverflow:
  */
 HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out)
 {
-    VARTYPE leftvt,rightvt;
+    VARTYPE leftvt,rightvt,resultvt;
     HRESULT hres;
     static const WCHAR str_true[] = {'T','r','u','e','\0'};
     static const WCHAR str_false[] = {'F','a','l','s','e','\0'};
+    static const WCHAR sz_empty[] = {'\0'};
     leftvt = V_VT(left);
     rightvt = V_VT(right);
 
     TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left),
           debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), out);
 
-    /* Null and Null simply return Null */
+    /* when both left and right are NULL the result is NULL */
     if (leftvt == VT_NULL && rightvt == VT_NULL)
     {
         V_VT(out) = VT_NULL;
         return S_OK;
     }
 
-    /* VT_ERROR with any other value should return VT_NULL */
-    else if (V_VT(left) == VT_ERROR || V_VT(right) == VT_ERROR)
+    hres = S_OK;
+    resultvt = VT_EMPTY;
+
+    /* There are many special case for errors and return types */
+    if (leftvt == VT_VARIANT && (rightvt == VT_ERROR ||
+            rightvt == VT_DATE || rightvt == VT_DECIMAL))
+        hres = DISP_E_TYPEMISMATCH;
+    else if ((leftvt == VT_I2 || leftvt == VT_I4 ||
+            leftvt == VT_R4 || leftvt == VT_R8 ||
+            leftvt == VT_CY || leftvt == VT_BOOL ||
+            leftvt == VT_BSTR || leftvt == VT_I1 ||
+            leftvt == VT_UI1 || leftvt == VT_UI2 ||
+            leftvt == VT_UI4 || leftvt == VT_I8 ||
+            leftvt == VT_UI8 || leftvt == VT_INT ||
+            leftvt == VT_UINT || leftvt == VT_EMPTY ||
+            leftvt == VT_NULL || leftvt == VT_DECIMAL ||
+            leftvt == VT_DATE)
+            &&
+            (rightvt == VT_I2 || rightvt == VT_I4 ||
+            rightvt == VT_R4 || rightvt == VT_R8 ||
+            rightvt == VT_CY || rightvt == VT_BOOL ||
+            rightvt == VT_BSTR || rightvt == VT_I1 ||
+            rightvt == VT_UI1 || rightvt == VT_UI2 ||
+            rightvt == VT_UI4 || rightvt == VT_I8 ||
+            rightvt == VT_UI8 || rightvt == VT_INT ||
+            rightvt == VT_UINT || rightvt == VT_EMPTY ||
+            rightvt == VT_NULL || rightvt == VT_DECIMAL ||
+            rightvt == VT_DATE))
+        resultvt = VT_BSTR;
+    else if (rightvt == VT_ERROR && leftvt < VT_VOID)
+        hres = DISP_E_TYPEMISMATCH;
+    else if (leftvt == VT_ERROR && (rightvt == VT_DATE ||
+            rightvt == VT_ERROR || rightvt == VT_DECIMAL))
+        hres = DISP_E_TYPEMISMATCH;
+    else if (rightvt == VT_DATE || rightvt == VT_ERROR ||
+            rightvt == VT_DECIMAL)
+        hres = DISP_E_BADVARTYPE;
+    else if (leftvt == VT_ERROR || rightvt == VT_ERROR)
+        hres = DISP_E_TYPEMISMATCH;
+    else if (leftvt == VT_VARIANT)
+        hres = DISP_E_TYPEMISMATCH;
+    else if (rightvt == VT_VARIANT && (leftvt == VT_EMPTY ||
+            leftvt == VT_NULL || leftvt ==  VT_I2 ||
+            leftvt == VT_I4 || leftvt == VT_R4 ||
+            leftvt == VT_R8 || leftvt == VT_CY ||
+            leftvt == VT_DATE || leftvt == VT_BSTR ||
+            leftvt == VT_BOOL ||  leftvt == VT_DECIMAL ||
+            leftvt == VT_I1 || leftvt == VT_UI1 ||
+            leftvt == VT_UI2 || leftvt == VT_UI4 ||
+            leftvt == VT_I8 || leftvt == VT_UI8 ||
+            leftvt == VT_INT || leftvt == VT_UINT))
+        hres = DISP_E_TYPEMISMATCH;
+    else
+        hres = DISP_E_BADVARTYPE;
+
+    /* if resutl type is not S_OK, then no need to go further */
+    if (hres != S_OK)
     {
-        V_VT(out) = VT_EMPTY;
-        return DISP_E_BADVARTYPE;
+        V_VT(out) = resultvt;
+        return hres;
     }
-
-   /* Concat all type that match conformance test */
-    if ((leftvt == VT_I2 || leftvt == VT_I4 ||
-        leftvt == VT_R4 || leftvt == VT_R8 ||
-        leftvt == VT_CY || leftvt == VT_BOOL ||
-        leftvt == VT_BSTR || leftvt == VT_I1 ||
-        leftvt == VT_UI1 || leftvt == VT_UI2 ||
-        leftvt == VT_UI4 || leftvt == VT_I8 ||
-        leftvt == VT_UI8 || leftvt == VT_INT ||
-        leftvt == VT_UINT || leftvt == VT_EMPTY ||
-        leftvt == VT_NULL || leftvt == VT_DATE ||
-        leftvt == VT_DECIMAL)
-        &&
-        (rightvt == VT_I2 || rightvt == VT_I4 ||
-        rightvt == VT_R4 || rightvt == VT_R8 ||
-        rightvt == VT_CY || rightvt == VT_BOOL ||
-        rightvt == VT_BSTR || rightvt == VT_I1 ||
-        rightvt == VT_UI1 || rightvt == VT_UI2 ||
-        rightvt == VT_UI4 || rightvt == VT_I8 ||
-        rightvt == VT_UI8 || rightvt == VT_INT ||
-        rightvt == VT_UINT || rightvt == VT_EMPTY ||
-        rightvt == VT_NULL || rightvt == VT_DATE ||
-        rightvt == VT_DECIMAL))
+    /* Else proceed with formatting inputs to strings */
+    else
     {
         VARIANT bstrvar_left, bstrvar_right;
         V_VT(out) = VT_BSTR;
 
+        VariantInit(&bstrvar_left);
+        VariantInit(&bstrvar_right);
+
         /* Convert left side variant to string */
         if (leftvt != VT_BSTR)
         {
-            VariantInit(&bstrvar_left);
             if (leftvt == VT_BOOL)
             {
                 /* Bools are handled as True/False strings instead of 0/-1 as in MSDN */
@@ -2507,6 +2544,12 @@ HRESULT WINAPI VarCat(LPVARIANT left, LP
                 else
                     V_BSTR(&bstrvar_left) = SysAllocString(str_false);
             }
+            /* Fill with empty string for later concat with right side */
+            else if (leftvt == VT_NULL)
+            {
+                V_VT(&bstrvar_left) = VT_BSTR;
+                V_BSTR(&bstrvar_left) = SysAllocString(sz_empty);
+            }
             else
             {
                 hres = VariantChangeTypeEx(&bstrvar_left,left,0,0,VT_BSTR);
@@ -2523,8 +2566,8 @@ HRESULT WINAPI VarCat(LPVARIANT left, LP
                         rightvt == VT_UI2 || rightvt == VT_UI4 ||
                         rightvt == VT_I8 || rightvt == VT_UI8 ||
                         rightvt == VT_INT || rightvt == VT_UINT))
-                        return DISP_E_BADVARTYPE;
-                    return hres;
+                        return DISP_E_TYPEMISMATCH;
+                    return DISP_E_TYPEMISMATCH;
                 }
             }
         }
@@ -2532,7 +2575,6 @@ HRESULT WINAPI VarCat(LPVARIANT left, LP
         /* convert right side variant to string */
         if (rightvt != VT_BSTR)
         {
-            VariantInit(&bstrvar_right);
             if (rightvt == VT_BOOL)
             {
                 /* Bools are handled as True/False strings instead of 0/-1 as in MSDN */
@@ -2542,6 +2584,12 @@ HRESULT WINAPI VarCat(LPVARIANT left, LP
                 else
                     V_BSTR(&bstrvar_right) = SysAllocString(str_false);
             }
+            /* Fill with empty string for later concat with right side */
+            else if (rightvt == VT_NULL)
+            {
+                V_VT(&bstrvar_right) = VT_BSTR;
+                V_BSTR(&bstrvar_right) = SysAllocString(sz_empty);
+            }
             else
             {
                 hres = VariantChangeTypeEx(&bstrvar_right,right,0,0,VT_BSTR);
@@ -2558,8 +2606,8 @@ HRESULT WINAPI VarCat(LPVARIANT left, LP
                         leftvt == VT_UI2 || leftvt == VT_UI4 ||
                         leftvt == VT_I8 || leftvt == VT_UI8 ||
                         leftvt == VT_INT || leftvt == VT_UINT))
-                        return DISP_E_BADVARTYPE;
-                    return hres;
+                        return DISP_E_TYPEMISMATCH;
+                    return DISP_E_TYPEMISMATCH;
                 }
             }
         }
@@ -2578,11 +2626,9 @@ HRESULT WINAPI VarCat(LPVARIANT left, LP
         VariantClear(&bstrvar_right);
         return S_OK;
     }
-
-    V_VT(out) = VT_EMPTY;
-    return S_OK;
 }
 
+
 /* Wrapper around VariantChangeTypeEx() which permits changing a
    variant with VT_RESERVED flag set. Needed by VarCmp. */
 static HRESULT _VarChangeTypeExWrap (VARIANTARG* pvargDest,
-- 
1.4.0



More information about the wine-patches mailing list