Module: wine Branch: master Commit: 6d3bfe8ee5a0bcfd8170b214e0fa422a5350195c URL: http://source.winehq.org/git/wine.git/?a=commit;h=6d3bfe8ee5a0bcfd8170b214e0...
Author: Jacek Caban jacek@codeweavers.com Date: Mon Sep 24 14:10:05 2012 +0200
mshtml: Added support for overriding builtin functions.
---
dlls/mshtml/dispex.c | 135 +++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 107 insertions(+), 28 deletions(-)
diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index eca45a6..cc22ce4 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -74,15 +74,21 @@ typedef struct { typedef struct { DispatchEx dispex; IUnknown IUnknown_iface; + LONG ref; DispatchEx *obj; func_info_t *info; } func_disp_t;
+typedef struct { + func_disp_t *func_obj; + IDispatch *val; +} func_obj_entry_t; + struct dispex_dynamic_data_t { DWORD buf_size; DWORD prop_cnt; dynamic_prop_t *props; - func_disp_t **func_disps; + func_obj_entry_t *func_disps; };
#define DISPID_DYNPROP_0 0x50000000 @@ -575,19 +581,27 @@ static HRESULT WINAPI Function_QueryInterface(IUnknown *iface, REFIID riid, void static ULONG WINAPI Function_AddRef(IUnknown *iface) { func_disp_t *This = impl_from_IUnknown(iface); + LONG ref = InterlockedIncrement(&This->ref);
- TRACE("(%p)\n", This); + TRACE("(%p) ref=%d\n", This, ref);
- return IDispatchEx_AddRef(&This->obj->IDispatchEx_iface); + return ref; }
static ULONG WINAPI Function_Release(IUnknown *iface) { func_disp_t *This = impl_from_IUnknown(iface); + LONG ref = InterlockedDecrement(&This->ref);
- TRACE("(%p)\n", This); + TRACE("(%p) ref=%d\n", This, ref);
- return IDispatchEx_Release(&This->obj->IDispatchEx_iface); + if(!ref) { + assert(!This->obj); + release_dispex(&This->dispex); + heap_free(This); + } + + return ref; }
static const IUnknownVtbl FunctionUnkVtbl = { @@ -613,6 +627,8 @@ static HRESULT function_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPAR return E_INVALIDARG; /* fall through */ case DISPATCH_METHOD: + if(!This->obj) + return E_UNEXPECTED; hres = typeinfo_invoke(This->obj, This->info, flags, params, res, ei); break; default: @@ -649,6 +665,7 @@ static func_disp_t *create_func_disp(DispatchEx *obj, func_info_t *info)
ret->IUnknown_iface.lpVtbl = &FunctionUnkVtbl; init_dispex(&ret->dispex, &ret->IUnknown_iface, &function_dispex); + ret->ref = 1; ret->obj = obj; ret->info = info;
@@ -696,6 +713,37 @@ static HRESULT invoke_disp_value(DispatchEx *This, IDispatch *func_disp, LCID lc return hres; }
+static HRESULT get_func_obj_entry(DispatchEx *This, func_info_t *func, func_obj_entry_t **ret) +{ + dispex_dynamic_data_t *dynamic_data; + + dynamic_data = get_dynamic_data(This); + if(!dynamic_data) + return E_OUTOFMEMORY; + + if(!dynamic_data->func_disps) { + dynamic_data->func_disps = heap_alloc_zero(This->data->data->func_disp_cnt * sizeof(*dynamic_data->func_disps)); + if(!dynamic_data->func_disps) + return E_OUTOFMEMORY; + } + + if(!dynamic_data->func_disps[func->func_disp_idx].func_obj) { + func_disp_t *func_obj; + + func_obj = create_func_disp(This, func); + if(!func_obj) + return E_OUTOFMEMORY; + + dynamic_data->func_disps[func->func_disp_idx].func_obj = func_obj; + + IDispatchEx_AddRef(&func_obj->dispex.IDispatchEx_iface); + dynamic_data->func_disps[func->func_disp_idx].val = (IDispatch*)&func_obj->dispex.IDispatchEx_iface; + } + + *ret = dynamic_data->func_disps+func->func_disp_idx; + return S_OK; +} + static HRESULT function_invoke(DispatchEx *This, func_info_t *func, WORD flags, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei) { @@ -707,10 +755,25 @@ static HRESULT function_invoke(DispatchEx *This, func_info_t *func, WORD flags, return E_INVALIDARG; /* fall through */ case DISPATCH_METHOD: + if(This->dynamic_data && This->dynamic_data && This->dynamic_data->func_disps + && This->dynamic_data->func_disps[func->func_disp_idx].func_obj) { + func_obj_entry_t *entry = This->dynamic_data->func_disps + func->func_disp_idx; + + if((IDispatch*)&entry->func_obj->dispex.IDispatchEx_iface != entry->val) { + if(!entry->val) { + FIXME("Calling null\n"); + return E_FAIL; + } + + hres = invoke_disp_value(This, entry->val, 0, flags, dp, res, ei, NULL); + break; + } + } + hres = typeinfo_invoke(This, func, flags, dp, res, ei); break; case DISPATCH_PROPERTYGET: { - dispex_dynamic_data_t *dynamic_data; + func_obj_entry_t *entry;
if(func->id == DISPID_VALUE) { BSTR ret; @@ -724,32 +787,46 @@ static HRESULT function_invoke(DispatchEx *This, func_info_t *func, WORD flags, return S_OK; }
- dynamic_data = get_dynamic_data(This); - if(!dynamic_data) - return E_OUTOFMEMORY; + hres = get_func_obj_entry(This, func, &entry); + if(FAILED(hres)) + return hres;
- if(!dynamic_data->func_disps) { - dynamic_data->func_disps = heap_alloc_zero(This->data->data->func_disp_cnt * sizeof(func_disp_t*)); - if(!dynamic_data->func_disps) - return E_OUTOFMEMORY; - } + V_VT(res) = VT_DISPATCH; + V_DISPATCH(res) = entry->val; + if(V_DISPATCH(res)) + IDispatch_AddRef(V_DISPATCH(res)); + hres = S_OK; + break; + } + case DISPATCH_PROPERTYPUT: { + func_obj_entry_t *entry; + VARIANT *v;
- if(!dynamic_data->func_disps[func->func_disp_idx]) { - dynamic_data->func_disps[func->func_disp_idx] = create_func_disp(This, func); - if(!dynamic_data->func_disps[func->func_disp_idx]) - return E_OUTOFMEMORY; + if(dp->cArgs != 1 || (dp->cNamedArgs == 1 && *dp->rgdispidNamedArgs != DISPID_PROPERTYPUT) + || dp->cNamedArgs > 1) { + FIXME("invalid args\n"); + return E_INVALIDARG; }
- V_VT(res) = VT_DISPATCH; - V_DISPATCH(res) = (IDispatch*)&dynamic_data->func_disps[func->func_disp_idx]->dispex.IDispatchEx_iface; - IDispatch_AddRef(V_DISPATCH(res)); + v = dp->rgvarg; + /* FIXME: not exactly right */ + if(V_VT(v) != VT_DISPATCH) + return E_NOTIMPL; + + hres = get_func_obj_entry(This, func, &entry); + if(FAILED(hres)) + return hres; + + if(entry->val) + IDispatch_Release(entry->val); + entry->val = V_DISPATCH(v); + if(entry->val) + IDispatch_AddRef(entry->val); hres = S_OK; break; } default: FIXME("Unimplemented flags %x\n", flags); - /* fall through */ - case DISPATCH_PROPERTYPUT: hres = E_NOTIMPL; }
@@ -1445,13 +1522,15 @@ void release_dispex(DispatchEx *This) heap_free(This->dynamic_data->props);
if(This->dynamic_data->func_disps) { - unsigned i; + func_obj_entry_t *iter;
- for(i=0; i < This->data->data->func_disp_cnt; i++) { - if(This->dynamic_data->func_disps[i]) { - release_dispex(&This->dynamic_data->func_disps[i]->dispex); - heap_free(This->dynamic_data->func_disps[i]); + for(iter = This->dynamic_data->func_disps; iter < This->dynamic_data->func_disps+This->data->data->func_disp_cnt; iter++) { + if(iter->func_obj) { + iter->func_obj->obj = NULL; + IDispatchEx_Release(&iter->func_obj->dispex.IDispatchEx_iface); } + if(iter->val) + IDispatch_Release(iter->val); }
heap_free(This->dynamic_data->func_disps);