Jacek Caban : mshtml: Added support for overriding builtin functions.
Alexandre Julliard
julliard at winehq.org
Mon Sep 24 16:04:27 CDT 2012
Module: wine
Branch: master
Commit: 6d3bfe8ee5a0bcfd8170b214e0fa422a5350195c
URL: http://source.winehq.org/git/wine.git/?a=commit;h=6d3bfe8ee5a0bcfd8170b214e0fa422a5350195c
Author: Jacek Caban <jacek at 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);
More information about the wine-cvs
mailing list