[PATCH 04/14] mshtml: Handle VT_DISPATCH in variant_to_nsstr.

Gabriel Ivăncescu gabrielopcode at gmail.com
Tue Nov 16 08:29:23 CST 2021


Some javascript libraries such as prototype.js use this (by setting to an
array) to examine setAttribute quirks.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
 dlls/mshtml/nsembed.c             | 49 +++++++++++++++++++++--
 dlls/mshtml/tests/documentmode.js | 64 +++++++++++++++++++++++++++++++
 2 files changed, 109 insertions(+), 4 deletions(-)

diff --git a/dlls/mshtml/nsembed.c b/dlls/mshtml/nsembed.c
index 4224d6a..d8210f7 100644
--- a/dlls/mshtml/nsembed.c
+++ b/dlls/mshtml/nsembed.c
@@ -994,6 +994,8 @@ HRESULT return_nsstr_variant(nsresult nsres, nsAString *nsstr, unsigned flags, V
 HRESULT variant_to_nsstr(VARIANT *v, BOOL hex_int, nsAString *nsstr)
 {
     WCHAR buf[32];
+    VARIANT strv;
+    HRESULT hres;
 
     switch(V_VT(v)) {
     case VT_NULL:
@@ -1013,10 +1015,7 @@ HRESULT variant_to_nsstr(VARIANT *v, BOOL hex_int, nsAString *nsstr)
         nsAString_Init(nsstr, buf);
         break;
 
-    case VT_R8: {
-        VARIANT strv;
-        HRESULT hres;
-
+    case VT_R8:
         V_VT(&strv) = VT_EMPTY;
         hres = VariantChangeTypeEx(&strv, v, MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT),
                                    0, VT_BSTR);
@@ -1026,6 +1025,48 @@ HRESULT variant_to_nsstr(VARIANT *v, BOOL hex_int, nsAString *nsstr)
         nsAString_Init(nsstr, V_BSTR(&strv));
         SysFreeString(V_BSTR(&strv));
         break;
+
+    case VT_DISPATCH: {
+        LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
+        IDispatch *disp = V_DISPATCH(v);
+        DISPID dispid;
+        WCHAR *name;
+
+        if(!disp) {
+            nsAString_InitDepend(nsstr, NULL);
+            return S_OK;
+        }
+
+        /* try toString() first */
+        memcpy(buf, L"toString", sizeof(L"toString"));
+        name = buf;
+        hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, &dispid);
+        if(SUCCEEDED(hres) && dispid != DISPID_UNKNOWN) {
+            DISPPARAMS params = { &strv, NULL, 0, 0 };
+            hres = IDispatch_Invoke(disp, dispid, &IID_NULL, lcid, DISPATCH_METHOD, &params, &strv, NULL, NULL);
+            if(SUCCEEDED(hres)) {
+                if(V_VT(&strv) == VT_BSTR) {
+                    nsAString_Init(nsstr, V_BSTR(&strv));
+                    SysFreeString(V_BSTR(&strv));
+                    break;
+                }
+                VariantClear(&strv);
+            }
+        }
+
+        /* try value */
+        hres = IDispatch_Invoke(disp, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET, NULL, &strv, NULL, NULL);
+        if(SUCCEEDED(hres)) {
+            if(V_VT(&strv) == VT_BSTR) {
+                nsAString_Init(nsstr, V_BSTR(&strv));
+                SysFreeString(V_BSTR(&strv));
+                break;
+            }
+            VariantClear(&strv);
+        }
+
+        FIXME("don't know how to handle dispatch %s\n", debugstr_variant(v));
+        return E_NOTIMPL;
     }
 
     default:
diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js
index a2c3714..ce29f23 100644
--- a/dlls/mshtml/tests/documentmode.js
+++ b/dlls/mshtml/tests/documentmode.js
@@ -1088,6 +1088,41 @@ sync_test("elem_attr", function() {
     r = elem.getAttribute("className");
     ok(r === "cls3", "className attr = " + r);
 
+    var arr = [3];
+    elem.setAttribute("testattr", arr);
+    r = elem.getAttribute("testattr");
+    ok(r === (v < 8 ? arr : "3"), "testattr = " + r);
+    todo_wine_if(v === 8).
+    ok(elem.testattr === (v < 9 ? arr : undefined), "elem.testattr = " + elem.testattr);
+    r = elem.removeAttribute("testattr");
+    ok(r === (v < 9 ? true : undefined), "testattr removeAttribute returned " + r);
+    ok(elem.testattr === undefined, "removed testattr = " + elem.testattr);
+
+    arr[0] = 9;
+    elem.setAttribute("testattr", "string");
+    elem.testattr = arr;
+    r = elem.getAttribute("testattr");
+    todo_wine_if(v === 8).
+    ok(r === (v < 8 ? arr : (v < 9 ? "9" : "string")), "testattr = " + r);
+    ok(elem.testattr === arr, "elem.testattr = " + elem.testattr);
+    arr[0] = 3;
+    r = elem.getAttribute("testattr");
+    todo_wine_if(v === 8).
+    ok(r === (v < 8 ? arr : (v < 9 ? "3" : "string")), "testattr = " + r);
+    ok(elem.testattr === arr, "elem.testattr = " + elem.testattr);
+    r = elem.removeAttribute("testattr");
+    ok(r === (v < 9 ? true : undefined), "testattr removeAttribute returned " + r);
+    todo_wine_if(v === 8).
+    ok(elem.testattr === (v < 9 ? undefined : arr), "removed testattr = " + elem.testattr);
+
+    elem.setAttribute("id", arr);
+    r = elem.getAttribute("id");
+    todo_wine_if(v >= 8 && v < 10).
+    ok(r === (v < 8 || v >= 10 ? "3" : "[object]"), "id = " + r);
+    r = elem.removeAttribute("id");
+    ok(r === (v < 9 ? true : undefined), "id removeAttribute returned " + r);
+    ok(elem.id === "", "removed id = " + elem.id);
+
     var func = function() { };
     elem.onclick = func;
     ok(elem.onclick === func, "onclick = " + elem.onclick);
@@ -1110,6 +1145,13 @@ sync_test("elem_attr", function() {
     ok(r === "test", "onclick attr after setAttribute = " + r);
     r = elem.removeAttribute("onclick");
     ok(r === (v < 9 ? true : undefined), "removeAttribute after setAttribute returned " + r);
+    if(v < 11)  /* IE11 returns an empty function, which we can't check */
+        todo_wine_if(v >= 8).
+        ok(elem.onclick === null, "removed onclick after setAttribute = " + elem.onclick);
+    r = Object.prototype.toString.call(elem.onclick);
+    todo_wine_if(v >= 8 && v < 11).
+    ok(r === (v < 9 ? "[object Object]" : (v < 11 ? "[object Null]" : "[object Function]")),
+        "removed onclick after setAttribute Object.toString returned " + r);
 
     elem.setAttribute("onclick", "string");
     r = elem.getAttribute("onclick");
@@ -1127,6 +1169,28 @@ sync_test("elem_attr", function() {
     ok(r === (v < 9 ? true : undefined), "removeAttribute returned " + r);
     todo_wine_if(v >= 8).
     ok(elem.onclick === null, "removed onclick = " + elem.onclick);
+
+    elem.setAttribute("ondblclick", arr);
+    r = elem.getAttribute("ondblclick");
+    todo_wine_if(v >= 8 && v < 10).
+    ok(r === (v < 8 ? arr : (v < 10 ? "[object]" : "3")), "ondblclick = " + r);
+    r = elem.removeAttribute("ondblclick");
+    todo_wine_if(v < 8).
+    ok(r === (v < 8 ? false : (v < 9 ? true : undefined)), "ondblclick removeAttribute returned " + r);
+    if(v < 11)  /* IE11 returns an empty function, which we can't check */
+        todo_wine_if(v < 8).
+        ok(elem.ondblclick === (v < 8 ? arr : null), "removed ondblclick = " + elem.ondblclick);
+    r = Object.prototype.toString.call(elem.ondblclick);
+    todo_wine_if(v != 8).
+    ok(r === (v < 8 ? "[object Array]" : (v < 9 ? "[object Object]" : (v < 11 ? "[object Null]" : "[object Function]"))),
+        "removed ondblclick Object.toString returned " + r);
+
+    elem.setAttribute("ondblclick", "string");
+    r = elem.getAttribute("ondblclick");
+    ok(r === "string", "ondblclick string = " + r);
+    r = elem.removeAttribute("ondblclick");
+    ok(r === (v < 9 ? true : undefined), "ondblclick string removeAttribute returned " + r);
+    ok(elem.ondblclick === null, "removed ondblclick string = " + elem.ondblclick);
 });
 
 sync_test("__proto__", function() {
-- 
2.31.1




More information about the wine-devel mailing list