mshtml: Added support for overriding builtin functions.
This commit is contained in:
parent
313157a036
commit
6d3bfe8ee5
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue