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
21 #include "wine/unicode.h"
22 #include "wine/debug.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(jscript
);
27 * This IID is used to get jsdisp_t objecto from interface.
28 * We might consider using private insteface instead.
30 static const IID IID_IDispatchJS
=
31 {0x719c3050,0xf9d3,0x11cf,{0xa4,0x93,0x00,0x40,0x05,0x23,0xa8,0xa6}};
33 #define FDEX_VERSION_MASK 0xf0000000
42 struct _dispex_prop_t
{
49 const builtin_prop_t
*p
;
54 static inline DISPID
prop_to_id(jsdisp_t
*This
, dispex_prop_t
*prop
)
56 return prop
- This
->props
;
59 static inline dispex_prop_t
*get_prop(jsdisp_t
*This
, DISPID id
)
61 if(id
< 0 || id
>= This
->prop_cnt
|| This
->props
[id
].type
== PROP_DELETED
)
64 return This
->props
+id
;
67 static DWORD
get_flags(jsdisp_t
*This
, dispex_prop_t
*prop
)
69 if(prop
->type
== PROP_PROTREF
) {
70 dispex_prop_t
*parent
= get_prop(This
->prototype
, prop
->u
.ref
);
72 prop
->type
= PROP_DELETED
;
76 return get_flags(This
->prototype
, parent
);
82 static const builtin_prop_t
*find_builtin_prop(jsdisp_t
*This
, const WCHAR
*name
)
84 int min
= 0, max
, i
, r
;
86 max
= This
->builtin_info
->props_cnt
-1;
90 r
= strcmpW(name
, This
->builtin_info
->props
[i
].name
);
92 return This
->builtin_info
->props
+ i
;
103 static dispex_prop_t
*alloc_prop(jsdisp_t
*This
, const WCHAR
*name
, prop_type_t type
, DWORD flags
)
107 if(This
->buf_size
== This
->prop_cnt
) {
108 dispex_prop_t
*tmp
= heap_realloc(This
->props
, (This
->buf_size
<<=1)*sizeof(*This
->props
));
114 ret
= This
->props
+ This
->prop_cnt
++;
117 ret
->name
= heap_strdupW(name
);
124 static dispex_prop_t
*alloc_protref(jsdisp_t
*This
, const WCHAR
*name
, DWORD ref
)
128 ret
= alloc_prop(This
, name
, PROP_PROTREF
, 0);
136 static HRESULT
find_prop_name(jsdisp_t
*This
, const WCHAR
*name
, dispex_prop_t
**ret
)
138 const builtin_prop_t
*builtin
;
141 for(prop
= This
->props
; prop
< This
->props
+This
->prop_cnt
; prop
++) {
142 if(prop
->name
&& !strcmpW(prop
->name
, name
)) {
148 builtin
= find_builtin_prop(This
, name
);
150 prop
= alloc_prop(This
, name
, PROP_BUILTIN
, builtin
->flags
);
152 return E_OUTOFMEMORY
;
163 static HRESULT
find_prop_name_prot(jsdisp_t
*This
, const WCHAR
*name
, dispex_prop_t
**ret
)
168 hres
= find_prop_name(This
, name
, &prop
);
176 if(This
->prototype
) {
177 hres
= find_prop_name_prot(This
->prototype
, name
, &prop
);
181 prop
= alloc_protref(This
, prop
->name
, prop
- This
->prototype
->props
);
183 return E_OUTOFMEMORY
;
193 static HRESULT
ensure_prop_name(jsdisp_t
*This
, const WCHAR
*name
, BOOL search_prot
, DWORD create_flags
, dispex_prop_t
**ret
)
199 hres
= find_prop_name_prot(This
, name
, &prop
);
201 hres
= find_prop_name(This
, name
, &prop
);
202 if(SUCCEEDED(hres
) && !prop
) {
203 TRACE("creating prop %s\n", debugstr_w(name
));
205 prop
= alloc_prop(This
, name
, PROP_VARIANT
, create_flags
);
207 return E_OUTOFMEMORY
;
208 VariantInit(&prop
->u
.var
);
215 static HRESULT
set_this(DISPPARAMS
*dp
, DISPPARAMS
*olddp
, IDispatch
*jsthis
)
220 static DISPID this_id
= DISPID_THIS
;
224 for(i
= 0; i
< dp
->cNamedArgs
; i
++) {
225 if(dp
->rgdispidNamedArgs
[i
] == DISPID_THIS
)
229 oldargs
= dp
->rgvarg
;
230 dp
->rgvarg
= heap_alloc((dp
->cArgs
+1) * sizeof(VARIANTARG
));
232 return E_OUTOFMEMORY
;
233 memcpy(dp
->rgvarg
+1, oldargs
, dp
->cArgs
*sizeof(VARIANTARG
));
234 V_VT(dp
->rgvarg
) = VT_DISPATCH
;
235 V_DISPATCH(dp
->rgvarg
) = jsthis
;
239 DISPID
*old
= dp
->rgdispidNamedArgs
;
240 dp
->rgdispidNamedArgs
= heap_alloc((dp
->cNamedArgs
+1)*sizeof(DISPID
));
241 if(!dp
->rgdispidNamedArgs
) {
242 heap_free(dp
->rgvarg
);
243 return E_OUTOFMEMORY
;
246 memcpy(dp
->rgdispidNamedArgs
+1, old
, dp
->cNamedArgs
*sizeof(DISPID
));
247 dp
->rgdispidNamedArgs
[0] = DISPID_THIS
;
250 dp
->rgdispidNamedArgs
= &this_id
;
257 static HRESULT
invoke_prop_func(jsdisp_t
*This
, jsdisp_t
*jsthis
, dispex_prop_t
*prop
, WORD flags
,
258 DISPPARAMS
*dp
, VARIANT
*retv
, jsexcept_t
*ei
, IServiceProvider
*caller
)
266 if(flags
== DISPATCH_CONSTRUCT
&& (prop
->flags
& PROPF_METHOD
)) {
267 WARN("%s is not a constructor\n", debugstr_w(prop
->name
));
271 set_jsdisp(&vthis
, jsthis
);
272 hres
= prop
->u
.p
->invoke(This
->ctx
, &vthis
, flags
, dp
, retv
, ei
, caller
);
273 vdisp_release(&vthis
);
277 return invoke_prop_func(This
->prototype
, jsthis
, This
->prototype
->props
+prop
->u
.ref
, flags
, dp
, retv
, ei
, caller
);
281 if(V_VT(&prop
->u
.var
) != VT_DISPATCH
) {
282 FIXME("invoke vt %d\n", V_VT(&prop
->u
.var
));
286 TRACE("call %s %p\n", debugstr_w(prop
->name
), V_DISPATCH(&prop
->u
.var
));
288 hres
= set_this(&new_dp
, dp
, to_disp(jsthis
));
292 hres
= disp_call(This
->ctx
, V_DISPATCH(&prop
->u
.var
), DISPID_VALUE
, flags
, &new_dp
, retv
, ei
, caller
);
294 if(new_dp
.rgvarg
!= dp
->rgvarg
) {
295 heap_free(new_dp
.rgvarg
);
296 if(new_dp
.cNamedArgs
> 1)
297 heap_free(new_dp
.rgdispidNamedArgs
);
303 ERR("type %d\n", prop
->type
);
309 static HRESULT
prop_get(jsdisp_t
*This
, dispex_prop_t
*prop
, DISPPARAMS
*dp
,
310 VARIANT
*retv
, jsexcept_t
*ei
, IServiceProvider
*caller
)
316 if(prop
->u
.p
->flags
& PROPF_METHOD
) {
318 hres
= create_builtin_function(This
->ctx
, prop
->u
.p
->invoke
, prop
->u
.p
->name
, NULL
,
319 prop
->u
.p
->flags
, NULL
, &obj
);
323 prop
->type
= PROP_VARIANT
;
324 var_set_jsdisp(&prop
->u
.var
, obj
);
325 hres
= VariantCopy(retv
, &prop
->u
.var
);
329 set_jsdisp(&vthis
, This
);
330 hres
= prop
->u
.p
->invoke(This
->ctx
, &vthis
, DISPATCH_PROPERTYGET
, dp
, retv
, ei
, caller
);
331 vdisp_release(&vthis
);
335 hres
= prop_get(This
->prototype
, This
->prototype
->props
+prop
->u
.ref
, dp
, retv
, ei
, caller
);
338 hres
= VariantCopy(retv
, &prop
->u
.var
);
341 ERR("type %d\n", prop
->type
);
346 TRACE("fail %08x\n", hres
);
350 TRACE("%s ret %s\n", debugstr_w(prop
->name
), debugstr_variant(retv
));
354 static HRESULT
prop_put(jsdisp_t
*This
, dispex_prop_t
*prop
, VARIANT
*val
,
355 jsexcept_t
*ei
, IServiceProvider
*caller
)
359 if(prop
->flags
& PROPF_CONST
)
364 if(!(prop
->flags
& PROPF_METHOD
)) {
365 DISPPARAMS dp
= {val
, NULL
, 1, 0};
368 set_jsdisp(&vthis
, This
);
369 hres
= prop
->u
.p
->invoke(This
->ctx
, &vthis
, DISPATCH_PROPERTYPUT
, &dp
, NULL
, ei
, caller
);
370 vdisp_release(&vthis
);
374 prop
->type
= PROP_VARIANT
;
375 prop
->flags
= PROPF_ENUM
;
376 V_VT(&prop
->u
.var
) = VT_EMPTY
;
379 VariantClear(&prop
->u
.var
);
382 ERR("type %d\n", prop
->type
);
386 hres
= VariantCopy(&prop
->u
.var
, val
);
390 if(This
->builtin_info
->on_put
)
391 This
->builtin_info
->on_put(This
, prop
->name
);
393 TRACE("%s = %s\n", debugstr_w(prop
->name
), debugstr_variant(val
));
397 static HRESULT
fill_protrefs(jsdisp_t
*This
)
399 dispex_prop_t
*iter
, *prop
;
405 fill_protrefs(This
->prototype
);
407 for(iter
= This
->prototype
->props
; iter
< This
->prototype
->props
+This
->prototype
->prop_cnt
; iter
++) {
410 hres
= find_prop_name(This
, iter
->name
, &prop
);
414 prop
= alloc_protref(This
, iter
->name
, iter
- This
->prototype
->props
);
416 return E_OUTOFMEMORY
;
423 #define DISPATCHEX_THIS(iface) DEFINE_THIS(jsdisp_t, IDispatchEx, iface)
425 static HRESULT WINAPI
DispatchEx_QueryInterface(IDispatchEx
*iface
, REFIID riid
, void **ppv
)
427 jsdisp_t
*This
= DISPATCHEX_THIS(iface
);
429 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
430 TRACE("(%p)->(IID_IUnknown %p)\n", This
, ppv
);
431 *ppv
= _IDispatchEx_(This
);
432 }else if(IsEqualGUID(&IID_IDispatch
, riid
)) {
433 TRACE("(%p)->(IID_IDispatch %p)\n", This
, ppv
);
434 *ppv
= _IDispatchEx_(This
);
435 }else if(IsEqualGUID(&IID_IDispatchEx
, riid
)) {
436 TRACE("(%p)->(IID_IDispatchEx %p)\n", This
, ppv
);
437 *ppv
= _IDispatchEx_(This
);
438 }else if(IsEqualGUID(&IID_IDispatchJS
, riid
)) {
439 TRACE("(%p)->(IID_IDispatchJS %p)\n", This
, ppv
);
444 WARN("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
446 return E_NOINTERFACE
;
449 IUnknown_AddRef((IUnknown
*)*ppv
);
453 static ULONG WINAPI
DispatchEx_AddRef(IDispatchEx
*iface
)
455 jsdisp_t
*This
= DISPATCHEX_THIS(iface
);
456 LONG ref
= InterlockedIncrement(&This
->ref
);
458 TRACE("(%p) ref=%d\n", This
, ref
);
463 static ULONG WINAPI
DispatchEx_Release(IDispatchEx
*iface
)
465 jsdisp_t
*This
= DISPATCHEX_THIS(iface
);
466 LONG ref
= InterlockedDecrement(&This
->ref
);
468 TRACE("(%p) ref=%d\n", This
, ref
);
473 for(prop
= This
->props
; prop
< This
->props
+This
->prop_cnt
; prop
++) {
474 if(prop
->type
== PROP_VARIANT
)
475 VariantClear(&prop
->u
.var
);
476 heap_free(prop
->name
);
478 heap_free(This
->props
);
479 script_release(This
->ctx
);
481 jsdisp_release(This
->prototype
);
483 if(This
->builtin_info
->destructor
)
484 This
->builtin_info
->destructor(This
);
492 static HRESULT WINAPI
DispatchEx_GetTypeInfoCount(IDispatchEx
*iface
, UINT
*pctinfo
)
494 jsdisp_t
*This
= DISPATCHEX_THIS(iface
);
496 TRACE("(%p)->(%p)\n", This
, pctinfo
);
502 static HRESULT WINAPI
DispatchEx_GetTypeInfo(IDispatchEx
*iface
, UINT iTInfo
, LCID lcid
,
505 jsdisp_t
*This
= DISPATCHEX_THIS(iface
);
506 FIXME("(%p)->(%u %u %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
510 static HRESULT WINAPI
DispatchEx_GetIDsOfNames(IDispatchEx
*iface
, REFIID riid
,
511 LPOLESTR
*rgszNames
, UINT cNames
, LCID lcid
,
514 jsdisp_t
*This
= DISPATCHEX_THIS(iface
);
518 TRACE("(%p)->(%s %p %u %u %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
,
521 for(i
=0; i
< cNames
; i
++) {
522 hres
= IDispatchEx_GetDispID(_IDispatchEx_(This
), rgszNames
[i
], 0, rgDispId
+i
);
530 static HRESULT WINAPI
DispatchEx_Invoke(IDispatchEx
*iface
, DISPID dispIdMember
,
531 REFIID riid
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
,
532 VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
534 jsdisp_t
*This
= DISPATCHEX_THIS(iface
);
536 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This
, dispIdMember
, debugstr_guid(riid
),
537 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
539 return IDispatchEx_InvokeEx(_IDispatchEx_(This
), dispIdMember
, lcid
, wFlags
,
540 pDispParams
, pVarResult
, pExcepInfo
, NULL
);
543 static HRESULT WINAPI
DispatchEx_GetDispID(IDispatchEx
*iface
, BSTR bstrName
, DWORD grfdex
, DISPID
*pid
)
545 jsdisp_t
*This
= DISPATCHEX_THIS(iface
);
547 TRACE("(%p)->(%s %x %p)\n", This
, debugstr_w(bstrName
), grfdex
, pid
);
549 if(grfdex
& ~(fdexNameCaseSensitive
|fdexNameEnsure
|fdexNameImplicit
|FDEX_VERSION_MASK
)) {
550 FIXME("Unsupported grfdex %x\n", grfdex
);
554 return jsdisp_get_id(This
, bstrName
, grfdex
, pid
);
557 static HRESULT WINAPI
DispatchEx_InvokeEx(IDispatchEx
*iface
, DISPID id
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pdp
,
558 VARIANT
*pvarRes
, EXCEPINFO
*pei
, IServiceProvider
*pspCaller
)
560 jsdisp_t
*This
= DISPATCHEX_THIS(iface
);
565 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This
, id
, lcid
, wFlags
, pdp
, pvarRes
, pei
, pspCaller
);
568 V_VT(pvarRes
) = VT_EMPTY
;
570 prop
= get_prop(This
, id
);
571 if(!prop
|| prop
->type
== PROP_DELETED
) {
572 TRACE("invalid id\n");
573 return DISP_E_MEMBERNOTFOUND
;
576 memset(&jsexcept
, 0, sizeof(jsexcept
));
579 case DISPATCH_METHOD
|DISPATCH_PROPERTYGET
:
580 wFlags
= DISPATCH_METHOD
;
581 case DISPATCH_METHOD
:
582 case DISPATCH_CONSTRUCT
:
583 hres
= invoke_prop_func(This
, This
, prop
, wFlags
, pdp
, pvarRes
, &jsexcept
, pspCaller
);
585 case DISPATCH_PROPERTYGET
:
586 hres
= prop_get(This
, prop
, pdp
, pvarRes
, &jsexcept
, pspCaller
);
588 case DISPATCH_PROPERTYPUT
: {
591 for(i
=0; i
< pdp
->cNamedArgs
; i
++) {
592 if(pdp
->rgdispidNamedArgs
[i
] == DISPID_PROPERTYPUT
)
596 if(i
== pdp
->cNamedArgs
) {
597 TRACE("no value to set\n");
598 return DISP_E_PARAMNOTOPTIONAL
;
601 hres
= prop_put(This
, prop
, pdp
->rgvarg
+i
, &jsexcept
, pspCaller
);
605 FIXME("Unimplemented flags %x\n", wFlags
);
615 static HRESULT
delete_prop(dispex_prop_t
*prop
)
617 heap_free(prop
->name
);
619 prop
->type
= PROP_DELETED
;
624 static HRESULT WINAPI
DispatchEx_DeleteMemberByName(IDispatchEx
*iface
, BSTR bstrName
, DWORD grfdex
)
626 jsdisp_t
*This
= DISPATCHEX_THIS(iface
);
630 TRACE("(%p)->(%s %x)\n", This
, debugstr_w(bstrName
), grfdex
);
632 if(grfdex
& ~(fdexNameCaseSensitive
|fdexNameEnsure
|fdexNameImplicit
|FDEX_VERSION_MASK
))
633 FIXME("Unsupported grfdex %x\n", grfdex
);
635 hres
= find_prop_name(This
, bstrName
, &prop
);
639 TRACE("not found\n");
643 return delete_prop(prop
);
646 static HRESULT WINAPI
DispatchEx_DeleteMemberByDispID(IDispatchEx
*iface
, DISPID id
)
648 jsdisp_t
*This
= DISPATCHEX_THIS(iface
);
651 TRACE("(%p)->(%x)\n", This
, id
);
653 prop
= get_prop(This
, id
);
655 WARN("invalid id\n");
656 return DISP_E_MEMBERNOTFOUND
;
659 return delete_prop(prop
);
662 static HRESULT WINAPI
DispatchEx_GetMemberProperties(IDispatchEx
*iface
, DISPID id
, DWORD grfdexFetch
, DWORD
*pgrfdex
)
664 jsdisp_t
*This
= DISPATCHEX_THIS(iface
);
665 FIXME("(%p)->(%x %x %p)\n", This
, id
, grfdexFetch
, pgrfdex
);
669 static HRESULT WINAPI
DispatchEx_GetMemberName(IDispatchEx
*iface
, DISPID id
, BSTR
*pbstrName
)
671 jsdisp_t
*This
= DISPATCHEX_THIS(iface
);
674 TRACE("(%p)->(%x %p)\n", This
, id
, pbstrName
);
676 prop
= get_prop(This
, id
);
677 if(!prop
|| !prop
->name
|| prop
->type
== PROP_DELETED
)
678 return DISP_E_MEMBERNOTFOUND
;
680 *pbstrName
= SysAllocString(prop
->name
);
682 return E_OUTOFMEMORY
;
687 static HRESULT WINAPI
DispatchEx_GetNextDispID(IDispatchEx
*iface
, DWORD grfdex
, DISPID id
, DISPID
*pid
)
689 jsdisp_t
*This
= DISPATCHEX_THIS(iface
);
693 TRACE("(%p)->(%x %x %p)\n", This
, grfdex
, id
, pid
);
695 if(id
== DISPID_STARTENUM
) {
696 hres
= fill_protrefs(This
);
701 iter
= get_prop(This
, id
+1);
703 *pid
= DISPID_STARTENUM
;
707 while(iter
< This
->props
+ This
->prop_cnt
) {
708 if(iter
->name
&& (get_flags(This
, iter
) & PROPF_ENUM
)) {
709 *pid
= prop_to_id(This
, iter
);
715 *pid
= DISPID_STARTENUM
;
719 static HRESULT WINAPI
DispatchEx_GetNameSpaceParent(IDispatchEx
*iface
, IUnknown
**ppunk
)
721 jsdisp_t
*This
= DISPATCHEX_THIS(iface
);
722 FIXME("(%p)->(%p)\n", This
, ppunk
);
726 #undef DISPATCHEX_THIS
728 static IDispatchExVtbl DispatchExVtbl
= {
729 DispatchEx_QueryInterface
,
732 DispatchEx_GetTypeInfoCount
,
733 DispatchEx_GetTypeInfo
,
734 DispatchEx_GetIDsOfNames
,
736 DispatchEx_GetDispID
,
738 DispatchEx_DeleteMemberByName
,
739 DispatchEx_DeleteMemberByDispID
,
740 DispatchEx_GetMemberProperties
,
741 DispatchEx_GetMemberName
,
742 DispatchEx_GetNextDispID
,
743 DispatchEx_GetNameSpaceParent
746 HRESULT
init_dispex(jsdisp_t
*dispex
, script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*prototype
)
748 TRACE("%p (%p)\n", dispex
, prototype
);
750 dispex
->lpIDispatchExVtbl
= &DispatchExVtbl
;
752 dispex
->builtin_info
= builtin_info
;
754 dispex
->props
= heap_alloc((dispex
->buf_size
=4) * sizeof(dispex_prop_t
));
756 return E_OUTOFMEMORY
;
758 dispex
->prototype
= prototype
;
760 jsdisp_addref(prototype
);
762 dispex
->prop_cnt
= 1;
763 dispex
->props
[0].name
= NULL
;
764 dispex
->props
[0].flags
= 0;
765 if(builtin_info
->value_prop
.invoke
) {
766 dispex
->props
[0].type
= PROP_BUILTIN
;
767 dispex
->props
[0].u
.p
= &builtin_info
->value_prop
;
769 dispex
->props
[0].type
= PROP_DELETED
;
778 static const builtin_info_t dispex_info
= {
786 HRESULT
create_dispex(script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*prototype
, jsdisp_t
**dispex
)
791 ret
= heap_alloc_zero(sizeof(jsdisp_t
));
793 return E_OUTOFMEMORY
;
795 hres
= init_dispex(ret
, ctx
, builtin_info
? builtin_info
: &dispex_info
, prototype
);
803 HRESULT
init_dispex_from_constr(jsdisp_t
*dispex
, script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*constr
)
805 jsdisp_t
*prot
= NULL
;
809 static const WCHAR constructorW
[] = {'c','o','n','s','t','r','u','c','t','o','r',0};
810 static const WCHAR prototypeW
[] = {'p','r','o','t','o','t','y','p','e',0};
812 hres
= find_prop_name_prot(constr
, prototypeW
, &prop
);
813 if(SUCCEEDED(hres
) && prop
) {
817 V_VT(&var
) = VT_EMPTY
;
818 memset(&jsexcept
, 0, sizeof(jsexcept
));
819 hres
= prop_get(constr
, prop
, NULL
, &var
, &jsexcept
, NULL
/*FIXME*/);
821 ERR("Could not get prototype\n");
825 if(V_VT(&var
) == VT_DISPATCH
)
826 prot
= iface_to_jsdisp((IUnknown
*)V_DISPATCH(&var
));
830 hres
= init_dispex(dispex
, ctx
, builtin_info
, prot
);
833 jsdisp_release(prot
);
837 hres
= ensure_prop_name(dispex
, constructorW
, FALSE
, 0, &prop
);
838 if(SUCCEEDED(hres
)) {
842 var_set_jsdisp(&var
, constr
);
843 memset(&jsexcept
, 0, sizeof(jsexcept
));
844 hres
= prop_put(dispex
, prop
, &var
, &jsexcept
, NULL
/*FIXME*/);
847 jsdisp_release(dispex
);
852 jsdisp_t
*iface_to_jsdisp(IUnknown
*iface
)
857 hres
= IUnknown_QueryInterface(iface
, &IID_IDispatchJS
, (void**)&ret
);
864 HRESULT
jsdisp_get_id(jsdisp_t
*jsdisp
, const WCHAR
*name
, DWORD flags
, DISPID
*id
)
869 if(flags
& fdexNameEnsure
)
870 hres
= ensure_prop_name(jsdisp
, name
, TRUE
, PROPF_ENUM
, &prop
);
872 hres
= find_prop_name_prot(jsdisp
, name
, &prop
);
877 *id
= prop_to_id(jsdisp
, prop
);
881 TRACE("not found %s\n", debugstr_w(name
));
882 return DISP_E_UNKNOWNNAME
;
885 HRESULT
jsdisp_call_value(jsdisp_t
*jsthis
, WORD flags
, DISPPARAMS
*dp
, VARIANT
*retv
,
886 jsexcept_t
*ei
, IServiceProvider
*caller
)
891 set_jsdisp(&vdisp
, jsthis
);
892 hres
= jsthis
->builtin_info
->value_prop
.invoke(jsthis
->ctx
, &vdisp
, flags
, dp
, retv
, ei
, caller
);
893 vdisp_release(&vdisp
);
897 HRESULT
jsdisp_call(jsdisp_t
*disp
, DISPID id
, WORD flags
, DISPPARAMS
*dp
, VARIANT
*retv
,
898 jsexcept_t
*ei
, IServiceProvider
*caller
)
902 memset(ei
, 0, sizeof(*ei
));
904 V_VT(retv
) = VT_EMPTY
;
906 prop
= get_prop(disp
, id
);
908 return DISP_E_MEMBERNOTFOUND
;
910 return invoke_prop_func(disp
, disp
, prop
, flags
, dp
, retv
, ei
, caller
);
913 HRESULT
jsdisp_call_name(jsdisp_t
*disp
, const WCHAR
*name
, WORD flags
, DISPPARAMS
*dp
, VARIANT
*retv
,
914 jsexcept_t
*ei
, IServiceProvider
*caller
)
919 hres
= find_prop_name_prot(disp
, name
, &prop
);
923 memset(ei
, 0, sizeof(*ei
));
925 V_VT(retv
) = VT_EMPTY
;
927 return invoke_prop_func(disp
, disp
, prop
, flags
, dp
, retv
, ei
, caller
);
930 HRESULT
disp_call(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, WORD flags
, DISPPARAMS
*dp
, VARIANT
*retv
,
931 jsexcept_t
*ei
, IServiceProvider
*caller
)
937 jsdisp
= iface_to_jsdisp((IUnknown
*)disp
);
939 hres
= jsdisp_call(jsdisp
, id
, flags
, dp
, retv
, ei
, caller
);
940 jsdisp_release(jsdisp
);
944 memset(ei
, 0, sizeof(*ei
));
945 if(retv
&& arg_cnt(dp
))
946 flags
|= DISPATCH_PROPERTYGET
;
949 V_VT(retv
) = VT_EMPTY
;
950 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
954 if(flags
== DISPATCH_CONSTRUCT
) {
955 WARN("IDispatch cannot be constructor\n");
956 return DISP_E_MEMBERNOTFOUND
;
959 TRACE("using IDispatch\n");
960 return IDispatch_Invoke(disp
, id
, &IID_NULL
, ctx
->lcid
, flags
, dp
, retv
, &ei
->ei
, &err
);
963 hres
= IDispatchEx_InvokeEx(dispex
, id
, ctx
->lcid
, flags
, dp
, retv
, &ei
->ei
, caller
);
964 IDispatchEx_Release(dispex
);
969 HRESULT
jsdisp_propput_name(jsdisp_t
*obj
, const WCHAR
*name
, VARIANT
*val
, jsexcept_t
*ei
, IServiceProvider
*caller
)
974 hres
= ensure_prop_name(obj
, name
, FALSE
, PROPF_ENUM
, &prop
);
978 return prop_put(obj
, prop
, val
, ei
, caller
);
981 HRESULT
jsdisp_propput_const(jsdisp_t
*obj
, const WCHAR
*name
, VARIANT
*val
)
986 hres
= ensure_prop_name(obj
, name
, FALSE
, PROPF_ENUM
|PROPF_CONST
, &prop
);
990 return VariantCopy(&prop
->u
.var
, val
);
993 HRESULT
jsdisp_propput_idx(jsdisp_t
*obj
, DWORD idx
, VARIANT
*val
, jsexcept_t
*ei
, IServiceProvider
*caller
)
997 static const WCHAR formatW
[] = {'%','d',0};
999 sprintfW(buf
, formatW
, idx
);
1000 return jsdisp_propput_name(obj
, buf
, val
, ei
, caller
);
1003 HRESULT
disp_propput(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, VARIANT
*val
, jsexcept_t
*ei
, IServiceProvider
*caller
)
1008 jsdisp
= iface_to_jsdisp((IUnknown
*)disp
);
1010 dispex_prop_t
*prop
;
1012 prop
= get_prop(jsdisp
, id
);
1014 hres
= prop_put(jsdisp
, prop
, val
, ei
, caller
);
1016 hres
= DISP_E_MEMBERNOTFOUND
;
1018 jsdisp_release(jsdisp
);
1020 DISPID dispid
= DISPID_PROPERTYPUT
;
1021 DISPPARAMS dp
= {val
, &dispid
, 1, 1};
1022 IDispatchEx
*dispex
;
1024 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
1025 if(SUCCEEDED(hres
)) {
1026 hres
= IDispatchEx_InvokeEx(dispex
, id
, ctx
->lcid
, DISPATCH_PROPERTYPUT
, &dp
, NULL
, &ei
->ei
, caller
);
1027 IDispatchEx_Release(dispex
);
1031 TRACE("using IDispatch\n");
1032 hres
= IDispatch_Invoke(disp
, id
, &IID_NULL
, ctx
->lcid
, DISPATCH_PROPERTYPUT
, &dp
, NULL
, &ei
->ei
, &err
);
1039 HRESULT
jsdisp_propget_name(jsdisp_t
*obj
, const WCHAR
*name
, VARIANT
*var
, jsexcept_t
*ei
, IServiceProvider
*caller
)
1041 DISPPARAMS dp
= {NULL
, NULL
, 0, 0};
1042 dispex_prop_t
*prop
;
1045 hres
= find_prop_name_prot(obj
, name
, &prop
);
1049 V_VT(var
) = VT_EMPTY
;
1053 return prop_get(obj
, prop
, &dp
, var
, ei
, caller
);
1056 HRESULT
jsdisp_get_idx(jsdisp_t
*obj
, DWORD idx
, VARIANT
*var
, jsexcept_t
*ei
, IServiceProvider
*caller
)
1059 DISPPARAMS dp
= {NULL
, NULL
, 0, 0};
1060 dispex_prop_t
*prop
;
1063 static const WCHAR formatW
[] = {'%','d',0};
1065 sprintfW(name
, formatW
, idx
);
1067 hres
= find_prop_name_prot(obj
, name
, &prop
);
1071 V_VT(var
) = VT_EMPTY
;
1073 return DISP_E_UNKNOWNNAME
;
1075 return prop_get(obj
, prop
, &dp
, var
, ei
, caller
);
1078 HRESULT
jsdisp_propget(jsdisp_t
*jsdisp
, DISPID id
, VARIANT
*val
, jsexcept_t
*ei
, IServiceProvider
*caller
)
1080 DISPPARAMS dp
= {NULL
,NULL
,0,0};
1081 dispex_prop_t
*prop
;
1083 prop
= get_prop(jsdisp
, id
);
1085 return DISP_E_MEMBERNOTFOUND
;
1087 V_VT(val
) = VT_EMPTY
;
1088 return prop_get(jsdisp
, prop
, &dp
, val
, ei
, caller
);
1091 HRESULT
disp_propget(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, VARIANT
*val
, jsexcept_t
*ei
, IServiceProvider
*caller
)
1093 DISPPARAMS dp
= {NULL
,NULL
,0,0};
1094 IDispatchEx
*dispex
;
1098 jsdisp
= iface_to_jsdisp((IUnknown
*)disp
);
1100 hres
= jsdisp_propget(jsdisp
, id
, val
, ei
, caller
);
1101 jsdisp_release(jsdisp
);
1105 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
1109 TRACE("using IDispatch\n");
1110 return IDispatch_Invoke(disp
, id
, &IID_NULL
, ctx
->lcid
, INVOKE_PROPERTYGET
, &dp
, val
, &ei
->ei
, &err
);
1113 hres
= IDispatchEx_InvokeEx(dispex
, id
, ctx
->lcid
, INVOKE_PROPERTYGET
, &dp
, val
, &ei
->ei
, caller
);
1114 IDispatchEx_Release(dispex
);
1119 HRESULT
jsdisp_delete_idx(jsdisp_t
*obj
, DWORD idx
)
1121 static const WCHAR formatW
[] = {'%','d',0};
1123 dispex_prop_t
*prop
;
1126 sprintfW(buf
, formatW
, idx
);
1128 hres
= find_prop_name(obj
, buf
, &prop
);
1129 if(FAILED(hres
) || !prop
)
1132 return delete_prop(prop
);