mshtml: Added support for overriding builtin functions.

This commit is contained in:
Jacek Caban 2012-09-24 14:10:05 +02:00 committed by Alexandre Julliard
parent 313157a036
commit 6d3bfe8ee5
1 changed files with 109 additions and 30 deletions

View File

@ -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;
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;
}
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;
}
hres = get_func_obj_entry(This, func, &entry);
if(FAILED(hres))
return hres;
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_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(dp->cArgs != 1 || (dp->cNamedArgs == 1 && *dp->rgdispidNamedArgs != DISPID_PROPERTYPUT)
|| dp->cNamedArgs > 1) {
FIXME("invalid args\n");
return E_INVALIDARG;
}
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);