For document modes <= IE8, native allows to retrieve the semi-implemented builtin methods, and then use them to retrieve their value props (and string) or the other props (which always return undefined), but it doesn't allow calling them or otherwise doing anything else with them anymore (e.g. chaining them like f.call.call). This implements it the same way with the same limitations.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
Tests follow.
dlls/mshtml/dispex.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 01c5656..2f3ca0b 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -91,7 +91,10 @@ typedef struct { DispatchEx dispex; IUnknown IUnknown_iface; LONG ref; - DispatchEx *obj; + union { + DispatchEx *obj; + DWORD idx; /* index into function_props, used when info == NULL */ + }; func_info_t *info; } func_disp_t;
@@ -126,6 +129,8 @@ PRIVATE_TID_LIST #undef XDIID };
+static func_disp_t *create_func_disp(DispatchEx*,func_info_t*); + static HRESULT load_typelib(void) { WCHAR module_path[MAX_PATH + 3]; @@ -816,7 +821,7 @@ static ULONG WINAPI Function_Release(IUnknown *iface) TRACE("(%p) ref=%d\n", This, ref);
if(!ref) { - assert(!This->obj); + assert(!This->info || !This->obj); release_dispex(&This->dispex); heap_free(This); } @@ -954,6 +959,8 @@ static HRESULT function_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPAR return E_INVALIDARG; /* fall through */ case DISPATCH_METHOD: + if(!This->info) + return JS_E_INVALID_PROPERTY; if(!This->obj) return E_UNEXPECTED; hres = typeinfo_invoke(This->obj, This->info, flags, params, res, ei); @@ -972,7 +979,7 @@ static HRESULT function_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPAR if(!caller) return E_ACCESSDENIED;
- name_len = SysStringLen(This->info->name); + name_len = This->info ? SysStringLen(This->info->name) : wcslen(function_props[This->idx].name); ptr = str = SysAllocStringLen(NULL, name_len + ARRAY_SIZE(func_prefixW) + ARRAY_SIZE(func_suffixW)); if(!str) return E_OUTOFMEMORY; @@ -980,7 +987,7 @@ static HRESULT function_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPAR memcpy(ptr, func_prefixW, sizeof(func_prefixW)); ptr += ARRAY_SIZE(func_prefixW);
- memcpy(ptr, This->info->name, name_len*sizeof(WCHAR)); + memcpy(ptr, This->info ? This->info->name : function_props[This->idx].name, name_len*sizeof(WCHAR)); ptr += name_len;
memcpy(ptr, func_suffixW, sizeof(func_suffixW)); @@ -999,12 +1006,18 @@ static HRESULT function_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPAR
static HRESULT function_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid) { + func_disp_t *This = impl_from_DispatchEx(dispex); DWORD i;
for(i = 0; i < ARRAY_SIZE(function_props); i++) { if(!wcsicmp(name, function_props[i].name)) { if((flags & fdexNameCaseSensitive) && wcscmp(name, function_props[i].name)) return DISP_E_UNKNOWNNAME; + + /* methods (apply, call) can't be chained */ + if(!This->info && function_props[i].method) + return DISP_E_UNKNOWNNAME; + *dispid = MSHTML_DISPID_CUSTOM_MIN + i; return S_OK; } @@ -1021,6 +1034,10 @@ static HRESULT function_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD fl if(idx >= ARRAY_SIZE(function_props)) return DISP_E_UNKNOWNNAME;
+ /* methods (apply, call) can't be chained */ + if(!This->info && function_props[idx].method) + return DISP_E_UNKNOWNNAME; + switch(flags) { case DISPATCH_METHOD|DISPATCH_PROPERTYGET: if(!res) @@ -1031,6 +1048,16 @@ static HRESULT function_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD fl return function_props[idx].method(This, params, res, ei); return JS_E_INVALID_PROPERTY; case DISPATCH_PROPERTYGET: + if(function_props[idx].method) { + func_disp_t *disp = create_func_disp(dispex, NULL); + if(!disp) + return E_OUTOFMEMORY; + disp->idx = idx; + + V_VT(res) = VT_DISPATCH; + V_DISPATCH(res) = (IDispatch*)&disp->dispex.IDispatchEx_iface; + break; + } V_VT(res) = VT_EMPTY; /* IE returns undefined */ break; default: