From 5fea362a1f87427b8f7a0fa47481eb52aae35363 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Tue, 9 Jul 2024 23:36:25 +0200 Subject: [PATCH] jscript: Add support for host functions. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Based on patch by Gabriel Ivăncescu. --- dlls/jscript/dispex.c | 36 ++++++++++++-- dlls/jscript/function.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++ dlls/jscript/jscript.h | 1 + dlls/jscript/jsdisp.idl | 1 + dlls/mshtml/dispex.c | 7 ++- 5 files changed, 160 insertions(+), 6 deletions(-) diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 26d89ab2b5e..dbdc64659a8 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -268,6 +268,28 @@ static dispex_prop_t *lookup_dispex_prop(jsdisp_t *obj, unsigned hash, const WCH return NULL; } +static HRESULT update_external_prop(jsdisp_t *obj, dispex_prop_t *prop, const struct property_info *desc) +{ + if(desc->func_iid) { + jsdisp_t *func; + HRESULT hres; + + hres = create_host_function(obj->ctx, desc, &func); + if(FAILED(hres)) + return hres; + + prop->type = PROP_JSVAL; + prop->flags = desc->flags; + prop->u.val = jsval_obj(func); + return S_OK; + } + + prop->type = PROP_EXTERN; + prop->flags = desc->flags; + prop->u.id = desc->id; + return S_OK; +} + static HRESULT find_external_prop(jsdisp_t *This, const WCHAR *name, BOOL case_insens, dispex_prop_t **ret) { dispex_prop_t *prop; @@ -282,13 +304,13 @@ static HRESULT find_external_prop(jsdisp_t *This, const WCHAR *name, BOOL case_i if(FAILED(hres)) return hres; - prop = alloc_prop(This, desc.name ? desc.name : name, PROP_EXTERN, desc.flags); + prop = alloc_prop(This, desc.name ? desc.name : name, PROP_DELETED, 0); if(!prop) return E_OUTOFMEMORY; - prop->u.id = desc.id; + hres = update_external_prop(This, prop, &desc); *ret = prop; - return S_OK; + return hres; } } @@ -427,6 +449,7 @@ HRESULT jsdisp_index_lookup(jsdisp_t *obj, const WCHAR *name, unsigned length, s desc->flags |= PROPF_WRITABLE; desc->name = NULL; desc->index = idx; + desc->func_iid = 0; return S_OK; } @@ -440,6 +463,7 @@ HRESULT jsdisp_next_index(jsdisp_t *obj, unsigned length, unsigned id, struct pr desc->flags |= PROPF_WRITABLE; desc->name = NULL; desc->index = desc->id; + desc->func_iid = 0; return S_OK; } @@ -685,10 +709,12 @@ static HRESULT fill_props(jsdisp_t *obj) prop = lookup_dispex_prop(obj, string_hash(desc.name), desc.name, FALSE); if(!prop) { - prop = alloc_prop(obj, desc.name, PROP_EXTERN, desc.flags); + prop = alloc_prop(obj, desc.name, PROP_DELETED, 0); if(!prop) return E_OUTOFMEMORY; - prop->u.id = desc.id; + hres = update_external_prop(obj, prop, &desc); + if(FAILED(hres)) + return hres; } id = desc.id; } diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 23b1308cbc0..40ff015121b 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -64,6 +64,13 @@ typedef struct { } BindFunction; typedef struct { + FunctionInstance function; + const WCHAR *name; + UINT32 id; + UINT32 iid; +} HostFunction; + +typedef struct { jsdisp_t jsdisp; jsval_t *buf; scope_chain_t *scope; @@ -918,6 +925,120 @@ HRESULT create_source_function(script_ctx_t *ctx, bytecode_t *code, function_cod return S_OK; } +static const builtin_info_t HostFunction_info = { + .class = JSCLASS_FUNCTION, + .call = Function_value, + .destructor = Function_destructor, + .gc_traverse = Function_gc_traverse +}; + +static HRESULT HostFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags, + unsigned argc, jsval_t *argv, jsval_t *r) +{ + HostFunction *function = (HostFunction*)func; + VARIANT buf[6], retv; + DISPPARAMS dp = { .cArgs = argc, .rgvarg = buf }; + IWineJSDispatchHost *obj; + EXCEPINFO ei = { 0 }; + IDispatch *this_obj; + HRESULT hres = S_OK; + unsigned i; + + if(flags & DISPATCH_CONSTRUCT) + return E_UNEXPECTED; + + if(is_object_instance(vthis)) + this_obj = get_object(vthis); + else if(is_undefined(vthis) || is_null(vthis)) + this_obj = lookup_global_host(ctx); + else + return E_UNEXPECTED; + + obj = get_host_dispatch(this_obj); + if(!obj) { + TRACE("no host dispatch\n"); + return E_UNEXPECTED; + } + + if(argc > ARRAYSIZE(buf) && !(dp.rgvarg = malloc(argc * sizeof(*dp.rgvarg)))) { + IWineJSDispatchHost_Release(obj); + return E_OUTOFMEMORY; + } + + for(i = 0; i < argc; i++) { + hres = jsval_to_variant(argv[i], &dp.rgvarg[dp.cArgs - i - 1]); + if(FAILED(hres)) + break; + } + + if(SUCCEEDED(hres)) { + V_VT(&retv) = VT_EMPTY; + hres = IWineJSDispatchHost_CallFunction(obj, function->id, function->iid, &dp, r ? &retv : NULL, &ei, + &ctx->jscaller->IServiceProvider_iface); + if(hres == DISP_E_EXCEPTION) + handle_dispatch_exception(ctx, &ei); + if(SUCCEEDED(hres) && r) { + hres = variant_to_jsval(ctx, &retv, r); + VariantClear(&retv); + } + } + + while(i--) + VariantClear(&dp.rgvarg[dp.cArgs - i - 1]); + if(dp.rgvarg != buf) + free(dp.rgvarg); + IWineJSDispatchHost_Release(obj); + return hres; +} + +static HRESULT HostFunction_toString(FunctionInstance *func, jsstr_t **ret) +{ + HostFunction *function = (HostFunction*)func; + return native_function_string(function->name, ret); +} + +static function_code_t *HostFunction_get_code(FunctionInstance *function) +{ + return NULL; +} + +static void HostFunction_destructor(FunctionInstance *func) +{ +} + +static HRESULT HostFunction_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, FunctionInstance *func) +{ + return S_OK; +} + +static const function_vtbl_t HostFunctionVtbl = { + HostFunction_call, + HostFunction_toString, + HostFunction_get_code, + HostFunction_destructor, + HostFunction_gc_traverse +}; + +HRESULT create_host_function(script_ctx_t *ctx, const struct property_info *desc, jsdisp_t **ret) +{ + HostFunction *function; + HRESULT hres; + + if(!ctx->function_constr) + return E_UNEXPECTED; + + hres = create_function(ctx, &HostFunction_info, &HostFunctionVtbl, sizeof(HostFunction), PROPF_METHOD, + FALSE, NULL, (void**)&function); + if(FAILED(hres)) + return hres; + + function->name = desc->name; + function->id = desc->id; + function->iid = desc->func_iid; + *ret = &function->function.dispex; + return S_OK; +} + static HRESULT BindFunction_get_arguments(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) { return JS_E_INVALID_ACTION; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index fdcead4a064..1cb423cff31 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -276,6 +276,7 @@ HRESULT create_builtin_function(script_ctx_t*,builtin_invoke_t,const WCHAR*,cons jsdisp_t*,jsdisp_t**); HRESULT create_builtin_constructor(script_ctx_t*,builtin_invoke_t,const WCHAR*,const builtin_info_t*,DWORD, jsdisp_t*,jsdisp_t**); +HRESULT create_host_function(script_ctx_t*,const struct property_info*,jsdisp_t**); HRESULT Function_invoke(jsdisp_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*); HRESULT Function_value(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*); diff --git a/dlls/jscript/jsdisp.idl b/dlls/jscript/jsdisp.idl index 533677f6cad..8ea53396f09 100644 --- a/dlls/jscript/jsdisp.idl +++ b/dlls/jscript/jsdisp.idl @@ -27,6 +27,7 @@ struct property_info UINT32 flags; const WCHAR *name; UINT32 index; + UINT32 func_iid; }; const unsigned int PROPF_ENUMERABLE = 0x0400; diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 61e7dae650e..7b334ac3001 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -2310,8 +2310,12 @@ static HRESULT WINAPI JSDispatchHost_LookupProperty(IWineJSDispatchHost *iface, return hres; desc->id = id; desc->flags = PROPF_WRITABLE | PROPF_CONFIGURABLE; - if(func->func_disp_idx < 0) + if(func->func_disp_idx < 0) { desc->flags |= PROPF_ENUMERABLE; + desc->func_iid = 0; + }else { + desc->func_iid = func->tid; + } desc->name = func->name; return S_OK; } @@ -2338,6 +2342,7 @@ static HRESULT WINAPI JSDispatchHost_NextProperty(IWineJSDispatchHost *iface, DI desc->id = func->id; desc->name = func->name; desc->flags = PROPF_WRITABLE | PROPF_CONFIGURABLE | PROPF_ENUMERABLE; + desc->func_iid = 0; return S_OK; } func++; -- 2.11.4.GIT