Commit 61734cd9 authored by Jacek Caban's avatar Jacek Caban Committed by Alexandre Julliard

jscript: Added InvokeEx implementation.

parent 8c0e089d
...@@ -23,6 +23,13 @@ ...@@ -23,6 +23,13 @@
WINE_DEFAULT_DEBUG_CHANNEL(jscript); WINE_DEFAULT_DEBUG_CHANNEL(jscript);
/*
* This IID is used to get DispatchEx objecto from interface.
* We might consider using private insteface instead.
*/
static const IID IID_IDispatchJS =
{0x719c3050,0xf9d3,0x11cf,{0xa4,0x93,0x00,0x40,0x05,0x23,0xa8,0xa6}};
typedef enum { typedef enum {
PROP_VARIANT, PROP_VARIANT,
PROP_BUILTIN, PROP_BUILTIN,
...@@ -47,6 +54,14 @@ static inline DISPID prop_to_id(DispatchEx *This, dispex_prop_t *prop) ...@@ -47,6 +54,14 @@ static inline DISPID prop_to_id(DispatchEx *This, dispex_prop_t *prop)
return prop - This->props; return prop - This->props;
} }
static inline dispex_prop_t *get_prop(DispatchEx *This, DISPID id)
{
if(id < 0 || id >= This->prop_cnt || This->props[id].type == PROP_DELETED)
return NULL;
return This->props+id;
}
static const builtin_prop_t *find_builtin_prop(DispatchEx *This, const WCHAR *name) static const builtin_prop_t *find_builtin_prop(DispatchEx *This, const WCHAR *name)
{ {
int min = 0, max, i, r; int min = 0, max, i, r;
...@@ -167,6 +182,171 @@ static HRESULT find_prop_name_prot(DispatchEx *This, const WCHAR *name, BOOL all ...@@ -167,6 +182,171 @@ static HRESULT find_prop_name_prot(DispatchEx *This, const WCHAR *name, BOOL all
return S_OK; return S_OK;
} }
static HRESULT set_this(DISPPARAMS *dp, DISPPARAMS *olddp, IDispatch *jsthis)
{
VARIANTARG *oldargs;
int i;
static DISPID this_id = DISPID_THIS;
*dp = *olddp;
for(i = 0; i < dp->cNamedArgs; i++) {
if(dp->rgdispidNamedArgs[i] == DISPID_THIS)
return S_OK;
}
oldargs = dp->rgvarg;
dp->rgvarg = heap_alloc((dp->cArgs+1) * sizeof(VARIANTARG));
if(!dp->rgvarg)
return E_OUTOFMEMORY;
memcpy(dp->rgvarg+1, oldargs, dp->cArgs*sizeof(VARIANTARG));
V_VT(dp->rgvarg) = VT_DISPATCH;
V_DISPATCH(dp->rgvarg) = jsthis;
dp->cArgs++;
if(dp->cNamedArgs) {
DISPID *old = dp->rgdispidNamedArgs;
dp->rgdispidNamedArgs = heap_alloc((dp->cNamedArgs+1)*sizeof(DISPID));
if(!dp->rgdispidNamedArgs) {
heap_free(dp->rgvarg);
return E_OUTOFMEMORY;
}
memcpy(dp->rgdispidNamedArgs+1, old, dp->cNamedArgs*sizeof(DISPID));
dp->rgdispidNamedArgs[0] = DISPID_THIS;
dp->cNamedArgs++;
}else {
dp->rgdispidNamedArgs = &this_id;
dp->cNamedArgs = 1;
}
return S_OK;
}
static HRESULT invoke_prop_func(DispatchEx *This, DispatchEx *jsthis, dispex_prop_t *prop, LCID lcid, WORD flags,
DISPPARAMS *dp, VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
{
HRESULT hres;
switch(prop->type) {
case PROP_BUILTIN:
if(flags == DISPATCH_CONSTRUCT && (prop->flags & DISPATCH_METHOD)) {
WARN("%s is not a constructor\n", debugstr_w(prop->name));
return E_INVALIDARG;
}
return prop->u.p->invoke(jsthis, lcid, flags, dp, retv, ei, caller);
case PROP_PROTREF:
return invoke_prop_func(This->prototype, jsthis, This->prototype->props+prop->u.ref, lcid, flags, dp, retv, ei, caller);
case PROP_VARIANT: {
DISPPARAMS new_dp;
if(V_VT(&prop->u.var) != VT_DISPATCH) {
FIXME("invoke vt %d\n", V_VT(&prop->u.var));
return E_FAIL;
}
TRACE("call %s %p\n", debugstr_w(prop->name), V_DISPATCH(&prop->u.var));
hres = set_this(&new_dp, dp, (IDispatch*)_IDispatchEx_(jsthis));
if(FAILED(hres))
return hres;
hres = disp_call(V_DISPATCH(&prop->u.var), DISPID_VALUE, lcid, flags, &new_dp, retv, ei, caller);
if(new_dp.rgvarg != dp->rgvarg) {
heap_free(new_dp.rgvarg);
if(new_dp.cNamedArgs > 1)
heap_free(new_dp.rgdispidNamedArgs);
}
return hres;
}
default:
ERR("type %d\n", prop->type);
}
return E_FAIL;
}
static HRESULT prop_get(DispatchEx *This, dispex_prop_t *prop, LCID lcid, DISPPARAMS *dp,
VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
{
HRESULT hres;
switch(prop->type) {
case PROP_BUILTIN:
if(prop->u.p->flags & PROPF_METHOD) {
FIXME("function objects not supported\n");
return E_NOTIMPL;
}else {
hres = prop->u.p->invoke(This, lcid, DISPATCH_PROPERTYGET, dp, retv, ei, caller);
}
break;
case PROP_PROTREF:
hres = prop_get(This->prototype, This->prototype->props+prop->u.ref, lcid, dp, retv, ei, caller);
break;
case PROP_VARIANT:
hres = VariantCopy(retv, &prop->u.var);
break;
default:
ERR("type %d\n", prop->type);
return E_FAIL;
}
if(FAILED(hres)) {
TRACE("fail %08x\n", hres);
return hres;
}
TRACE("%s ret %s\n", debugstr_w(prop->name), debugstr_variant(retv));
return hres;
}
static HRESULT prop_put(DispatchEx *This, dispex_prop_t *prop, LCID lcid, DISPPARAMS *dp,
jsexcept_t *ei, IServiceProvider *caller)
{
DWORD i;
HRESULT hres;
switch(prop->type) {
case PROP_BUILTIN:
if(!(prop->flags & PROPF_METHOD))
return prop->u.p->invoke(This, lcid, DISPATCH_PROPERTYPUT, dp, NULL, ei, caller);
case PROP_PROTREF:
prop->type = PROP_VARIANT;
prop->flags = PROPF_ENUM;
V_VT(&prop->u.var) = VT_EMPTY;
break;
case PROP_VARIANT:
VariantClear(&prop->u.var);
break;
default:
ERR("type %d\n", prop->type);
return E_FAIL;
}
for(i=0; i < dp->cNamedArgs; i++) {
if(dp->rgdispidNamedArgs[i] == DISPID_PROPERTYPUT)
break;
}
if(i == dp->cNamedArgs) {
TRACE("no value to set\n");
return DISP_E_PARAMNOTOPTIONAL;
}
hres = VariantCopy(&prop->u.var, dp->rgvarg+i);
if(FAILED(hres))
return hres;
if(This->builtin_info->on_put)
This->builtin_info->on_put(This, prop->name);
TRACE("%s = %s\n", debugstr_w(prop->name), debugstr_variant(dp->rgvarg+i));
return S_OK;
}
#define DISPATCHEX_THIS(iface) DEFINE_THIS(DispatchEx, IDispatchEx, iface) #define DISPATCHEX_THIS(iface) DEFINE_THIS(DispatchEx, IDispatchEx, iface)
static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
...@@ -182,6 +362,11 @@ static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, ...@@ -182,6 +362,11 @@ static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid,
}else if(IsEqualGUID(&IID_IDispatchEx, riid)) { }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv); TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
*ppv = _IDispatchEx_(This); *ppv = _IDispatchEx_(This);
}else if(IsEqualGUID(&IID_IDispatchJS, riid)) {
TRACE("(%p)->(IID_IDispatchJS %p)\n", This, ppv);
IUnknown_AddRef(_IDispatchEx_(This));
*ppv = This;
return S_OK;
}else { }else {
WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
*ppv = NULL; *ppv = NULL;
...@@ -309,8 +494,43 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc ...@@ -309,8 +494,43 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc
VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
{ {
DispatchEx *This = DISPATCHEX_THIS(iface); DispatchEx *This = DISPATCHEX_THIS(iface);
FIXME("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); dispex_prop_t *prop;
return E_NOTIMPL; jsexcept_t jsexcept;
HRESULT hres;
TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
if(pvarRes)
V_VT(pvarRes) = VT_EMPTY;
prop = get_prop(This, id);
if(!prop || prop->type == PROP_DELETED) {
TRACE("invalid id\n");
return DISP_E_MEMBERNOTFOUND;
}
memset(&jsexcept, 0, sizeof(jsexcept));
switch(wFlags) {
case DISPATCH_METHOD:
case DISPATCH_CONSTRUCT:
hres = invoke_prop_func(This, This, prop, lcid, wFlags, pdp, pvarRes, &jsexcept, pspCaller);
break;
case DISPATCH_PROPERTYGET:
hres = prop_get(This, prop, lcid, pdp, pvarRes, &jsexcept, pspCaller);
break;
case DISPATCH_PROPERTYPUT:
hres = prop_put(This, prop, lcid, pdp, &jsexcept, pspCaller);
break;
default:
FIXME("Unimplemented flags %x\n", wFlags);
return E_INVALIDARG;
}
if(pei)
*pei = jsexcept.ei;
return hres;
} }
static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
...@@ -464,3 +684,63 @@ HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, Dis ...@@ -464,3 +684,63 @@ HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, Dis
*dispex = ret; *dispex = ret;
return S_OK; return S_OK;
} }
DispatchEx *iface_to_jsdisp(IUnknown *iface)
{
DispatchEx *ret;
HRESULT hres;
hres = IUnknown_QueryInterface(iface, &IID_IDispatchJS, (void**)&ret);
if(FAILED(hres))
return NULL;
return ret;
}
HRESULT jsdisp_call(DispatchEx *disp, DISPID id, LCID lcid, WORD flags, DISPPARAMS *dp, VARIANT *retv,
jsexcept_t *ei, IServiceProvider *caller)
{
dispex_prop_t *prop;
memset(ei, 0, sizeof(*ei));
if(retv)
V_VT(retv) = VT_EMPTY;
prop = get_prop(disp, id);
if(!prop)
return DISP_E_MEMBERNOTFOUND;
return invoke_prop_func(disp, disp, prop, lcid, flags, dp, retv, ei, caller);
}
HRESULT disp_call(IDispatch *disp, DISPID id, LCID lcid, WORD flags, DISPPARAMS *dp, VARIANT *retv,
jsexcept_t *ei, IServiceProvider *caller)
{
DispatchEx *jsdisp;
IDispatchEx *dispex;
HRESULT hres;
jsdisp = iface_to_jsdisp((IUnknown*)disp);
if(jsdisp) {
hres = jsdisp_call(jsdisp, id, lcid, flags, dp, retv, ei, caller);
IDispatchEx_Release(_IDispatchEx_(jsdisp));
return hres;
}
memset(ei, 0, sizeof(*ei));
if(retv)
V_VT(retv) = VT_EMPTY;
hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
if(FAILED(hres)) {
UINT err = 0;
TRACE("using IDispatch\n");
return IDispatch_Invoke(disp, id, &IID_NULL, lcid, flags, dp, retv, &ei->ei, &err);
}
hres = IDispatchEx_InvokeEx(dispex, id, lcid, flags, dp, retv, &ei->ei, caller);
IDispatchEx_Release(dispex);
return hres;
}
...@@ -86,6 +86,7 @@ struct DispatchEx { ...@@ -86,6 +86,7 @@ struct DispatchEx {
#define _IDispatchEx_(x) ((IDispatchEx*) &(x)->lpIDispatchExVtbl) #define _IDispatchEx_(x) ((IDispatchEx*) &(x)->lpIDispatchExVtbl)
HRESULT create_dispex(script_ctx_t*,const builtin_info_t*,DispatchEx*,DispatchEx**); HRESULT create_dispex(script_ctx_t*,const builtin_info_t*,DispatchEx*,DispatchEx**);
HRESULT disp_call(IDispatch*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,jsexcept_t*,IServiceProvider*);
struct _script_ctx_t { struct _script_ctx_t {
LONG ref; LONG ref;
...@@ -104,6 +105,8 @@ static inline void script_addref(script_ctx_t *ctx) ...@@ -104,6 +105,8 @@ static inline void script_addref(script_ctx_t *ctx)
ctx->ref++; ctx->ref++;
} }
const char *debugstr_variant(const VARIANT*);
HRESULT WINAPI JScriptFactory_CreateInstance(IClassFactory*,IUnknown*,REFIID,void**); HRESULT WINAPI JScriptFactory_CreateInstance(IClassFactory*,IUnknown*,REFIID,void**);
typedef struct { typedef struct {
......
...@@ -38,6 +38,8 @@ static const CLSID CLSID_JScriptAuthor = ...@@ -38,6 +38,8 @@ static const CLSID CLSID_JScriptAuthor =
static const CLSID CLSID_JScriptEncode = static const CLSID CLSID_JScriptEncode =
{0xf414c262,0x6ac0,0x11cf,{0xb6,0xd1,0x00,0xaa,0x00,0xbb,0xbb,0x58}}; {0xf414c262,0x6ac0,0x11cf,{0xb6,0xd1,0x00,0xaa,0x00,0xbb,0xbb,0x58}};
DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
static HINSTANCE jscript_hinstance; static HINSTANCE jscript_hinstance;
static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
......
...@@ -22,6 +22,28 @@ ...@@ -22,6 +22,28 @@
WINE_DEFAULT_DEBUG_CHANNEL(jscript); WINE_DEFAULT_DEBUG_CHANNEL(jscript);
const char *debugstr_variant(const VARIANT *v)
{
switch(V_VT(v)) {
case VT_EMPTY:
return wine_dbg_sprintf("{VT_EMPTY}");
case VT_NULL:
return wine_dbg_sprintf("{VT_NULL}");
case VT_I4:
return wine_dbg_sprintf("{VT_I4: %d}", V_I4(v));
case VT_R8:
return wine_dbg_sprintf("{VT_R8: %lf}", V_R8(v));
case VT_BSTR:
return wine_dbg_sprintf("{VT_BSTR: %s}", debugstr_w(V_BSTR(v)));
case VT_DISPATCH:
return wine_dbg_sprintf("{VT_DISPATCH: %p}", V_DISPATCH(v));
case VT_BOOL:
return wine_dbg_sprintf("{VT_BOOL: %x}", V_BOOL(v));
default:
return wine_dbg_sprintf("{vt %d}", V_VT(v));
}
}
#define MIN_BLOCK_SIZE 128 #define MIN_BLOCK_SIZE 128
static inline DWORD block_size(DWORD block) static inline DWORD block_size(DWORD block)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment