[v6 PATCH] oleaut32: Improve support for IDispatch in VarCat

Alistair Leslie-Hughes leslie_alistair at hotmail.com
Thu May 11 19:11:53 CDT 2017


Fixes https://bugs.winehq.org/show_bug.cgi?id=27106

v6 - Simplify the code when the Variant cannot be coerced.

Signed-off-by: Alistair Leslie-Hughes <leslie_alistair at hotmail.com>
---
 dlls/oleaut32/tests/vartest.c | 217 ++++++++++++++++++++++++++++++++++++++++++
 dlls/oleaut32/variant.c       |  52 +++-------
 2 files changed, 229 insertions(+), 40 deletions(-)

diff --git a/dlls/oleaut32/tests/vartest.c b/dlls/oleaut32/tests/vartest.c
index 0e86ffb..7d781e7 100644
--- a/dlls/oleaut32/tests/vartest.c
+++ b/dlls/oleaut32/tests/vartest.c
@@ -97,6 +97,150 @@ static BOOL has_i8;
 #define R8_MAX DBL_MAX
 #define R8_MIN DBL_MIN
 
+#define DEFINE_EXPECT(func) \
+    static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
+
+#define SET_EXPECT(func) \
+    do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0)
+
+#define CHECK_EXPECT2(func) \
+    do { \
+        ok(expect_ ##func, "unexpected call " #func "\n"); \
+        called_ ## func = TRUE; \
+    }while(0)
+
+#define CHECK_EXPECT(func) \
+    do { \
+        CHECK_EXPECT2(func); \
+        expect_ ## func = FALSE; \
+    }while(0)
+
+#define CHECK_CALLED(func) \
+    do { \
+        ok(called_ ## func, "expected " #func "\n"); \
+        expect_ ## func = called_ ## func = FALSE; \
+    }while(0)
+
+DEFINE_EXPECT(dispatch_invoke);
+
+typedef struct
+{
+    IDispatch IDispatch_iface;
+    VARTYPE vt;
+    HRESULT result;
+} DummyDispatch;
+
+static inline DummyDispatch *impl_from_IDispatch(IDispatch *iface)
+{
+    return CONTAINING_RECORD(iface, DummyDispatch, IDispatch_iface);
+}
+
+static ULONG WINAPI DummyDispatch_AddRef(IDispatch *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI DummyDispatch_Release(IDispatch *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI DummyDispatch_QueryInterface(IDispatch *iface,
+                                                   REFIID riid,
+                                                   void** ppvObject)
+{
+    *ppvObject = NULL;
+
+    if (IsEqualIID(riid, &IID_IDispatch) ||
+        IsEqualIID(riid, &IID_IUnknown))
+    {
+        *ppvObject = iface;
+        IDispatch_AddRef(iface);
+    }
+
+    return *ppvObject ? S_OK : E_NOINTERFACE;
+}
+
+static HRESULT WINAPI DummyDispatch_GetTypeInfoCount(IDispatch *iface, UINT *pctinfo)
+{
+    ok(0, "Unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DummyDispatch_GetTypeInfo(IDispatch *iface, UINT tinfo, LCID lcid, ITypeInfo **ti)
+{
+    ok(0, "Unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DummyDispatch_GetIDsOfNames(IDispatch *iface, REFIID riid, LPOLESTR *names,
+    UINT cnames, LCID lcid, DISPID *dispid)
+{
+    ok(0, "Unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DummyDispatch_Invoke(IDispatch *iface,
+                                           DISPID dispid, REFIID riid,
+                                           LCID lcid, WORD wFlags,
+                                           DISPPARAMS *params,
+                                           VARIANT *res,
+                                           EXCEPINFO *ei,
+                                           UINT *arg_err)
+{
+    DummyDispatch *This = impl_from_IDispatch(iface);
+
+    CHECK_EXPECT(dispatch_invoke);
+
+    ok(dispid == DISPID_VALUE, "got dispid %d\n", dispid);
+    ok(IsEqualIID(riid, &IID_NULL), "go riid %s\n", wine_dbgstr_guid(riid));
+    ok(wFlags == DISPATCH_PROPERTYGET, "Flags wrong\n");
+
+    ok(params->rgvarg == NULL, "got %p\n", params->rgvarg);
+    ok(params->rgdispidNamedArgs == NULL, "got %p\n", params->rgdispidNamedArgs);
+    ok(params->cArgs == 0, "got %d\n", params->cArgs);
+    ok(params->cNamedArgs == 0, "got %d\n", params->cNamedArgs);
+
+    ok(res != NULL, "got %p\n", res);
+    ok(V_VT(res) == VT_EMPTY, "got %d\n", V_VT(res));
+    ok(ei == NULL, "got %p\n", ei);
+    ok(arg_err == NULL, "got %p\n", arg_err);
+
+    if (FAILED(This->result))
+        return FAILED(This->result);
+
+    V_VT(res) = This->vt;
+    if (This->vt == VT_UI1)
+        V_UI1(res) = 34;
+    else if (This->vt == VT_NULL)
+    {
+        V_VT(res) = VT_NULL;
+        V_BSTR(res) = NULL;
+    }
+    else
+        memset(res, 0, sizeof(*res));
+
+    return S_OK;
+}
+
+static const IDispatchVtbl DummyDispatch_VTable =
+{
+    DummyDispatch_QueryInterface,
+    DummyDispatch_AddRef,
+    DummyDispatch_Release,
+    DummyDispatch_GetTypeInfoCount,
+    DummyDispatch_GetTypeInfo,
+    DummyDispatch_GetIDsOfNames,
+    DummyDispatch_Invoke
+};
+
+static void init_test_dispatch(VARTYPE vt, DummyDispatch *dispatch)
+{
+    dispatch->IDispatch_iface.lpVtbl = &DummyDispatch_VTable;
+    dispatch->vt = vt;
+    dispatch->result = S_OK;
+}
+
 typedef struct IRecordInfoImpl
 {
     IRecordInfo IRecordInfo_iface;
@@ -5607,6 +5751,7 @@ static void test_VarCat(void)
     HRESULT hres;
     HRESULT expected_error_num;
     int cmp;
+    DummyDispatch dispatch;
 
     CHECKPTR(VarCat);
 
@@ -5941,6 +6086,78 @@ static void test_VarCat(void)
     VariantClear(&result);
     VariantClear(&expected);
 
+    /* Dispatch conversion */
+    init_test_dispatch(VT_NULL, &dispatch);
+    V_VT(&left) = VT_DISPATCH;
+    V_DISPATCH(&left) = &dispatch.IDispatch_iface;
+
+    V_VT(&expected) = VT_BSTR;
+    V_BSTR(&expected)= SysAllocString(sz_empty);
+
+    SET_EXPECT(dispatch_invoke);
+    hres = VarCat(&left, &right, &result);
+    ok(hres == S_OK, "got 0x%08x\n", hres);
+    ok(V_VT(&result) == VT_BSTR, "got %d\n", V_VT(&result));
+    ok(SysStringLen(V_BSTR(&result)) == 0, "got %d\n", SysStringLen(V_BSTR(&result)));
+    CHECK_CALLED(dispatch_invoke);
+    ok(VarCmp(&result,&expected,lcid,0) == VARCMP_EQ, "VarCat: DISPATCH concat with EMPTY did not return empty VT_BSTR\n");
+
+    VariantClear(&left);
+    VariantClear(&right);
+    VariantClear(&result);
+    VariantClear(&expected);
+
+    init_test_dispatch(VT_NULL, &dispatch);
+    V_VT(&right) = VT_DISPATCH;
+    V_DISPATCH(&right) = &dispatch.IDispatch_iface;
+
+    SET_EXPECT(dispatch_invoke);
+    hres = VarCat(&left, &right, &result);
+    ok(hres == S_OK, "got 0x%08x\n", hres);
+    ok(V_VT(&result) == VT_BSTR, "got %d\n", V_VT(&result));
+    ok(SysStringLen(V_BSTR(&result)) == 0, "got %d\n", SysStringLen(V_BSTR(&result)));
+    CHECK_CALLED(dispatch_invoke);
+    ok(VarCmp(&result,&expected,lcid,0) == VARCMP_EQ, "VarCat: DISPATCH concat with EMPTY did not return empty VT_BSTR\n");
+
+    VariantClear(&left);
+    VariantClear(&right);
+    VariantClear(&result);
+    VariantClear(&expected);
+
+    init_test_dispatch(VT_UI1, &dispatch);
+    V_VT(&right) = VT_DISPATCH;
+    V_DISPATCH(&right) = &dispatch.IDispatch_iface;
+
+    V_VT(&expected) = VT_BSTR;
+    V_VT(&left) = VT_BSTR;
+    V_BSTR(&left) = SysAllocString(sz12);
+    V_BSTR(&expected) = SysAllocString(sz1234);
+    SET_EXPECT(dispatch_invoke);
+    hres = pVarCat(&left,&right,&result);
+    ok(hres == S_OK, "VarCat failed with error 0x%08x\n", hres);
+    CHECK_CALLED(dispatch_invoke);
+    ok(VarCmp(&result,&expected,lcid,0) == VARCMP_EQ, "VarCat: VT_DISPATCH concat with VT_BSTR failed to return correct result\n");
+
+    VariantClear(&left);
+    VariantClear(&right);
+    VariantClear(&result);
+    VariantClear(&expected);
+
+    init_test_dispatch(VT_NULL, &dispatch);
+    dispatch.result = E_OUTOFMEMORY;
+    V_VT(&right) = VT_DISPATCH;
+    V_DISPATCH(&right) = &dispatch.IDispatch_iface;
+
+    SET_EXPECT(dispatch_invoke);
+    hres = VarCat(&left, &right, &result);
+    ok(hres == S_OK, "got 0x%08x\n", hres);
+    CHECK_CALLED(dispatch_invoke);
+
+    VariantClear(&left);
+    VariantClear(&right);
+    VariantClear(&result);
+    VariantClear(&expected);
+
     /* Test boolean conversion */
     V_VT(&left) = VT_BOOL;
     V_BOOL(&left) = VARIANT_TRUE;
diff --git a/dlls/oleaut32/variant.c b/dlls/oleaut32/variant.c
index 17f753a..aa86be0 100644
--- a/dlls/oleaut32/variant.c
+++ b/dlls/oleaut32/variant.c
@@ -2605,30 +2605,16 @@ HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out)
                 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
             {
+                /* The value may not be able to be coerced, ie. VT_NULL */
                 hres = VariantChangeTypeEx(&bstrvar_left,left,0,0,VT_BSTR);
-                if (hres != S_OK) {
-                    VariantClear(&bstrvar_left);
-                    VariantClear(&bstrvar_right);
-                    if (leftvt == VT_NULL && (rightvt == VT_EMPTY ||
-                        rightvt == VT_NULL || rightvt ==  VT_I2 ||
-                        rightvt == VT_I4 || rightvt == VT_R4 ||
-                        rightvt == VT_R8 || rightvt == VT_CY ||
-                        rightvt == VT_DATE || rightvt == VT_BSTR ||
-                        rightvt == VT_BOOL ||  rightvt == VT_DECIMAL ||
-                        rightvt == VT_I1 || rightvt == VT_UI1 ||
-                        rightvt == VT_UI2 || rightvt == VT_UI4 ||
-                        rightvt == VT_I8 || rightvt == VT_UI8 ||
-                        rightvt == VT_INT || rightvt == VT_UINT))
-                        return DISP_E_BADVARTYPE;
+                if (hres != S_OK && hres != DISP_E_TYPEMISMATCH)
                     return hres;
+                else if(FAILED(hres))
+                {
+                    V_VT(&bstrvar_left) = VT_BSTR;
+                    V_BSTR(&bstrvar_left) = SysAllocString(sz_empty);
                 }
             }
         }
@@ -2645,30 +2631,16 @@ HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out)
                 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
             {
+                /* The value may not be able to be coerced, ie. VT_NULL */
                 hres = VariantChangeTypeEx(&bstrvar_right,right,0,0,VT_BSTR);
-                if (hres != S_OK) {
-                    VariantClear(&bstrvar_left);
-                    VariantClear(&bstrvar_right);
-                    if (rightvt == VT_NULL && (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))
-                        return DISP_E_BADVARTYPE;
+                if (hres != S_OK && hres != DISP_E_TYPEMISMATCH)
                     return hres;
+                else if(FAILED(hres))
+                {
+                    V_VT(&bstrvar_right) = VT_BSTR;
+                    V_BSTR(&bstrvar_right) = SysAllocString(sz_empty);
                 }
             }
         }
-- 
1.9.1




More information about the wine-patches mailing list