2 * Copyright 2008 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wine/unicode.h"
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
29 * This IID is used to get jsdisp_t objecto from interface.
30 * We might consider using private interface instead.
32 static const IID IID_IDispatchJS =
33 {0x719c3050,0xf9d3,0x11cf,{0xa4,0x93,0x00,0x40,0x05,0x23,0xa8,0xa6}};
35 #define FDEX_VERSION_MASK 0xf0000000
36 #define GOLDEN_RATIO 0x9E3779B9U
45 struct _dispex_prop_t {
53 const builtin_prop_t *p;
61 static inline DISPID prop_to_id(jsdisp_t *This, dispex_prop_t *prop)
63 return prop - This->props;
66 static inline dispex_prop_t *get_prop(jsdisp_t *This, DISPID id)
68 if(id < 0 || id >= This->prop_cnt || This->props[id].type == PROP_DELETED)
71 return This->props+id;
74 static DWORD get_flags(jsdisp_t *This, dispex_prop_t *prop)
76 if(prop->type == PROP_PROTREF) {
77 dispex_prop_t *parent = get_prop(This->prototype, prop->u.ref);
79 prop->type = PROP_DELETED;
83 return get_flags(This->prototype, parent);
89 static const builtin_prop_t *find_builtin_prop(jsdisp_t *This, const WCHAR *name)
91 int min = 0, max, i, r;
93 max = This->builtin_info->props_cnt-1;
97 r = strcmpW(name, This->builtin_info->props[i].name);
99 return This->builtin_info->props + i;
110 static inline unsigned string_hash(const WCHAR *name)
114 h = (h>>(sizeof(unsigned)*8-4)) ^ (h<<4) ^ tolowerW(*name);
118 static inline unsigned get_props_idx(jsdisp_t *This, unsigned hash)
120 return (hash*GOLDEN_RATIO) & (This->buf_size-1);
123 static inline HRESULT resize_props(jsdisp_t *This)
125 dispex_prop_t *props;
128 if(This->buf_size != This->prop_cnt)
131 props = heap_realloc(This->props, sizeof(dispex_prop_t)*This->buf_size*2);
133 return E_OUTOFMEMORY;
137 for(i=0; i<This->buf_size; i++) {
138 This->props[i].bucket_head = 0;
139 This->props[i].bucket_next = 0;
142 for(i=1; i<This->prop_cnt; i++) {
143 props = This->props+i;
145 bucket = get_props_idx(This, props->hash);
146 props->bucket_next = This->props[bucket].bucket_head;
147 This->props[bucket].bucket_head = i;
153 static inline dispex_prop_t* alloc_prop(jsdisp_t *This, const WCHAR *name, prop_type_t type, DWORD flags)
158 if(FAILED(resize_props(This)))
161 prop = &This->props[This->prop_cnt];
162 prop->name = heap_strdupW(name);
167 prop->hash = string_hash(name);
169 bucket = get_props_idx(This, prop->hash);
170 prop->bucket_next = This->props[bucket].bucket_head;
171 This->props[bucket].bucket_head = This->prop_cnt++;
175 static dispex_prop_t *alloc_protref(jsdisp_t *This, const WCHAR *name, DWORD ref)
179 ret = alloc_prop(This, name, PROP_PROTREF, 0);
187 static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, dispex_prop_t **ret)
189 const builtin_prop_t *builtin;
190 unsigned bucket, pos, prev = 0;
193 bucket = get_props_idx(This, hash);
194 pos = This->props[bucket].bucket_head;
196 if(!strcmpW(name, This->props[pos].name)) {
198 This->props[prev].bucket_next = This->props[pos].bucket_next;
199 This->props[pos].bucket_next = This->props[bucket].bucket_head;
200 This->props[bucket].bucket_head = pos;
203 *ret = &This->props[pos];
208 pos = This->props[pos].bucket_next;
211 builtin = find_builtin_prop(This, name);
213 prop = alloc_prop(This, name, PROP_BUILTIN, builtin->flags);
215 return E_OUTOFMEMORY;
226 static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *name, dispex_prop_t **ret)
228 dispex_prop_t *prop, *del=NULL;
231 hres = find_prop_name(This, hash, name, &prop);
234 if(prop && prop->type==PROP_DELETED) {
241 if(This->prototype) {
242 hres = find_prop_name_prot(This->prototype, hash, name, &prop);
247 del->type = PROP_PROTREF;
249 del->u.ref = prop - This->prototype->props;
252 prop = alloc_protref(This, prop->name, prop - This->prototype->props);
254 return E_OUTOFMEMORY;
266 static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, BOOL search_prot, DWORD create_flags, dispex_prop_t **ret)
272 hres = find_prop_name_prot(This, string_hash(name), name, &prop);
274 hres = find_prop_name(This, string_hash(name), name, &prop);
275 if(SUCCEEDED(hres) && (!prop || prop->type == PROP_DELETED)) {
276 TRACE("creating prop %s flags %x\n", debugstr_w(name), create_flags);
279 prop->type = PROP_JSVAL;
280 prop->flags = create_flags;
281 prop->u.val = jsval_undefined();
283 prop = alloc_prop(This, name, PROP_JSVAL, create_flags);
285 return E_OUTOFMEMORY;
288 prop->u.val = jsval_undefined();
295 static IDispatch *get_this(DISPPARAMS *dp)
299 for(i=0; i < dp->cNamedArgs; i++) {
300 if(dp->rgdispidNamedArgs[i] == DISPID_THIS) {
301 if(V_VT(dp->rgvarg+i) == VT_DISPATCH)
302 return V_DISPATCH(dp->rgvarg+i);
304 WARN("This is not VT_DISPATCH\n");
309 TRACE("no this passed\n");
313 static HRESULT convert_params(const DISPPARAMS *dp, jsval_t *buf, unsigned *argc, jsval_t **ret)
320 cnt = dp->cArgs - dp->cNamedArgs;
323 argv = heap_alloc(cnt * sizeof(*argv));
325 return E_OUTOFMEMORY;
330 for(i = 0; i < cnt; i++) {
331 hres = variant_to_jsval(dp->rgvarg+dp->cArgs-i-1, argv+i);
334 jsval_release(argv[i]);
346 static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t *prop, WORD flags,
347 unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller)
353 if(flags == DISPATCH_CONSTRUCT && (prop->flags & PROPF_METHOD)) {
354 WARN("%s is not a constructor\n", debugstr_w(prop->name));
358 if(prop->name || This->builtin_info->class != JSCLASS_FUNCTION) {
362 set_disp(&vthis, jsthis);
364 set_jsdisp(&vthis, This);
365 hres = prop->u.p->invoke(This->ctx, &vthis, flags, argc, argv, r);
366 vdisp_release(&vthis);
368 /* Function object calls are special case */
369 hres = Function_invoke(This, jsthis, flags, argc, argv, r);
374 return invoke_prop_func(This->prototype, jsthis, This->prototype->props+prop->u.ref,
375 flags, argc, argv, r, caller);
377 if(!is_object_instance(prop->u.val)) {
378 FIXME("invoke %s\n", debugstr_jsval(prop->u.val));
382 TRACE("call %s %p\n", debugstr_w(prop->name), get_object(prop->u.val));
384 return disp_call_value(This->ctx, get_object(prop->u.val), jsthis, flags, argc, argv, r);
387 ERR("type %d\n", prop->type);
393 static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, DISPPARAMS *dp,
394 jsval_t *r, IServiceProvider *caller)
400 if(prop->u.p->flags & PROPF_METHOD) {
402 hres = create_builtin_function(This->ctx, prop->u.p->invoke, prop->u.p->name, NULL,
403 prop->u.p->flags, NULL, &obj);
407 prop->type = PROP_JSVAL;
408 prop->u.val = jsval_obj(obj);
415 set_jsdisp(&vthis, This);
416 hres = prop->u.p->invoke(This->ctx, &vthis, DISPATCH_PROPERTYGET, 0, NULL, r);
417 vdisp_release(&vthis);
421 hres = prop_get(This->prototype, This->prototype->props+prop->u.ref, dp, r, caller);
424 hres = jsval_copy(prop->u.val, r);
427 ERR("type %d\n", prop->type);
432 TRACE("fail %08x\n", hres);
436 TRACE("%s ret %s\n", debugstr_w(prop->name), debugstr_jsval(*r));
440 static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val, IServiceProvider *caller)
444 if(prop->flags & PROPF_CONST)
449 if(!(prop->flags & PROPF_METHOD)) {
452 set_jsdisp(&vthis, This);
453 hres = prop->u.p->invoke(This->ctx, &vthis, DISPATCH_PROPERTYPUT, 1, &val, NULL);
454 vdisp_release(&vthis);
459 prop->type = PROP_JSVAL;
460 prop->flags = PROPF_ENUM;
461 prop->u.val = jsval_undefined();
464 jsval_release(prop->u.val);
467 ERR("type %d\n", prop->type);
471 TRACE("%s = %s\n", debugstr_w(prop->name), debugstr_jsval(val));
473 hres = jsval_copy(val, &prop->u.val);
475 prop->u.val = jsval_undefined();
479 if(This->builtin_info->on_put)
480 This->builtin_info->on_put(This, prop->name);
482 TRACE("%s = %s\n", debugstr_w(prop->name), debugstr_jsval(val));
486 static HRESULT fill_protrefs(jsdisp_t *This)
488 dispex_prop_t *iter, *prop;
494 fill_protrefs(This->prototype);
496 for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) {
499 hres = find_prop_name(This, iter->hash, iter->name, &prop);
502 if(!prop || prop->type==PROP_DELETED) {
504 prop->type = PROP_PROTREF;
506 prop->u.ref = iter - This->prototype->props;
508 prop = alloc_protref(This, iter->name, iter - This->prototype->props);
510 return E_OUTOFMEMORY;
518 static inline jsdisp_t *impl_from_IDispatchEx(IDispatchEx *iface)
520 return CONTAINING_RECORD(iface, jsdisp_t, IDispatchEx_iface);
523 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
525 jsdisp_t *This = impl_from_IDispatchEx(iface);
527 if(IsEqualGUID(&IID_IUnknown, riid)) {
528 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
529 *ppv = &This->IDispatchEx_iface;
530 }else if(IsEqualGUID(&IID_IDispatch, riid)) {
531 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
532 *ppv = &This->IDispatchEx_iface;
533 }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
534 TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
535 *ppv = &This->IDispatchEx_iface;
536 }else if(IsEqualGUID(&IID_IDispatchJS, riid)) {
537 TRACE("(%p)->(IID_IDispatchJS %p)\n", This, ppv);
542 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
544 return E_NOINTERFACE;
551 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
553 jsdisp_t *This = impl_from_IDispatchEx(iface);
558 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
560 jsdisp_t *This = impl_from_IDispatchEx(iface);
561 ULONG ref = --This->ref;
567 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
569 jsdisp_t *This = impl_from_IDispatchEx(iface);
571 TRACE("(%p)->(%p)\n", This, pctinfo);
577 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid,
580 jsdisp_t *This = impl_from_IDispatchEx(iface);
581 FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
585 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
586 LPOLESTR *rgszNames, UINT cNames, LCID lcid,
589 jsdisp_t *This = impl_from_IDispatchEx(iface);
593 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
596 for(i=0; i < cNames; i++) {
597 hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[i], 0, rgDispId+i);
605 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
606 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
607 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
609 jsdisp_t *This = impl_from_IDispatchEx(iface);
611 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
612 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
614 return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags,
615 pDispParams, pVarResult, pExcepInfo, NULL);
618 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
620 jsdisp_t *This = impl_from_IDispatchEx(iface);
622 TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
624 if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) {
625 FIXME("Unsupported grfdex %x\n", grfdex);
629 return jsdisp_get_id(This, bstrName, grfdex, pid);
632 static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
633 VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
635 jsdisp_t *This = impl_from_IDispatchEx(iface);
639 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
642 V_VT(pvarRes) = VT_EMPTY;
644 prop = get_prop(This, id);
645 if(!prop || prop->type == PROP_DELETED) {
646 TRACE("invalid id\n");
647 return DISP_E_MEMBERNOTFOUND;
653 case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
654 wFlags = DISPATCH_METHOD;
656 case DISPATCH_METHOD:
657 case DISPATCH_CONSTRUCT: {
658 jsval_t *argv, buf[6], r;
661 hres = convert_params(pdp, buf, &argc, &argv);
665 hres = invoke_prop_func(This, get_this(pdp), prop, wFlags, argc, argv, pvarRes ? &r : NULL, pspCaller);
668 if(SUCCEEDED(hres) && pvarRes) {
669 hres = jsval_to_variant(r, pvarRes);
674 case DISPATCH_PROPERTYGET: {
677 hres = prop_get(This, prop, pdp, &r, pspCaller);
678 if(SUCCEEDED(hres)) {
679 hres = jsval_to_variant(r, pvarRes);
684 case DISPATCH_PROPERTYPUT: {
688 for(i=0; i < pdp->cNamedArgs; i++) {
689 if(pdp->rgdispidNamedArgs[i] == DISPID_PROPERTYPUT)
693 if(i == pdp->cNamedArgs) {
694 TRACE("no value to set\n");
695 return DISP_E_PARAMNOTOPTIONAL;
698 hres = variant_to_jsval(pdp->rgvarg+i, &val);
702 hres = prop_put(This, prop, val, pspCaller);
707 FIXME("Unimplemented flags %x\n", wFlags);
712 *pei = This->ctx->ei.ei;
716 static HRESULT delete_prop(dispex_prop_t *prop)
718 if(prop->type == PROP_JSVAL) {
719 jsval_release(prop->u.val);
720 prop->type = PROP_DELETED;
725 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
727 jsdisp_t *This = impl_from_IDispatchEx(iface);
731 TRACE("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex);
733 if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK))
734 FIXME("Unsupported grfdex %x\n", grfdex);
736 hres = find_prop_name(This, string_hash(bstrName), bstrName, &prop);
740 TRACE("not found\n");
744 return delete_prop(prop);
747 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
749 jsdisp_t *This = impl_from_IDispatchEx(iface);
752 TRACE("(%p)->(%x)\n", This, id);
754 prop = get_prop(This, id);
756 WARN("invalid id\n");
757 return DISP_E_MEMBERNOTFOUND;
760 return delete_prop(prop);
763 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
765 jsdisp_t *This = impl_from_IDispatchEx(iface);
766 FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex);
770 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
772 jsdisp_t *This = impl_from_IDispatchEx(iface);
775 TRACE("(%p)->(%x %p)\n", This, id, pbstrName);
777 prop = get_prop(This, id);
778 if(!prop || !prop->name || prop->type == PROP_DELETED)
779 return DISP_E_MEMBERNOTFOUND;
781 *pbstrName = SysAllocString(prop->name);
783 return E_OUTOFMEMORY;
788 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
790 jsdisp_t *This = impl_from_IDispatchEx(iface);
794 TRACE("(%p)->(%x %x %p)\n", This, grfdex, id, pid);
796 if(id == DISPID_STARTENUM) {
797 hres = fill_protrefs(This);
802 if(id+1>=0 && id+1<This->prop_cnt) {
803 iter = &This->props[id+1];
805 *pid = DISPID_STARTENUM;
809 while(iter < This->props + This->prop_cnt) {
810 if(iter->name && (get_flags(This, iter) & PROPF_ENUM) && iter->type!=PROP_DELETED) {
811 *pid = prop_to_id(This, iter);
817 *pid = DISPID_STARTENUM;
821 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
823 jsdisp_t *This = impl_from_IDispatchEx(iface);
824 FIXME("(%p)->(%p)\n", This, ppunk);
828 static IDispatchExVtbl DispatchExVtbl = {
829 DispatchEx_QueryInterface,
832 DispatchEx_GetTypeInfoCount,
833 DispatchEx_GetTypeInfo,
834 DispatchEx_GetIDsOfNames,
836 DispatchEx_GetDispID,
838 DispatchEx_DeleteMemberByName,
839 DispatchEx_DeleteMemberByDispID,
840 DispatchEx_GetMemberProperties,
841 DispatchEx_GetMemberName,
842 DispatchEx_GetNextDispID,
843 DispatchEx_GetNameSpaceParent
846 jsdisp_t *as_jsdisp(IDispatch *disp)
848 assert(disp->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl);
849 return impl_from_IDispatchEx((IDispatchEx*)disp);
852 jsdisp_t *to_jsdisp(IDispatch *disp)
854 return disp->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl ? impl_from_IDispatchEx((IDispatchEx*)disp) : NULL;
857 HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype)
859 TRACE("%p (%p)\n", dispex, prototype);
861 dispex->IDispatchEx_iface.lpVtbl = &DispatchExVtbl;
863 dispex->builtin_info = builtin_info;
865 dispex->props = heap_alloc_zero(sizeof(dispex_prop_t)*(dispex->buf_size=4));
867 return E_OUTOFMEMORY;
869 dispex->prototype = prototype;
871 jsdisp_addref(prototype);
873 dispex->prop_cnt = 1;
874 if(builtin_info->value_prop.invoke) {
875 dispex->props[0].type = PROP_BUILTIN;
876 dispex->props[0].u.p = &builtin_info->value_prop;
878 dispex->props[0].type = PROP_DELETED;
887 static const builtin_info_t dispex_info = {
895 HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype, jsdisp_t **dispex)
900 ret = heap_alloc_zero(sizeof(jsdisp_t));
902 return E_OUTOFMEMORY;
904 hres = init_dispex(ret, ctx, builtin_info ? builtin_info : &dispex_info, prototype);
914 void jsdisp_free(jsdisp_t *obj)
918 TRACE("(%p)\n", obj);
920 for(prop = obj->props; prop < obj->props+obj->prop_cnt; prop++) {
921 if(prop->type == PROP_JSVAL)
922 jsval_release(prop->u.val);
923 heap_free(prop->name);
925 heap_free(obj->props);
926 script_release(obj->ctx);
928 jsdisp_release(obj->prototype);
930 if(obj->builtin_info->destructor)
931 obj->builtin_info->destructor(obj);
938 jsdisp_t *jsdisp_addref(jsdisp_t *jsdisp)
940 ULONG ref = ++jsdisp->ref;
941 TRACE("(%p) ref=%d\n", jsdisp, ref);
945 void jsdisp_release(jsdisp_t *jsdisp)
947 ULONG ref = --jsdisp->ref;
949 TRACE("(%p) ref=%d\n", jsdisp, ref);
957 HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *constr)
959 jsdisp_t *prot = NULL;
963 static const WCHAR prototypeW[] = {'p','r','o','t','o','t','y','p','e',0};
965 hres = find_prop_name_prot(constr, string_hash(prototypeW), prototypeW, &prop);
966 if(SUCCEEDED(hres) && prop && prop->type!=PROP_DELETED) {
969 hres = prop_get(constr, prop, NULL, &val, NULL);
971 ERR("Could not get prototype\n");
975 if(is_object_instance(val))
976 prot = iface_to_jsdisp((IUnknown*)get_object(val));
980 hres = init_dispex(dispex, ctx, builtin_info, prot);
983 jsdisp_release(prot);
987 jsdisp_t *iface_to_jsdisp(IUnknown *iface)
992 hres = IUnknown_QueryInterface(iface, &IID_IDispatchJS, (void**)&ret);
999 HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID *id)
1001 dispex_prop_t *prop;
1004 if(flags & fdexNameEnsure)
1005 hres = ensure_prop_name(jsdisp, name, TRUE, PROPF_ENUM, &prop);
1007 hres = find_prop_name_prot(jsdisp, string_hash(name), name, &prop);
1011 if(prop && prop->type!=PROP_DELETED) {
1012 *id = prop_to_id(jsdisp, prop);
1016 TRACE("not found %s\n", debugstr_w(name));
1017 return DISP_E_UNKNOWNNAME;
1020 HRESULT jsdisp_call_value(jsdisp_t *jsfunc, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1024 if(is_class(jsfunc, JSCLASS_FUNCTION)) {
1025 hres = Function_invoke(jsfunc, jsthis, flags, argc, argv, r);
1029 set_disp(&vdisp, jsthis);
1030 hres = jsfunc->builtin_info->value_prop.invoke(jsfunc->ctx, &vdisp, flags, argc, argv, r);
1031 vdisp_release(&vdisp);
1036 HRESULT jsdisp_call(jsdisp_t *disp, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1038 dispex_prop_t *prop;
1040 prop = get_prop(disp, id);
1042 return DISP_E_MEMBERNOTFOUND;
1044 return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, NULL);
1047 HRESULT jsdisp_call_name(jsdisp_t *disp, const WCHAR *name, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1049 dispex_prop_t *prop;
1052 hres = find_prop_name_prot(disp, string_hash(name), name, &prop);
1056 return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, NULL);
1059 HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *ret)
1061 IDispatchEx *dispex;
1063 VARIANT buf[6], retv;
1068 jsdisp = iface_to_jsdisp((IUnknown*)disp);
1070 if(flags & DISPATCH_PROPERTYPUT) {
1071 FIXME("disp_call(propput) on builtin object\n");
1075 hres = jsdisp_call(jsdisp, id, flags, argc, argv, ret);
1076 jsdisp_release(jsdisp);
1081 flags |= DISPATCH_PROPERTYGET;
1085 if(flags & DISPATCH_PROPERTYPUT) {
1086 static DISPID propput_dispid = DISPID_PROPERTYPUT;
1089 dp.rgdispidNamedArgs = &propput_dispid;
1092 dp.rgdispidNamedArgs = NULL;
1096 dp.rgvarg = heap_alloc(argc*sizeof(VARIANT));
1098 return E_OUTOFMEMORY;
1103 for(i=0; i<argc; i++) {
1104 hres = jsval_to_variant(argv[i], dp.rgvarg+argc-i-1);
1107 VariantClear(dp.rgvarg+argc-i-1);
1108 if(dp.rgvarg != buf)
1109 heap_free(dp.rgvarg);
1114 V_VT(&retv) = VT_EMPTY;
1116 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1117 if(SUCCEEDED(hres)) {
1118 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, &dp, ret ? &retv : NULL, &ctx->ei.ei,
1119 &ctx->jscaller->IServiceProvider_iface);
1120 IDispatchEx_Release(dispex);
1124 if(flags == DISPATCH_CONSTRUCT) {
1125 WARN("IDispatch cannot be constructor\n");
1126 return DISP_E_MEMBERNOTFOUND;
1129 TRACE("using IDispatch\n");
1130 hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, &dp, ret ? &retv : NULL, &ctx->ei.ei, &err);
1133 for(i=0; i<argc; i++)
1134 VariantClear(dp.rgvarg+argc-i-1);
1135 if(dp.rgvarg != buf)
1136 heap_free(dp.rgvarg);
1141 hres = variant_to_jsval(&retv, ret);
1142 VariantClear(&retv);
1147 HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1151 IDispatchEx *dispex;
1152 VARIANT buf[6], retv;
1157 jsdisp = iface_to_jsdisp((IUnknown*)disp);
1159 if(flags & DISPATCH_PROPERTYPUT) {
1160 FIXME("disp_call(propput) on builtin object\n");
1164 hres = jsdisp_call_value(jsdisp, jsthis, flags, argc, argv, r);
1165 jsdisp_release(jsdisp);
1170 flags |= DISPATCH_PROPERTYGET;
1174 static DISPID this_id = DISPID_THIS;
1178 dp.rgdispidNamedArgs = &this_id;
1182 dp.rgdispidNamedArgs = NULL;
1185 if(dp.cArgs > sizeof(buf)/sizeof(*buf)) {
1186 dp.rgvarg = heap_alloc(dp.cArgs*sizeof(VARIANT));
1188 return E_OUTOFMEMORY;
1193 for(i=0; i<argc; i++) {
1194 hres = jsval_to_variant(argv[i], dp.rgvarg+dp.cArgs-i-1);
1197 VariantClear(dp.rgvarg+dp.cArgs-i-1);
1198 if(dp.rgvarg != buf)
1199 heap_free(dp.rgvarg);
1204 V_VT(dp.rgvarg) = VT_DISPATCH;
1205 V_DISPATCH(dp.rgvarg) = jsthis;
1208 V_VT(&retv) = VT_EMPTY;
1210 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1211 if(SUCCEEDED(hres)) {
1212 hres = IDispatchEx_InvokeEx(dispex, DISPID_VALUE, ctx->lcid, flags, &dp, r ? &retv : NULL, &ctx->ei.ei,
1213 &ctx->jscaller->IServiceProvider_iface);
1214 IDispatchEx_Release(dispex);
1218 if(flags == DISPATCH_CONSTRUCT) {
1219 WARN("IDispatch cannot be constructor\n");
1220 return DISP_E_MEMBERNOTFOUND;
1223 TRACE("using IDispatch\n");
1224 hres = IDispatch_Invoke(disp, DISPID_VALUE, &IID_NULL, ctx->lcid, flags, &dp, r ? &retv : NULL, &ctx->ei.ei, &err);
1227 for(i=0; i<argc; i++)
1228 VariantClear(dp.rgvarg+dp.cArgs-i-1);
1229 if(dp.rgvarg != buf)
1230 heap_free(dp.rgvarg);
1237 hres = variant_to_jsval(&retv, r);
1238 VariantClear(&retv);
1242 HRESULT jsdisp_propput_name(jsdisp_t *obj, const WCHAR *name, jsval_t val)
1244 dispex_prop_t *prop;
1247 hres = ensure_prop_name(obj, name, FALSE, PROPF_ENUM, &prop);
1251 return prop_put(obj, prop, val, NULL);
1254 HRESULT jsdisp_propput_const(jsdisp_t *obj, const WCHAR *name, jsval_t val)
1256 dispex_prop_t *prop;
1259 hres = ensure_prop_name(obj, name, FALSE, PROPF_CONST, &prop);
1263 return jsval_copy(val, &prop->u.val);
1266 HRESULT jsdisp_propput_dontenum(jsdisp_t *obj, const WCHAR *name, jsval_t val)
1268 dispex_prop_t *prop;
1271 hres = ensure_prop_name(obj, name, FALSE, 0, &prop);
1275 return prop_put(obj, prop, val, NULL);
1278 HRESULT jsdisp_propput_idx(jsdisp_t *obj, DWORD idx, jsval_t val)
1282 static const WCHAR formatW[] = {'%','d',0};
1284 sprintfW(buf, formatW, idx);
1285 return jsdisp_propput_name(obj, buf, val);
1288 HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val)
1293 jsdisp = iface_to_jsdisp((IUnknown*)disp);
1295 dispex_prop_t *prop;
1297 prop = get_prop(jsdisp, id);
1299 hres = prop_put(jsdisp, prop, val, NULL);
1301 hres = DISP_E_MEMBERNOTFOUND;
1303 jsdisp_release(jsdisp);
1305 DISPID dispid = DISPID_PROPERTYPUT;
1307 DISPPARAMS dp = {&var, &dispid, 1, 1};
1308 IDispatchEx *dispex;
1310 hres = jsval_to_variant(val, &var);
1315 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1316 if(SUCCEEDED(hres)) {
1317 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, DISPATCH_PROPERTYPUT, &dp, NULL, &ctx->ei.ei,
1318 &ctx->jscaller->IServiceProvider_iface);
1319 IDispatchEx_Release(dispex);
1323 TRACE("using IDispatch\n");
1324 hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, DISPATCH_PROPERTYPUT, &dp, NULL, &ctx->ei.ei, &err);
1333 HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val)
1335 DISPPARAMS dp = {NULL, NULL, 0, 0};
1336 dispex_prop_t *prop;
1339 hres = find_prop_name_prot(obj, string_hash(name), name, &prop);
1343 if(!prop || prop->type==PROP_DELETED) {
1344 *val = jsval_undefined();
1348 return prop_get(obj, prop, &dp, val, NULL);
1351 HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r)
1354 DISPPARAMS dp = {NULL, NULL, 0, 0};
1355 dispex_prop_t *prop;
1358 static const WCHAR formatW[] = {'%','d',0};
1360 sprintfW(name, formatW, idx);
1362 hres = find_prop_name_prot(obj, string_hash(name), name, &prop);
1366 if(!prop || prop->type==PROP_DELETED) {
1367 *r = jsval_undefined();
1368 return DISP_E_UNKNOWNNAME;
1371 return prop_get(obj, prop, &dp, r, NULL);
1374 HRESULT jsdisp_propget(jsdisp_t *jsdisp, DISPID id, jsval_t *val)
1376 DISPPARAMS dp = {NULL,NULL,0,0};
1377 dispex_prop_t *prop;
1379 prop = get_prop(jsdisp, id);
1381 return DISP_E_MEMBERNOTFOUND;
1383 return prop_get(jsdisp, prop, &dp, val, NULL);
1386 HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t *val)
1388 DISPPARAMS dp = {NULL,NULL,0,0};
1389 IDispatchEx *dispex;
1394 jsdisp = iface_to_jsdisp((IUnknown*)disp);
1396 hres = jsdisp_propget(jsdisp, id, val);
1397 jsdisp_release(jsdisp);
1401 V_VT(&var) = VT_EMPTY;
1403 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1404 if(SUCCEEDED(hres)) {
1405 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, INVOKE_PROPERTYGET, &dp, &var, &ctx->ei.ei,
1406 &ctx->jscaller->IServiceProvider_iface);
1407 IDispatchEx_Release(dispex);
1411 TRACE("using IDispatch\n");
1412 hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, INVOKE_PROPERTYGET, &dp, &var, &ctx->ei.ei, &err);
1417 hres = variant_to_jsval(&var, val);
1422 HRESULT jsdisp_delete_idx(jsdisp_t *obj, DWORD idx)
1424 static const WCHAR formatW[] = {'%','d',0};
1426 dispex_prop_t *prop;
1429 sprintfW(buf, formatW, idx);
1431 hres = find_prop_name(obj, string_hash(buf), buf, &prop);
1432 if(FAILED(hres) || !prop)
1435 return delete_prop(prop);
1438 HRESULT jsdisp_is_own_prop(jsdisp_t *obj, const WCHAR *name, BOOL *ret)
1440 dispex_prop_t *prop;
1443 hres = find_prop_name(obj, string_hash(name), name, &prop);
1447 *ret = prop && (prop->type == PROP_JSVAL || prop->type == PROP_BUILTIN);
1451 HRESULT jsdisp_is_enumerable(jsdisp_t *obj, const WCHAR *name, BOOL *ret)
1453 dispex_prop_t *prop;
1456 hres = find_prop_name(obj, string_hash(name), name, &prop);
1460 *ret = prop && (prop->flags & PROPF_ENUM) && prop->type != PROP_PROTREF;