From: Gabriel Ivăncescu gabrielopcode@gmail.com
Props allocated with dispex_get_dprop_ref or dispex_get_dynid are purely internal to our implementation and must not be enumerated.
Note that in case of window, the props themselves become enumerable, but the dynamic props must still be hidden, since it's the custom prop that refers to it that must be enumerated (i.e. the DISPID must match with the custom prop, not the underlying dynamic prop backing it, which would violate the former DISPID obtained for the respective name).
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/dispex.c | 7 +++++- dlls/mshtml/htmlwindow.c | 16 +++++++++++- dlls/mshtml/tests/documentmode.js | 42 ++++++++++++++++++++++++++++++- 3 files changed, 62 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index d7b587f21d2..3d3d854936e 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -85,6 +85,7 @@ typedef struct { } dynamic_prop_t;
#define DYNPROP_DELETED 0x01 +#define DYNPROP_HIDDEN 0x02
typedef struct { DispatchEx dispex; @@ -702,6 +703,8 @@ HRESULT dispex_get_dprop_ref(DispatchEx *This, const WCHAR *name, BOOL alloc, VA if(FAILED(hres)) return hres;
+ if(alloc) + prop->flags |= DYNPROP_HIDDEN; *ret = &prop->var; return S_OK; } @@ -715,6 +718,7 @@ HRESULT dispex_get_dynid(DispatchEx *This, const WCHAR *name, DISPID *id) if(FAILED(hres)) return hres;
+ prop->flags |= DYNPROP_HIDDEN; *id = DISPID_DYNPROP_0 + (prop - This->dynamic_data->props); return S_OK; } @@ -1860,7 +1864,8 @@ static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BS
static HRESULT next_dynamic_id(DispatchEx *dispex, DWORD idx, DISPID *ret_id) { - while(idx < dispex->dynamic_data->prop_cnt && dispex->dynamic_data->props[idx].flags & DYNPROP_DELETED) + while(idx < dispex->dynamic_data->prop_cnt && + (dispex->dynamic_data->props[idx].flags & (DYNPROP_DELETED | DYNPROP_HIDDEN))) idx++;
if(idx == dispex->dynamic_data->prop_cnt) { diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 02d6d374255..12f8a304d41 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3874,6 +3874,20 @@ static HRESULT HTMLWindow_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD return hres; }
+static HRESULT HTMLWindow_next_dispid(DispatchEx *dispex, DISPID id, DISPID *pid) +{ + DWORD idx = (id == DISPID_STARTENUM) ? 0 : id - MSHTML_DISPID_CUSTOM_MIN + 1; + HTMLInnerWindow *This = impl_from_DispatchEx(dispex); + + while(idx < This->global_prop_cnt && This->global_props[idx].type != GLOBAL_DISPEXVAR) + idx++; + if(idx >= This->global_prop_cnt) + return S_FALSE; + + *pid = idx + MSHTML_DISPID_CUSTOM_MIN; + return S_OK; +} + static compat_mode_t HTMLWindow_get_compat_mode(DispatchEx *dispex) { HTMLInnerWindow *This = impl_from_DispatchEx(dispex); @@ -3971,7 +3985,7 @@ static const event_target_vtbl_t HTMLWindow_event_target_vtbl = { HTMLWindow_get_name, HTMLWindow_invoke, NULL, - NULL, + HTMLWindow_next_dispid, HTMLWindow_get_compat_mode, NULL }, diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index cb6d2d01ec2..a3a0e2439cd 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -635,6 +635,8 @@ sync_test("JS objs", function() { });
sync_test("for..in", function() { + var v = document.documentMode, found = 0, r; + function ctor() {} ctor.prototype.test2 = true;
@@ -642,7 +644,7 @@ sync_test("for..in", function() { obj.test1 = true;
i = 0; - for(var r in obj) { + for(r in obj) { ctor.prototype.test3 = true; arr[r] = true; i++; @@ -652,10 +654,22 @@ sync_test("for..in", function() { ok(arr["test1"] === true, "arr[test1] !== true"); ok(arr["test2"] === true, "arr[test2] !== true"); ok(arr["test3"] === true, "arr[test3] !== true"); + + for(r in document) + if(r === "ondragstart") + found++; + ok(found === 1, "ondragstart enumerated " + found + " times in document"); + document.ondragstart = ""; + found = 0; + for(r in document) + if(r === "ondragstart") + found++; + ok(found === 1, "ondragstart enumerated " + found + " times in document after set to empty string"); });
sync_test("elem_by_id", function() { document.body.innerHTML = '<form id="testid" name="testname"></form>'; + var found;
var id_elem = document.getElementById("testid"); ok(id_elem.tagName === "FORM", "id_elem.tagName = " + id_elem.tagName); @@ -665,6 +679,32 @@ sync_test("elem_by_id", function() { ok(id_elem === name_elem, "id_elem != id_elem"); else ok(name_elem === null, "name_elem != null"); + + id_elem = window.testid; + ok(id_elem.tagName === "FORM", "window.testid = " + id_elem); + + name_elem = document.testname; + ok(name_elem.tagName === "FORM", "document.testname = " + name_elem); + + for(id_elem in window) + ok(id_elem !== "testid" && id_elem != "testname", id_elem + " was enumerated in window"); + window.testid = 137; + found = false; + for(id_elem in window) { + ok(id_elem != "testname", id_elem + " was enumerated in window after set to 137"); + if(id_elem === "testid") + found = true; + } + ok(found, "testid was not enumerated in window after set to 137"); + + found = false; + for(id_elem in document) { + ok(id_elem !== "testid", "testid was enumerated in document"); + if(id_elem === "testname") + found = true; + } + todo_wine. + ok(found, "testname was not enumerated in document"); });
sync_test("doc_mode", function() {