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\n", debugstr_w(name
));
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
);
458 prop
->type
= PROP_JSVAL
;
459 prop
->flags
= PROPF_ENUM
;
460 prop
->u
.val
= jsval_undefined();
463 jsval_release(prop
->u
.val
);
466 ERR("type %d\n", prop
->type
);
470 TRACE("%s = %s\n", debugstr_w(prop
->name
), debugstr_jsval(val
));
472 hres
= jsval_copy(val
, &prop
->u
.val
);
474 prop
->u
.val
= jsval_undefined();
478 if(This
->builtin_info
->on_put
)
479 This
->builtin_info
->on_put(This
, prop
->name
);
481 TRACE("%s = %s\n", debugstr_w(prop
->name
), debugstr_jsval(val
));
485 static HRESULT
fill_protrefs(jsdisp_t
*This
)
487 dispex_prop_t
*iter
, *prop
;
493 fill_protrefs(This
->prototype
);
495 for(iter
= This
->prototype
->props
; iter
< This
->prototype
->props
+This
->prototype
->prop_cnt
; iter
++) {
498 hres
= find_prop_name(This
, iter
->hash
, iter
->name
, &prop
);
501 if(!prop
|| prop
->type
==PROP_DELETED
) {
503 prop
->type
= PROP_PROTREF
;
505 prop
->u
.ref
= iter
- This
->prototype
->props
;
507 prop
= alloc_protref(This
, iter
->name
, iter
- This
->prototype
->props
);
509 return E_OUTOFMEMORY
;
517 static inline jsdisp_t
*impl_from_IDispatchEx(IDispatchEx
*iface
)
519 return CONTAINING_RECORD(iface
, jsdisp_t
, IDispatchEx_iface
);
522 static HRESULT WINAPI
DispatchEx_QueryInterface(IDispatchEx
*iface
, REFIID riid
, void **ppv
)
524 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
526 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
527 TRACE("(%p)->(IID_IUnknown %p)\n", This
, ppv
);
528 *ppv
= &This
->IDispatchEx_iface
;
529 }else if(IsEqualGUID(&IID_IDispatch
, riid
)) {
530 TRACE("(%p)->(IID_IDispatch %p)\n", This
, ppv
);
531 *ppv
= &This
->IDispatchEx_iface
;
532 }else if(IsEqualGUID(&IID_IDispatchEx
, riid
)) {
533 TRACE("(%p)->(IID_IDispatchEx %p)\n", This
, ppv
);
534 *ppv
= &This
->IDispatchEx_iface
;
535 }else if(IsEqualGUID(&IID_IDispatchJS
, riid
)) {
536 TRACE("(%p)->(IID_IDispatchJS %p)\n", This
, ppv
);
541 WARN("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
543 return E_NOINTERFACE
;
550 static ULONG WINAPI
DispatchEx_AddRef(IDispatchEx
*iface
)
552 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
557 static ULONG WINAPI
DispatchEx_Release(IDispatchEx
*iface
)
559 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
560 ULONG ref
= --This
->ref
;
566 static HRESULT WINAPI
DispatchEx_GetTypeInfoCount(IDispatchEx
*iface
, UINT
*pctinfo
)
568 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
570 TRACE("(%p)->(%p)\n", This
, pctinfo
);
576 static HRESULT WINAPI
DispatchEx_GetTypeInfo(IDispatchEx
*iface
, UINT iTInfo
, LCID lcid
,
579 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
580 FIXME("(%p)->(%u %u %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
584 static HRESULT WINAPI
DispatchEx_GetIDsOfNames(IDispatchEx
*iface
, REFIID riid
,
585 LPOLESTR
*rgszNames
, UINT cNames
, LCID lcid
,
588 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
592 TRACE("(%p)->(%s %p %u %u %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
,
595 for(i
=0; i
< cNames
; i
++) {
596 hres
= IDispatchEx_GetDispID(&This
->IDispatchEx_iface
, rgszNames
[i
], 0, rgDispId
+i
);
604 static HRESULT WINAPI
DispatchEx_Invoke(IDispatchEx
*iface
, DISPID dispIdMember
,
605 REFIID riid
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
,
606 VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
608 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
610 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This
, dispIdMember
, debugstr_guid(riid
),
611 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
613 return IDispatchEx_InvokeEx(&This
->IDispatchEx_iface
, dispIdMember
, lcid
, wFlags
,
614 pDispParams
, pVarResult
, pExcepInfo
, NULL
);
617 static HRESULT WINAPI
DispatchEx_GetDispID(IDispatchEx
*iface
, BSTR bstrName
, DWORD grfdex
, DISPID
*pid
)
619 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
621 TRACE("(%p)->(%s %x %p)\n", This
, debugstr_w(bstrName
), grfdex
, pid
);
623 if(grfdex
& ~(fdexNameCaseSensitive
|fdexNameEnsure
|fdexNameImplicit
|FDEX_VERSION_MASK
)) {
624 FIXME("Unsupported grfdex %x\n", grfdex
);
628 return jsdisp_get_id(This
, bstrName
, grfdex
, pid
);
631 static HRESULT WINAPI
DispatchEx_InvokeEx(IDispatchEx
*iface
, DISPID id
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pdp
,
632 VARIANT
*pvarRes
, EXCEPINFO
*pei
, IServiceProvider
*pspCaller
)
634 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
638 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This
, id
, lcid
, wFlags
, pdp
, pvarRes
, pei
, pspCaller
);
641 V_VT(pvarRes
) = VT_EMPTY
;
643 prop
= get_prop(This
, id
);
644 if(!prop
|| prop
->type
== PROP_DELETED
) {
645 TRACE("invalid id\n");
646 return DISP_E_MEMBERNOTFOUND
;
652 case DISPATCH_METHOD
|DISPATCH_PROPERTYGET
:
653 wFlags
= DISPATCH_METHOD
;
655 case DISPATCH_METHOD
:
656 case DISPATCH_CONSTRUCT
: {
657 jsval_t
*argv
, buf
[6], r
;
660 hres
= convert_params(pdp
, buf
, &argc
, &argv
);
664 hres
= invoke_prop_func(This
, get_this(pdp
), prop
, wFlags
, argc
, argv
, pvarRes
? &r
: NULL
, pspCaller
);
667 if(SUCCEEDED(hres
) && pvarRes
) {
668 hres
= jsval_to_variant(r
, pvarRes
);
673 case DISPATCH_PROPERTYGET
: {
676 hres
= prop_get(This
, prop
, pdp
, &r
, pspCaller
);
677 if(SUCCEEDED(hres
)) {
678 hres
= jsval_to_variant(r
, pvarRes
);
683 case DISPATCH_PROPERTYPUT
: {
687 for(i
=0; i
< pdp
->cNamedArgs
; i
++) {
688 if(pdp
->rgdispidNamedArgs
[i
] == DISPID_PROPERTYPUT
)
692 if(i
== pdp
->cNamedArgs
) {
693 TRACE("no value to set\n");
694 return DISP_E_PARAMNOTOPTIONAL
;
697 hres
= variant_to_jsval(pdp
->rgvarg
+i
, &val
);
701 hres
= prop_put(This
, prop
, val
, pspCaller
);
706 FIXME("Unimplemented flags %x\n", wFlags
);
711 *pei
= This
->ctx
->ei
.ei
;
715 static HRESULT
delete_prop(dispex_prop_t
*prop
)
717 if(prop
->type
== PROP_JSVAL
) {
718 jsval_release(prop
->u
.val
);
719 prop
->type
= PROP_DELETED
;
724 static HRESULT WINAPI
DispatchEx_DeleteMemberByName(IDispatchEx
*iface
, BSTR bstrName
, DWORD grfdex
)
726 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
730 TRACE("(%p)->(%s %x)\n", This
, debugstr_w(bstrName
), grfdex
);
732 if(grfdex
& ~(fdexNameCaseSensitive
|fdexNameEnsure
|fdexNameImplicit
|FDEX_VERSION_MASK
))
733 FIXME("Unsupported grfdex %x\n", grfdex
);
735 hres
= find_prop_name(This
, string_hash(bstrName
), bstrName
, &prop
);
739 TRACE("not found\n");
743 return delete_prop(prop
);
746 static HRESULT WINAPI
DispatchEx_DeleteMemberByDispID(IDispatchEx
*iface
, DISPID id
)
748 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
751 TRACE("(%p)->(%x)\n", This
, id
);
753 prop
= get_prop(This
, id
);
755 WARN("invalid id\n");
756 return DISP_E_MEMBERNOTFOUND
;
759 return delete_prop(prop
);
762 static HRESULT WINAPI
DispatchEx_GetMemberProperties(IDispatchEx
*iface
, DISPID id
, DWORD grfdexFetch
, DWORD
*pgrfdex
)
764 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
765 FIXME("(%p)->(%x %x %p)\n", This
, id
, grfdexFetch
, pgrfdex
);
769 static HRESULT WINAPI
DispatchEx_GetMemberName(IDispatchEx
*iface
, DISPID id
, BSTR
*pbstrName
)
771 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
774 TRACE("(%p)->(%x %p)\n", This
, id
, pbstrName
);
776 prop
= get_prop(This
, id
);
777 if(!prop
|| !prop
->name
|| prop
->type
== PROP_DELETED
)
778 return DISP_E_MEMBERNOTFOUND
;
780 *pbstrName
= SysAllocString(prop
->name
);
782 return E_OUTOFMEMORY
;
787 static HRESULT WINAPI
DispatchEx_GetNextDispID(IDispatchEx
*iface
, DWORD grfdex
, DISPID id
, DISPID
*pid
)
789 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
793 TRACE("(%p)->(%x %x %p)\n", This
, grfdex
, id
, pid
);
795 if(id
== DISPID_STARTENUM
) {
796 hres
= fill_protrefs(This
);
801 if(id
+1>=0 && id
+1<This
->prop_cnt
) {
802 iter
= &This
->props
[id
+1];
804 *pid
= DISPID_STARTENUM
;
808 while(iter
< This
->props
+ This
->prop_cnt
) {
809 if(iter
->name
&& (get_flags(This
, iter
) & PROPF_ENUM
) && iter
->type
!=PROP_DELETED
) {
810 *pid
= prop_to_id(This
, iter
);
816 *pid
= DISPID_STARTENUM
;
820 static HRESULT WINAPI
DispatchEx_GetNameSpaceParent(IDispatchEx
*iface
, IUnknown
**ppunk
)
822 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
823 FIXME("(%p)->(%p)\n", This
, ppunk
);
827 static IDispatchExVtbl DispatchExVtbl
= {
828 DispatchEx_QueryInterface
,
831 DispatchEx_GetTypeInfoCount
,
832 DispatchEx_GetTypeInfo
,
833 DispatchEx_GetIDsOfNames
,
835 DispatchEx_GetDispID
,
837 DispatchEx_DeleteMemberByName
,
838 DispatchEx_DeleteMemberByDispID
,
839 DispatchEx_GetMemberProperties
,
840 DispatchEx_GetMemberName
,
841 DispatchEx_GetNextDispID
,
842 DispatchEx_GetNameSpaceParent
845 jsdisp_t
*as_jsdisp(IDispatch
*disp
)
847 assert(disp
->lpVtbl
== (IDispatchVtbl
*)&DispatchExVtbl
);
848 return impl_from_IDispatchEx((IDispatchEx
*)disp
);
851 jsdisp_t
*to_jsdisp(IDispatch
*disp
)
853 return disp
->lpVtbl
== (IDispatchVtbl
*)&DispatchExVtbl
? impl_from_IDispatchEx((IDispatchEx
*)disp
) : NULL
;
856 HRESULT
init_dispex(jsdisp_t
*dispex
, script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*prototype
)
858 TRACE("%p (%p)\n", dispex
, prototype
);
860 dispex
->IDispatchEx_iface
.lpVtbl
= &DispatchExVtbl
;
862 dispex
->builtin_info
= builtin_info
;
864 dispex
->props
= heap_alloc_zero(sizeof(dispex_prop_t
)*(dispex
->buf_size
=4));
866 return E_OUTOFMEMORY
;
868 dispex
->prototype
= prototype
;
870 jsdisp_addref(prototype
);
872 dispex
->prop_cnt
= 1;
873 if(builtin_info
->value_prop
.invoke
) {
874 dispex
->props
[0].type
= PROP_BUILTIN
;
875 dispex
->props
[0].u
.p
= &builtin_info
->value_prop
;
877 dispex
->props
[0].type
= PROP_DELETED
;
886 static const builtin_info_t dispex_info
= {
894 HRESULT
create_dispex(script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*prototype
, jsdisp_t
**dispex
)
899 ret
= heap_alloc_zero(sizeof(jsdisp_t
));
901 return E_OUTOFMEMORY
;
903 hres
= init_dispex(ret
, ctx
, builtin_info
? builtin_info
: &dispex_info
, prototype
);
913 void jsdisp_free(jsdisp_t
*obj
)
917 TRACE("(%p)\n", obj
);
919 for(prop
= obj
->props
; prop
< obj
->props
+obj
->prop_cnt
; prop
++) {
920 if(prop
->type
== PROP_JSVAL
)
921 jsval_release(prop
->u
.val
);
922 heap_free(prop
->name
);
924 heap_free(obj
->props
);
925 script_release(obj
->ctx
);
927 jsdisp_release(obj
->prototype
);
929 if(obj
->builtin_info
->destructor
)
930 obj
->builtin_info
->destructor(obj
);
937 jsdisp_t
*jsdisp_addref(jsdisp_t
*jsdisp
)
939 ULONG ref
= ++jsdisp
->ref
;
940 TRACE("(%p) ref=%d\n", jsdisp
, ref
);
944 void jsdisp_release(jsdisp_t
*jsdisp
)
946 ULONG ref
= --jsdisp
->ref
;
948 TRACE("(%p) ref=%d\n", jsdisp
, ref
);
956 HRESULT
init_dispex_from_constr(jsdisp_t
*dispex
, script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*constr
)
958 jsdisp_t
*prot
= NULL
;
962 static const WCHAR prototypeW
[] = {'p','r','o','t','o','t','y','p','e',0};
964 hres
= find_prop_name_prot(constr
, string_hash(prototypeW
), prototypeW
, &prop
);
965 if(SUCCEEDED(hres
) && prop
&& prop
->type
!=PROP_DELETED
) {
968 hres
= prop_get(constr
, prop
, NULL
, &val
, NULL
);
970 ERR("Could not get prototype\n");
974 if(is_object_instance(val
))
975 prot
= iface_to_jsdisp((IUnknown
*)get_object(val
));
979 hres
= init_dispex(dispex
, ctx
, builtin_info
, prot
);
982 jsdisp_release(prot
);
986 jsdisp_t
*iface_to_jsdisp(IUnknown
*iface
)
991 hres
= IUnknown_QueryInterface(iface
, &IID_IDispatchJS
, (void**)&ret
);
998 HRESULT
jsdisp_get_id(jsdisp_t
*jsdisp
, const WCHAR
*name
, DWORD flags
, DISPID
*id
)
1000 dispex_prop_t
*prop
;
1003 if(flags
& fdexNameEnsure
)
1004 hres
= ensure_prop_name(jsdisp
, name
, TRUE
, PROPF_ENUM
, &prop
);
1006 hres
= find_prop_name_prot(jsdisp
, string_hash(name
), name
, &prop
);
1010 if(prop
&& prop
->type
!=PROP_DELETED
) {
1011 *id
= prop_to_id(jsdisp
, prop
);
1015 TRACE("not found %s\n", debugstr_w(name
));
1016 return DISP_E_UNKNOWNNAME
;
1019 HRESULT
jsdisp_call_value(jsdisp_t
*jsfunc
, IDispatch
*jsthis
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1023 if(is_class(jsfunc
, JSCLASS_FUNCTION
)) {
1024 hres
= Function_invoke(jsfunc
, jsthis
, flags
, argc
, argv
, r
);
1028 set_disp(&vdisp
, jsthis
);
1029 hres
= jsfunc
->builtin_info
->value_prop
.invoke(jsfunc
->ctx
, &vdisp
, flags
, argc
, argv
, r
);
1030 vdisp_release(&vdisp
);
1035 HRESULT
jsdisp_call(jsdisp_t
*disp
, DISPID id
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1037 dispex_prop_t
*prop
;
1039 prop
= get_prop(disp
, id
);
1041 return DISP_E_MEMBERNOTFOUND
;
1043 return invoke_prop_func(disp
, to_disp(disp
), prop
, flags
, argc
, argv
, r
, NULL
);
1046 HRESULT
jsdisp_call_name(jsdisp_t
*disp
, const WCHAR
*name
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1048 dispex_prop_t
*prop
;
1051 hres
= find_prop_name_prot(disp
, string_hash(name
), name
, &prop
);
1055 return invoke_prop_func(disp
, to_disp(disp
), prop
, flags
, argc
, argv
, r
, NULL
);
1058 HRESULT
disp_call(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*ret
)
1060 IDispatchEx
*dispex
;
1062 VARIANT buf
[6], retv
;
1067 jsdisp
= iface_to_jsdisp((IUnknown
*)disp
);
1069 if(flags
& DISPATCH_PROPERTYPUT
) {
1070 FIXME("disp_call(propput) on builtin object\n");
1074 hres
= jsdisp_call(jsdisp
, id
, flags
, argc
, argv
, ret
);
1075 jsdisp_release(jsdisp
);
1080 flags
|= DISPATCH_PROPERTYGET
;
1084 if(flags
& DISPATCH_PROPERTYPUT
) {
1085 static DISPID propput_dispid
= DISPID_PROPERTYPUT
;
1088 dp
.rgdispidNamedArgs
= &propput_dispid
;
1091 dp
.rgdispidNamedArgs
= NULL
;
1095 dp
.rgvarg
= heap_alloc(argc
*sizeof(VARIANT
));
1097 return E_OUTOFMEMORY
;
1102 for(i
=0; i
<argc
; i
++) {
1103 hres
= jsval_to_variant(argv
[i
], dp
.rgvarg
+argc
-i
-1);
1106 VariantClear(dp
.rgvarg
+argc
-i
-1);
1107 if(dp
.rgvarg
!= buf
)
1108 heap_free(dp
.rgvarg
);
1113 V_VT(&retv
) = VT_EMPTY
;
1115 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
1116 if(SUCCEEDED(hres
)) {
1117 hres
= IDispatchEx_InvokeEx(dispex
, id
, ctx
->lcid
, flags
, &dp
, ret
? &retv
: NULL
, &ctx
->ei
.ei
,
1118 &ctx
->jscaller
->IServiceProvider_iface
);
1119 IDispatchEx_Release(dispex
);
1123 if(flags
== DISPATCH_CONSTRUCT
) {
1124 WARN("IDispatch cannot be constructor\n");
1125 return DISP_E_MEMBERNOTFOUND
;
1128 TRACE("using IDispatch\n");
1129 hres
= IDispatch_Invoke(disp
, id
, &IID_NULL
, ctx
->lcid
, flags
, &dp
, ret
? &retv
: NULL
, &ctx
->ei
.ei
, &err
);
1132 for(i
=0; i
<argc
; i
++)
1133 VariantClear(dp
.rgvarg
+argc
-i
-1);
1134 if(dp
.rgvarg
!= buf
)
1135 heap_free(dp
.rgvarg
);
1140 hres
= variant_to_jsval(&retv
, ret
);
1141 VariantClear(&retv
);
1146 HRESULT
disp_call_value(script_ctx_t
*ctx
, IDispatch
*disp
, IDispatch
*jsthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1150 IDispatchEx
*dispex
;
1151 VARIANT buf
[6], retv
;
1156 jsdisp
= iface_to_jsdisp((IUnknown
*)disp
);
1158 if(flags
& DISPATCH_PROPERTYPUT
) {
1159 FIXME("disp_call(propput) on builtin object\n");
1163 hres
= jsdisp_call_value(jsdisp
, jsthis
, flags
, argc
, argv
, r
);
1164 jsdisp_release(jsdisp
);
1169 flags
|= DISPATCH_PROPERTYGET
;
1173 static DISPID this_id
= DISPID_THIS
;
1177 dp
.rgdispidNamedArgs
= &this_id
;
1181 dp
.rgdispidNamedArgs
= NULL
;
1184 if(dp
.cArgs
> sizeof(buf
)/sizeof(*buf
)) {
1185 dp
.rgvarg
= heap_alloc(dp
.cArgs
*sizeof(VARIANT
));
1187 return E_OUTOFMEMORY
;
1192 for(i
=0; i
<argc
; i
++) {
1193 hres
= jsval_to_variant(argv
[i
], dp
.rgvarg
+dp
.cArgs
-i
-1);
1196 VariantClear(dp
.rgvarg
+dp
.cArgs
-i
-1);
1197 if(dp
.rgvarg
!= buf
)
1198 heap_free(dp
.rgvarg
);
1203 V_VT(dp
.rgvarg
) = VT_DISPATCH
;
1204 V_DISPATCH(dp
.rgvarg
) = jsthis
;
1207 V_VT(&retv
) = VT_EMPTY
;
1209 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
1210 if(SUCCEEDED(hres
)) {
1211 hres
= IDispatchEx_InvokeEx(dispex
, DISPID_VALUE
, ctx
->lcid
, flags
, &dp
, r
? &retv
: NULL
, &ctx
->ei
.ei
,
1212 &ctx
->jscaller
->IServiceProvider_iface
);
1213 IDispatchEx_Release(dispex
);
1217 if(flags
== DISPATCH_CONSTRUCT
) {
1218 WARN("IDispatch cannot be constructor\n");
1219 return DISP_E_MEMBERNOTFOUND
;
1222 TRACE("using IDispatch\n");
1223 hres
= IDispatch_Invoke(disp
, DISPID_VALUE
, &IID_NULL
, ctx
->lcid
, flags
, &dp
, r
? &retv
: NULL
, &ctx
->ei
.ei
, &err
);
1226 for(i
=0; i
<argc
; i
++)
1227 VariantClear(dp
.rgvarg
+dp
.cArgs
-i
-1);
1228 if(dp
.rgvarg
!= buf
)
1229 heap_free(dp
.rgvarg
);
1236 hres
= variant_to_jsval(&retv
, r
);
1237 VariantClear(&retv
);
1241 HRESULT
jsdisp_propput_name(jsdisp_t
*obj
, const WCHAR
*name
, jsval_t val
)
1243 dispex_prop_t
*prop
;
1246 hres
= ensure_prop_name(obj
, name
, FALSE
, PROPF_ENUM
, &prop
);
1250 return prop_put(obj
, prop
, val
, NULL
);
1253 HRESULT
jsdisp_propput_const(jsdisp_t
*obj
, const WCHAR
*name
, jsval_t val
)
1255 dispex_prop_t
*prop
;
1258 hres
= ensure_prop_name(obj
, name
, FALSE
, PROPF_ENUM
|PROPF_CONST
, &prop
);
1262 return jsval_copy(val
, &prop
->u
.val
);
1265 HRESULT
jsdisp_propput_dontenum(jsdisp_t
*obj
, const WCHAR
*name
, jsval_t val
)
1267 dispex_prop_t
*prop
;
1270 hres
= ensure_prop_name(obj
, name
, FALSE
, 0, &prop
);
1274 return jsval_copy(val
, &prop
->u
.val
);
1277 HRESULT
jsdisp_propput_idx(jsdisp_t
*obj
, DWORD idx
, jsval_t val
)
1281 static const WCHAR formatW
[] = {'%','d',0};
1283 sprintfW(buf
, formatW
, idx
);
1284 return jsdisp_propput_name(obj
, buf
, val
);
1287 HRESULT
disp_propput(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, jsval_t val
)
1292 jsdisp
= iface_to_jsdisp((IUnknown
*)disp
);
1294 dispex_prop_t
*prop
;
1296 prop
= get_prop(jsdisp
, id
);
1298 hres
= prop_put(jsdisp
, prop
, val
, NULL
);
1300 hres
= DISP_E_MEMBERNOTFOUND
;
1302 jsdisp_release(jsdisp
);
1304 DISPID dispid
= DISPID_PROPERTYPUT
;
1306 DISPPARAMS dp
= {&var
, &dispid
, 1, 1};
1307 IDispatchEx
*dispex
;
1309 hres
= jsval_to_variant(val
, &var
);
1314 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
1315 if(SUCCEEDED(hres
)) {
1316 hres
= IDispatchEx_InvokeEx(dispex
, id
, ctx
->lcid
, DISPATCH_PROPERTYPUT
, &dp
, NULL
, &ctx
->ei
.ei
,
1317 &ctx
->jscaller
->IServiceProvider_iface
);
1318 IDispatchEx_Release(dispex
);
1322 TRACE("using IDispatch\n");
1323 hres
= IDispatch_Invoke(disp
, id
, &IID_NULL
, ctx
->lcid
, DISPATCH_PROPERTYPUT
, &dp
, NULL
, &ctx
->ei
.ei
, &err
);
1332 HRESULT
jsdisp_propget_name(jsdisp_t
*obj
, const WCHAR
*name
, jsval_t
*val
)
1334 DISPPARAMS dp
= {NULL
, NULL
, 0, 0};
1335 dispex_prop_t
*prop
;
1338 hres
= find_prop_name_prot(obj
, string_hash(name
), name
, &prop
);
1342 if(!prop
|| prop
->type
==PROP_DELETED
) {
1343 *val
= jsval_undefined();
1347 return prop_get(obj
, prop
, &dp
, val
, NULL
);
1350 HRESULT
jsdisp_get_idx(jsdisp_t
*obj
, DWORD idx
, jsval_t
*r
)
1353 DISPPARAMS dp
= {NULL
, NULL
, 0, 0};
1354 dispex_prop_t
*prop
;
1357 static const WCHAR formatW
[] = {'%','d',0};
1359 sprintfW(name
, formatW
, idx
);
1361 hres
= find_prop_name_prot(obj
, string_hash(name
), name
, &prop
);
1365 if(!prop
|| prop
->type
==PROP_DELETED
) {
1366 *r
= jsval_undefined();
1367 return DISP_E_UNKNOWNNAME
;
1370 return prop_get(obj
, prop
, &dp
, r
, NULL
);
1373 HRESULT
jsdisp_propget(jsdisp_t
*jsdisp
, DISPID id
, jsval_t
*val
)
1375 DISPPARAMS dp
= {NULL
,NULL
,0,0};
1376 dispex_prop_t
*prop
;
1378 prop
= get_prop(jsdisp
, id
);
1380 return DISP_E_MEMBERNOTFOUND
;
1382 return prop_get(jsdisp
, prop
, &dp
, val
, NULL
);
1385 HRESULT
disp_propget(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, jsval_t
*val
)
1387 DISPPARAMS dp
= {NULL
,NULL
,0,0};
1388 IDispatchEx
*dispex
;
1393 jsdisp
= iface_to_jsdisp((IUnknown
*)disp
);
1395 hres
= jsdisp_propget(jsdisp
, id
, val
);
1396 jsdisp_release(jsdisp
);
1400 V_VT(&var
) = VT_EMPTY
;
1402 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
1403 if(SUCCEEDED(hres
)) {
1404 hres
= IDispatchEx_InvokeEx(dispex
, id
, ctx
->lcid
, INVOKE_PROPERTYGET
, &dp
, &var
, &ctx
->ei
.ei
,
1405 &ctx
->jscaller
->IServiceProvider_iface
);
1406 IDispatchEx_Release(dispex
);
1410 TRACE("using IDispatch\n");
1411 hres
= IDispatch_Invoke(disp
, id
, &IID_NULL
, ctx
->lcid
, INVOKE_PROPERTYGET
, &dp
, &var
, &ctx
->ei
.ei
, &err
);
1416 return variant_to_jsval(&var
, val
);
1419 HRESULT
jsdisp_delete_idx(jsdisp_t
*obj
, DWORD idx
)
1421 static const WCHAR formatW
[] = {'%','d',0};
1423 dispex_prop_t
*prop
;
1426 sprintfW(buf
, formatW
, idx
);
1428 hres
= find_prop_name(obj
, string_hash(buf
), buf
, &prop
);
1429 if(FAILED(hres
) || !prop
)
1432 return delete_prop(prop
);
1435 HRESULT
jsdisp_is_own_prop(jsdisp_t
*obj
, const WCHAR
*name
, BOOL
*ret
)
1437 dispex_prop_t
*prop
;
1440 hres
= find_prop_name(obj
, string_hash(name
), name
, &prop
);
1444 *ret
= prop
&& (prop
->type
== PROP_JSVAL
|| prop
->type
== PROP_BUILTIN
);