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
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(jscript
);
28 static const GUID GUID_JScriptTypeInfo
= {0xc59c6b12,0xf6c1,0x11cf,{0x88,0x35,0x00,0xa0,0xc9,0x11,0xe8,0xb2}};
30 #define FDEX_VERSION_MASK 0xf0000000
31 #define GOLDEN_RATIO 0x9E3779B9U
42 struct _dispex_prop_t
{
50 const builtin_prop_t
*p
;
63 static void fix_protref_prop(jsdisp_t
*jsdisp
, dispex_prop_t
*prop
)
67 if(prop
->type
!= PROP_PROTREF
)
71 while((jsdisp
= jsdisp
->prototype
)) {
72 if(ref
>= jsdisp
->prop_cnt
|| jsdisp
->props
[ref
].type
== PROP_DELETED
)
74 if(jsdisp
->props
[ref
].type
!= PROP_PROTREF
)
76 ref
= jsdisp
->props
[ref
].u
.ref
;
78 prop
->type
= PROP_DELETED
;
81 static inline DISPID
prop_to_id(jsdisp_t
*This
, dispex_prop_t
*prop
)
83 /* don't overlap with DISPID_VALUE */
84 return prop
- This
->props
+ 1;
87 static inline dispex_prop_t
*get_prop(jsdisp_t
*This
, DISPID id
)
91 if(idx
>= This
->prop_cnt
)
93 fix_protref_prop(This
, &This
->props
[idx
]);
95 return This
->props
[idx
].type
== PROP_DELETED
? NULL
: &This
->props
[idx
];
98 static inline BOOL
is_function_prop(dispex_prop_t
*prop
)
102 if (is_object_instance(prop
->u
.val
))
104 jsdisp_t
*jsdisp
= iface_to_jsdisp(get_object(prop
->u
.val
));
106 if (jsdisp
) ret
= is_class(jsdisp
, JSCLASS_FUNCTION
);
107 jsdisp_release(jsdisp
);
112 static DWORD
get_flags(jsdisp_t
*This
, dispex_prop_t
*prop
)
114 if(prop
->type
== PROP_PROTREF
) {
115 dispex_prop_t
*parent
= NULL
;
117 if(prop
->u
.ref
< This
->prototype
->prop_cnt
)
118 parent
= &This
->prototype
->props
[prop
->u
.ref
];
120 if(!parent
|| parent
->type
== PROP_DELETED
) {
121 prop
->type
= PROP_DELETED
;
125 return get_flags(This
->prototype
, parent
);
131 static const builtin_prop_t
*find_builtin_prop(jsdisp_t
*This
, const WCHAR
*name
)
133 int min
= 0, max
, i
, r
;
135 max
= This
->builtin_info
->props_cnt
-1;
139 r
= wcscmp(name
, This
->builtin_info
->props
[i
].name
);
141 /* Skip prop if it's available only in higher compatibility mode. */
142 unsigned version
= (This
->builtin_info
->props
[i
].flags
& PROPF_VERSION_MASK
)
143 >> PROPF_VERSION_SHIFT
;
144 if(version
&& version
> This
->ctx
->version
)
147 /* Skip prop if it's available only in HTML mode and we're not running in HTML mode. */
148 if((This
->builtin_info
->props
[i
].flags
& PROPF_HTML
) && !This
->ctx
->html_mode
)
151 return This
->builtin_info
->props
+ i
;
163 static inline unsigned string_hash(const WCHAR
*name
)
167 h
= (h
>>(sizeof(unsigned)*8-4)) ^ (h
<<4) ^ towlower(*name
);
171 static inline unsigned get_props_idx(jsdisp_t
*This
, unsigned hash
)
173 return (hash
*GOLDEN_RATIO
) & (This
->buf_size
-1);
176 static inline HRESULT
resize_props(jsdisp_t
*This
)
178 dispex_prop_t
*props
;
181 if(This
->buf_size
!= This
->prop_cnt
)
184 props
= heap_realloc(This
->props
, sizeof(dispex_prop_t
)*This
->buf_size
*2);
186 return E_OUTOFMEMORY
;
190 for(i
=0; i
<This
->buf_size
; i
++) {
191 This
->props
[i
].bucket_head
= ~0;
192 This
->props
[i
].bucket_next
= ~0;
195 for(i
=0; i
<This
->prop_cnt
; i
++) {
196 props
= This
->props
+i
;
198 bucket
= get_props_idx(This
, props
->hash
);
199 props
->bucket_next
= This
->props
[bucket
].bucket_head
;
200 This
->props
[bucket
].bucket_head
= i
;
206 static inline dispex_prop_t
* alloc_prop(jsdisp_t
*This
, const WCHAR
*name
, prop_type_t type
, DWORD flags
)
211 if(FAILED(resize_props(This
)))
214 prop
= &This
->props
[This
->prop_cnt
];
215 prop
->name
= heap_strdupW(name
);
220 prop
->hash
= string_hash(name
);
222 bucket
= get_props_idx(This
, prop
->hash
);
223 prop
->bucket_next
= This
->props
[bucket
].bucket_head
;
224 This
->props
[bucket
].bucket_head
= This
->prop_cnt
++;
228 static dispex_prop_t
*alloc_protref(jsdisp_t
*This
, const WCHAR
*name
, DWORD ref
)
232 ret
= alloc_prop(This
, name
, PROP_PROTREF
, 0);
240 static HRESULT
find_prop_name(jsdisp_t
*This
, unsigned hash
, const WCHAR
*name
, dispex_prop_t
**ret
)
242 const builtin_prop_t
*builtin
;
243 unsigned bucket
, pos
, prev
= ~0;
247 bucket
= get_props_idx(This
, hash
);
248 pos
= This
->props
[bucket
].bucket_head
;
250 if(!wcscmp(name
, This
->props
[pos
].name
)) {
252 This
->props
[prev
].bucket_next
= This
->props
[pos
].bucket_next
;
253 This
->props
[pos
].bucket_next
= This
->props
[bucket
].bucket_head
;
254 This
->props
[bucket
].bucket_head
= pos
;
257 *ret
= &This
->props
[pos
];
262 pos
= This
->props
[pos
].bucket_next
;
265 builtin
= find_builtin_prop(This
, name
);
267 unsigned flags
= builtin
->flags
;
268 if(flags
& PROPF_METHOD
) {
271 hres
= create_builtin_function(This
->ctx
, builtin
->invoke
, builtin
->name
, NULL
, flags
, NULL
, &obj
);
275 prop
= alloc_prop(This
, name
, PROP_JSVAL
, (flags
& PROPF_ALL
) | PROPF_WRITABLE
| PROPF_CONFIGURABLE
);
278 return E_OUTOFMEMORY
;
281 prop
->type
= PROP_JSVAL
;
282 prop
->u
.val
= jsval_obj(obj
);
285 }else if(builtin
->setter
)
286 flags
|= PROPF_WRITABLE
;
287 flags
&= PROPF_ENUMERABLE
| PROPF_WRITABLE
| PROPF_CONFIGURABLE
;
288 prop
= alloc_prop(This
, name
, PROP_BUILTIN
, flags
);
290 return E_OUTOFMEMORY
;
297 if(This
->builtin_info
->idx_length
) {
301 for(ptr
= name
; is_digit(*ptr
) && idx
< 0x10000; ptr
++)
302 idx
= idx
*10 + (*ptr
-'0');
303 if(!*ptr
&& idx
< This
->builtin_info
->idx_length(This
)) {
304 unsigned flags
= PROPF_ENUMERABLE
;
305 if(This
->builtin_info
->idx_put
)
306 flags
|= PROPF_WRITABLE
;
307 prop
= alloc_prop(This
, name
, PROP_IDX
, flags
);
309 return E_OUTOFMEMORY
;
321 static HRESULT
find_prop_name_prot(jsdisp_t
*This
, unsigned hash
, const WCHAR
*name
, dispex_prop_t
**ret
)
323 dispex_prop_t
*prop
, *del
=NULL
;
326 hres
= find_prop_name(This
, hash
, name
, &prop
);
329 if(prop
&& prop
->type
==PROP_DELETED
) {
332 fix_protref_prop(This
, prop
);
337 if(This
->prototype
) {
338 hres
= find_prop_name_prot(This
->prototype
, hash
, name
, &prop
);
341 if(prop
&& prop
->type
!= PROP_DELETED
) {
343 del
->type
= PROP_PROTREF
;
344 del
->u
.ref
= prop
- This
->prototype
->props
;
347 prop
= alloc_protref(This
, prop
->name
, prop
- This
->prototype
->props
);
349 return E_OUTOFMEMORY
;
361 static HRESULT
ensure_prop_name(jsdisp_t
*This
, const WCHAR
*name
, DWORD create_flags
, dispex_prop_t
**ret
)
366 hres
= find_prop_name_prot(This
, string_hash(name
), name
, &prop
);
367 if(SUCCEEDED(hres
) && (!prop
|| prop
->type
== PROP_DELETED
)) {
368 TRACE("creating prop %s flags %lx\n", debugstr_w(name
), create_flags
);
371 prop
->type
= PROP_JSVAL
;
372 prop
->flags
= create_flags
;
373 prop
->u
.val
= jsval_undefined();
375 prop
= alloc_prop(This
, name
, PROP_JSVAL
, create_flags
);
377 return E_OUTOFMEMORY
;
380 prop
->u
.val
= jsval_undefined();
387 static IDispatch
*get_this(DISPPARAMS
*dp
)
391 for(i
=0; i
< dp
->cNamedArgs
; i
++) {
392 if(dp
->rgdispidNamedArgs
[i
] == DISPID_THIS
) {
393 if(V_VT(dp
->rgvarg
+i
) == VT_DISPATCH
)
394 return V_DISPATCH(dp
->rgvarg
+i
);
396 WARN("This is not VT_DISPATCH\n");
401 TRACE("no this passed\n");
405 static HRESULT
convert_params(script_ctx_t
*ctx
, const DISPPARAMS
*dp
, jsval_t
*buf
, unsigned *argc
, jsval_t
**ret
)
412 cnt
= dp
->cArgs
- dp
->cNamedArgs
;
415 argv
= heap_alloc(cnt
* sizeof(*argv
));
417 return E_OUTOFMEMORY
;
422 for(i
= 0; i
< cnt
; i
++) {
423 hres
= variant_to_jsval(ctx
, dp
->rgvarg
+dp
->cArgs
-i
-1, argv
+i
);
426 jsval_release(argv
[i
]);
438 static HRESULT
prop_get(jsdisp_t
*This
, dispex_prop_t
*prop
, jsval_t
*r
)
440 jsdisp_t
*prop_obj
= This
;
443 while(prop
->type
== PROP_PROTREF
) {
444 prop_obj
= prop_obj
->prototype
;
445 prop
= prop_obj
->props
+ prop
->u
.ref
;
450 hres
= prop
->u
.p
->getter(This
->ctx
, This
, r
);
453 hres
= jsval_copy(prop
->u
.val
, r
);
456 if(prop
->u
.accessor
.getter
) {
457 hres
= jsdisp_call_value(prop
->u
.accessor
.getter
, to_disp(This
),
458 DISPATCH_METHOD
, 0, NULL
, r
);
460 *r
= jsval_undefined();
465 hres
= prop_obj
->builtin_info
->idx_get(prop_obj
, prop
->u
.idx
, r
);
468 ERR("type %d\n", prop
->type
);
473 TRACE("fail %08lx\n", hres
);
477 TRACE("%p.%s ret %s\n", This
, debugstr_w(prop
->name
), debugstr_jsval(*r
));
481 static HRESULT
prop_put(jsdisp_t
*This
, dispex_prop_t
*prop
, jsval_t val
)
485 if(prop
->type
== PROP_PROTREF
) {
486 dispex_prop_t
*prop_iter
= prop
;
487 jsdisp_t
*prototype_iter
= This
;
490 prototype_iter
= prototype_iter
->prototype
;
491 prop_iter
= prototype_iter
->props
+ prop_iter
->u
.ref
;
492 } while(prop_iter
->type
== PROP_PROTREF
);
494 if(prop_iter
->type
== PROP_ACCESSOR
)
500 if(!prop
->u
.p
->setter
) {
501 TRACE("getter with no setter\n");
504 return prop
->u
.p
->setter(This
->ctx
, This
, val
);
507 if(!This
->extensible
)
509 prop
->type
= PROP_JSVAL
;
510 prop
->flags
= PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
;
511 prop
->u
.val
= jsval_undefined();
514 if(!(prop
->flags
& PROPF_WRITABLE
))
517 jsval_release(prop
->u
.val
);
520 if(!prop
->u
.accessor
.setter
) {
521 TRACE("no setter\n");
524 return jsdisp_call_value(prop
->u
.accessor
.setter
, to_disp(This
), DISPATCH_METHOD
, 1, &val
, NULL
);
526 if(!This
->builtin_info
->idx_put
) {
527 TRACE("no put_idx\n");
530 return This
->builtin_info
->idx_put(This
, prop
->u
.idx
, val
);
532 ERR("type %d\n", prop
->type
);
536 TRACE("%p.%s = %s\n", This
, debugstr_w(prop
->name
), debugstr_jsval(val
));
538 hres
= jsval_copy(val
, &prop
->u
.val
);
542 if(This
->builtin_info
->on_put
)
543 This
->builtin_info
->on_put(This
, prop
->name
);
548 static HRESULT
invoke_prop_func(jsdisp_t
*This
, IDispatch
*jsthis
, dispex_prop_t
*prop
, WORD flags
,
549 unsigned argc
, jsval_t
*argv
, jsval_t
*r
, IServiceProvider
*caller
)
555 return JS_E_FUNCTION_EXPECTED
;
557 return invoke_prop_func(This
->prototype
, jsthis
? jsthis
: (IDispatch
*)&This
->IDispatchEx_iface
,
558 This
->prototype
->props
+prop
->u
.ref
, flags
, argc
, argv
, r
, caller
);
560 if(!is_object_instance(prop
->u
.val
)) {
561 FIXME("invoke %s\n", debugstr_jsval(prop
->u
.val
));
565 TRACE("call %s %p\n", debugstr_w(prop
->name
), get_object(prop
->u
.val
));
567 return disp_call_value(This
->ctx
, get_object(prop
->u
.val
),
568 jsthis
? jsthis
: (IDispatch
*)&This
->IDispatchEx_iface
,
569 flags
, argc
, argv
, r
);
575 hres
= prop_get(This
, prop
, &val
);
579 if(is_object_instance(val
)) {
580 hres
= disp_call_value(This
->ctx
, get_object(val
),
581 jsthis
? jsthis
: (IDispatch
*)&This
->IDispatchEx_iface
,
582 flags
, argc
, argv
, r
);
584 FIXME("invoke %s\n", debugstr_jsval(val
));
599 HRESULT
builtin_set_const(script_ctx_t
*ctx
, jsdisp_t
*jsthis
, jsval_t value
)
601 TRACE("%p %s\n", jsthis
, debugstr_jsval(value
));
605 static HRESULT
fill_protrefs(jsdisp_t
*This
)
607 dispex_prop_t
*iter
, *prop
;
613 fill_protrefs(This
->prototype
);
615 for(iter
= This
->prototype
->props
; iter
< This
->prototype
->props
+This
->prototype
->prop_cnt
; iter
++) {
616 hres
= find_prop_name(This
, iter
->hash
, iter
->name
, &prop
);
619 if(!prop
|| prop
->type
==PROP_DELETED
) {
621 prop
->type
= PROP_PROTREF
;
623 prop
->u
.ref
= iter
- This
->prototype
->props
;
625 prop
= alloc_protref(This
, iter
->name
, iter
- This
->prototype
->props
);
627 return E_OUTOFMEMORY
;
635 struct typeinfo_func
{
637 function_code_t
*code
;
641 ITypeInfo ITypeInfo_iface
;
642 ITypeComp ITypeComp_iface
;
647 struct typeinfo_func
*funcs
;
648 dispex_prop_t
**vars
;
653 static struct typeinfo_func
*get_func_from_memid(const ScriptTypeInfo
*typeinfo
, MEMBERID memid
)
655 UINT a
= 0, b
= typeinfo
->num_funcs
;
659 UINT i
= (a
+ b
- 1) / 2;
660 MEMBERID func_memid
= prop_to_id(typeinfo
->jsdisp
, typeinfo
->funcs
[i
].prop
);
662 if (memid
== func_memid
)
663 return &typeinfo
->funcs
[i
];
664 else if (memid
< func_memid
)
672 static dispex_prop_t
*get_var_from_memid(const ScriptTypeInfo
*typeinfo
, MEMBERID memid
)
674 UINT a
= 0, b
= typeinfo
->num_vars
;
678 UINT i
= (a
+ b
- 1) / 2;
679 MEMBERID var_memid
= prop_to_id(typeinfo
->jsdisp
, typeinfo
->vars
[i
]);
681 if (memid
== var_memid
)
682 return typeinfo
->vars
[i
];
683 else if (memid
< var_memid
)
691 static inline ScriptTypeInfo
*ScriptTypeInfo_from_ITypeInfo(ITypeInfo
*iface
)
693 return CONTAINING_RECORD(iface
, ScriptTypeInfo
, ITypeInfo_iface
);
696 static inline ScriptTypeInfo
*ScriptTypeInfo_from_ITypeComp(ITypeComp
*iface
)
698 return CONTAINING_RECORD(iface
, ScriptTypeInfo
, ITypeComp_iface
);
701 static HRESULT WINAPI
ScriptTypeInfo_QueryInterface(ITypeInfo
*iface
, REFIID riid
, void **ppv
)
703 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
705 if (IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_ITypeInfo
, riid
))
706 *ppv
= &This
->ITypeInfo_iface
;
707 else if (IsEqualGUID(&IID_ITypeComp
, riid
))
708 *ppv
= &This
->ITypeComp_iface
;
711 WARN("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
713 return E_NOINTERFACE
;
716 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
717 IUnknown_AddRef((IUnknown
*)*ppv
);
721 static ULONG WINAPI
ScriptTypeInfo_AddRef(ITypeInfo
*iface
)
723 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
724 LONG ref
= InterlockedIncrement(&This
->ref
);
726 TRACE("(%p) ref=%ld\n", This
, ref
);
731 static ULONG WINAPI
ScriptTypeInfo_Release(ITypeInfo
*iface
)
733 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
734 LONG ref
= InterlockedDecrement(&This
->ref
);
737 TRACE("(%p) ref=%ld\n", This
, ref
);
741 for (i
= This
->num_funcs
; i
--;)
742 release_bytecode(This
->funcs
[i
].code
->bytecode
);
743 IDispatchEx_Release(&This
->jsdisp
->IDispatchEx_iface
);
744 heap_free(This
->funcs
);
745 heap_free(This
->vars
);
751 static HRESULT WINAPI
ScriptTypeInfo_GetTypeAttr(ITypeInfo
*iface
, TYPEATTR
**ppTypeAttr
)
753 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
756 TRACE("(%p)->(%p)\n", This
, ppTypeAttr
);
758 if (!ppTypeAttr
) return E_INVALIDARG
;
760 attr
= heap_alloc_zero(sizeof(*attr
));
761 if (!attr
) return E_OUTOFMEMORY
;
763 attr
->guid
= GUID_JScriptTypeInfo
;
764 attr
->lcid
= LOCALE_USER_DEFAULT
;
765 attr
->memidConstructor
= MEMBERID_NIL
;
766 attr
->memidDestructor
= MEMBERID_NIL
;
767 attr
->cbSizeInstance
= 4;
768 attr
->typekind
= TKIND_DISPATCH
;
769 attr
->cFuncs
= This
->num_funcs
;
770 attr
->cVars
= This
->num_vars
;
771 attr
->cImplTypes
= 1;
772 attr
->cbSizeVft
= sizeof(IDispatchVtbl
);
773 attr
->cbAlignment
= 4;
774 attr
->wTypeFlags
= TYPEFLAG_FDISPATCHABLE
;
775 attr
->wMajorVerNum
= JSCRIPT_MAJOR_VERSION
;
776 attr
->wMinorVerNum
= JSCRIPT_MINOR_VERSION
;
782 static HRESULT WINAPI
ScriptTypeInfo_GetTypeComp(ITypeInfo
*iface
, ITypeComp
**ppTComp
)
784 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
786 TRACE("(%p)->(%p)\n", This
, ppTComp
);
788 if (!ppTComp
) return E_INVALIDARG
;
790 *ppTComp
= &This
->ITypeComp_iface
;
791 ITypeInfo_AddRef(iface
);
795 static HRESULT WINAPI
ScriptTypeInfo_GetFuncDesc(ITypeInfo
*iface
, UINT index
, FUNCDESC
**ppFuncDesc
)
797 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
798 struct typeinfo_func
*func
;
802 TRACE("(%p)->(%u %p)\n", This
, index
, ppFuncDesc
);
804 if (!ppFuncDesc
) return E_INVALIDARG
;
805 if (index
>= This
->num_funcs
) return TYPE_E_ELEMENTNOTFOUND
;
806 func
= &This
->funcs
[index
];
808 /* Store the parameter array after the FUNCDESC structure */
809 desc
= heap_alloc_zero(sizeof(*desc
) + sizeof(ELEMDESC
) * func
->code
->param_cnt
);
810 if (!desc
) return E_OUTOFMEMORY
;
812 desc
->memid
= prop_to_id(This
->jsdisp
, func
->prop
);
813 desc
->funckind
= FUNC_DISPATCH
;
814 desc
->invkind
= INVOKE_FUNC
;
815 desc
->callconv
= CC_STDCALL
;
816 desc
->cParams
= func
->code
->param_cnt
;
817 desc
->elemdescFunc
.tdesc
.vt
= VT_VARIANT
;
819 if (func
->code
->param_cnt
) desc
->lprgelemdescParam
= (ELEMDESC
*)(desc
+ 1);
820 for (i
= 0; i
< func
->code
->param_cnt
; i
++)
821 desc
->lprgelemdescParam
[i
].tdesc
.vt
= VT_VARIANT
;
827 static HRESULT WINAPI
ScriptTypeInfo_GetVarDesc(ITypeInfo
*iface
, UINT index
, VARDESC
**ppVarDesc
)
829 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
832 TRACE("(%p)->(%u %p)\n", This
, index
, ppVarDesc
);
834 if (!ppVarDesc
) return E_INVALIDARG
;
835 if (index
>= This
->num_vars
) return TYPE_E_ELEMENTNOTFOUND
;
837 desc
= heap_alloc_zero(sizeof(*desc
));
838 if (!desc
) return E_OUTOFMEMORY
;
840 desc
->memid
= prop_to_id(This
->jsdisp
, This
->vars
[index
]);
841 desc
->varkind
= VAR_DISPATCH
;
842 desc
->elemdescVar
.tdesc
.vt
= VT_VARIANT
;
848 static HRESULT WINAPI
ScriptTypeInfo_GetNames(ITypeInfo
*iface
, MEMBERID memid
, BSTR
*rgBstrNames
,
849 UINT cMaxNames
, UINT
*pcNames
)
851 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
852 struct typeinfo_func
*func
;
853 ITypeInfo
*disp_typeinfo
;
858 TRACE("(%p)->(%ld %p %u %p)\n", This
, memid
, rgBstrNames
, cMaxNames
, pcNames
);
860 if (!rgBstrNames
|| !pcNames
) return E_INVALIDARG
;
861 if (memid
<= 0) return TYPE_E_ELEMENTNOTFOUND
;
863 func
= get_func_from_memid(This
, memid
);
866 var
= get_var_from_memid(This
, memid
);
869 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
870 if (FAILED(hr
)) return hr
;
872 return ITypeInfo_GetNames(disp_typeinfo
, memid
, rgBstrNames
, cMaxNames
, pcNames
);
877 if (!cMaxNames
) return S_OK
;
879 rgBstrNames
[0] = SysAllocString(func
? func
->prop
->name
: var
->name
);
880 if (!rgBstrNames
[0]) return E_OUTOFMEMORY
;
885 unsigned num
= min(cMaxNames
, func
->code
->param_cnt
+ 1);
889 if (!(rgBstrNames
[i
] = SysAllocString(func
->code
->params
[i
- 1])))
891 do SysFreeString(rgBstrNames
[--i
]); while (i
);
892 return E_OUTOFMEMORY
;
901 static HRESULT WINAPI
ScriptTypeInfo_GetRefTypeOfImplType(ITypeInfo
*iface
, UINT index
, HREFTYPE
*pRefType
)
903 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
905 TRACE("(%p)->(%u %p)\n", This
, index
, pRefType
);
907 /* We only inherit from IDispatch */
908 if (!pRefType
) return E_INVALIDARG
;
909 if (index
!= 0) return TYPE_E_ELEMENTNOTFOUND
;
915 static HRESULT WINAPI
ScriptTypeInfo_GetImplTypeFlags(ITypeInfo
*iface
, UINT index
, INT
*pImplTypeFlags
)
917 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
919 TRACE("(%p)->(%u %p)\n", This
, index
, pImplTypeFlags
);
921 if (!pImplTypeFlags
) return E_INVALIDARG
;
922 if (index
!= 0) return TYPE_E_ELEMENTNOTFOUND
;
928 static HRESULT WINAPI
ScriptTypeInfo_GetIDsOfNames(ITypeInfo
*iface
, LPOLESTR
*rgszNames
, UINT cNames
,
931 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
932 ITypeInfo
*disp_typeinfo
;
937 TRACE("(%p)->(%p %u %p)\n", This
, rgszNames
, cNames
, pMemId
);
939 if (!rgszNames
|| !cNames
|| !pMemId
) return E_INVALIDARG
;
941 for (i
= 0; i
< cNames
; i
++) pMemId
[i
] = MEMBERID_NIL
;
944 for (i
= 0; i
< This
->num_funcs
; i
++)
946 struct typeinfo_func
*func
= &This
->funcs
[i
];
948 if (wcsicmp(name
, func
->prop
->name
)) continue;
949 pMemId
[0] = prop_to_id(This
->jsdisp
, func
->prop
);
951 for (j
= 1; j
< cNames
; j
++)
954 for (arg
= func
->code
->param_cnt
; --arg
>= 0;)
955 if (!wcsicmp(name
, func
->code
->params
[arg
]))
960 hr
= DISP_E_UNKNOWNNAME
;
965 for (i
= 0; i
< This
->num_vars
; i
++)
967 dispex_prop_t
*var
= This
->vars
[i
];
969 if (wcsicmp(name
, var
->name
)) continue;
970 pMemId
[0] = prop_to_id(This
->jsdisp
, var
);
974 /* Look into the inherited IDispatch */
975 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
976 if (FAILED(hr
)) return hr
;
978 return ITypeInfo_GetIDsOfNames(disp_typeinfo
, rgszNames
, cNames
, pMemId
);
981 static HRESULT WINAPI
ScriptTypeInfo_Invoke(ITypeInfo
*iface
, PVOID pvInstance
, MEMBERID memid
, WORD wFlags
,
982 DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
984 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
985 ITypeInfo
*disp_typeinfo
;
989 TRACE("(%p)->(%p %ld %d %p %p %p %p)\n", This
, pvInstance
, memid
, wFlags
,
990 pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
992 if (!pvInstance
) return E_INVALIDARG
;
993 if (memid
<= 0) return TYPE_E_ELEMENTNOTFOUND
;
995 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
997 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
998 if (FAILED(hr
)) return hr
;
1000 return ITypeInfo_Invoke(disp_typeinfo
, pvInstance
, memid
, wFlags
, pDispParams
,
1001 pVarResult
, pExcepInfo
, puArgErr
);
1004 hr
= IUnknown_QueryInterface((IUnknown
*)pvInstance
, &IID_IDispatch
, (void**)&disp
);
1005 if (FAILED(hr
)) return hr
;
1007 hr
= IDispatch_Invoke(disp
, memid
, &IID_NULL
, LOCALE_USER_DEFAULT
, wFlags
,
1008 pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
1009 IDispatch_Release(disp
);
1014 static HRESULT WINAPI
ScriptTypeInfo_GetDocumentation(ITypeInfo
*iface
, MEMBERID memid
, BSTR
*pBstrName
,
1015 BSTR
*pBstrDocString
, DWORD
*pdwHelpContext
, BSTR
*pBstrHelpFile
)
1017 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1018 struct typeinfo_func
*func
;
1019 ITypeInfo
*disp_typeinfo
;
1023 TRACE("(%p)->(%ld %p %p %p %p)\n", This
, memid
, pBstrName
, pBstrDocString
, pdwHelpContext
, pBstrHelpFile
);
1025 if (pBstrDocString
) *pBstrDocString
= NULL
;
1026 if (pdwHelpContext
) *pdwHelpContext
= 0;
1027 if (pBstrHelpFile
) *pBstrHelpFile
= NULL
;
1029 if (memid
== MEMBERID_NIL
)
1031 if (pBstrName
&& !(*pBstrName
= SysAllocString(L
"JScriptTypeInfo")))
1032 return E_OUTOFMEMORY
;
1033 if (pBstrDocString
&&
1034 !(*pBstrDocString
= SysAllocString(L
"JScript Type Info")))
1036 if (pBstrName
) SysFreeString(*pBstrName
);
1037 return E_OUTOFMEMORY
;
1041 if (memid
<= 0) return TYPE_E_ELEMENTNOTFOUND
;
1043 func
= get_func_from_memid(This
, memid
);
1046 var
= get_var_from_memid(This
, memid
);
1049 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1050 if (FAILED(hr
)) return hr
;
1052 return ITypeInfo_GetDocumentation(disp_typeinfo
, memid
, pBstrName
, pBstrDocString
,
1053 pdwHelpContext
, pBstrHelpFile
);
1059 *pBstrName
= SysAllocString(func
? func
->prop
->name
: var
->name
);
1062 return E_OUTOFMEMORY
;
1067 static HRESULT WINAPI
ScriptTypeInfo_GetDllEntry(ITypeInfo
*iface
, MEMBERID memid
, INVOKEKIND invKind
,
1068 BSTR
*pBstrDllName
, BSTR
*pBstrName
, WORD
*pwOrdinal
)
1070 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1071 ITypeInfo
*disp_typeinfo
;
1074 TRACE("(%p)->(%ld %d %p %p %p)\n", This
, memid
, invKind
, pBstrDllName
, pBstrName
, pwOrdinal
);
1076 if (pBstrDllName
) *pBstrDllName
= NULL
;
1077 if (pBstrName
) *pBstrName
= NULL
;
1078 if (pwOrdinal
) *pwOrdinal
= 0;
1080 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
1082 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1083 if (FAILED(hr
)) return hr
;
1085 return ITypeInfo_GetDllEntry(disp_typeinfo
, memid
, invKind
, pBstrDllName
, pBstrName
, pwOrdinal
);
1087 return TYPE_E_BADMODULEKIND
;
1090 static HRESULT WINAPI
ScriptTypeInfo_GetRefTypeInfo(ITypeInfo
*iface
, HREFTYPE hRefType
, ITypeInfo
**ppTInfo
)
1092 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1095 TRACE("(%p)->(%lx %p)\n", This
, hRefType
, ppTInfo
);
1097 if (!ppTInfo
|| (INT
)hRefType
< 0) return E_INVALIDARG
;
1099 if (hRefType
& ~3) return E_FAIL
;
1102 hr
= get_dispatch_typeinfo(ppTInfo
);
1103 if (FAILED(hr
)) return hr
;
1108 ITypeInfo_AddRef(*ppTInfo
);
1112 static HRESULT WINAPI
ScriptTypeInfo_AddressOfMember(ITypeInfo
*iface
, MEMBERID memid
, INVOKEKIND invKind
, PVOID
*ppv
)
1114 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1115 ITypeInfo
*disp_typeinfo
;
1118 TRACE("(%p)->(%ld %d %p)\n", This
, memid
, invKind
, ppv
);
1120 if (!ppv
) return E_INVALIDARG
;
1123 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
1125 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1126 if (FAILED(hr
)) return hr
;
1128 return ITypeInfo_AddressOfMember(disp_typeinfo
, memid
, invKind
, ppv
);
1130 return TYPE_E_BADMODULEKIND
;
1133 static HRESULT WINAPI
ScriptTypeInfo_CreateInstance(ITypeInfo
*iface
, IUnknown
*pUnkOuter
, REFIID riid
, PVOID
*ppvObj
)
1135 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1137 TRACE("(%p)->(%p %s %p)\n", This
, pUnkOuter
, debugstr_guid(riid
), ppvObj
);
1139 if (!ppvObj
) return E_INVALIDARG
;
1142 return TYPE_E_BADMODULEKIND
;
1145 static HRESULT WINAPI
ScriptTypeInfo_GetMops(ITypeInfo
*iface
, MEMBERID memid
, BSTR
*pBstrMops
)
1147 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1148 ITypeInfo
*disp_typeinfo
;
1151 TRACE("(%p)->(%ld %p)\n", This
, memid
, pBstrMops
);
1153 if (!pBstrMops
) return E_INVALIDARG
;
1155 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
1157 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1158 if (FAILED(hr
)) return hr
;
1160 return ITypeInfo_GetMops(disp_typeinfo
, memid
, pBstrMops
);
1167 static HRESULT WINAPI
ScriptTypeInfo_GetContainingTypeLib(ITypeInfo
*iface
, ITypeLib
**ppTLib
, UINT
*pIndex
)
1169 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1171 FIXME("(%p)->(%p %p)\n", This
, ppTLib
, pIndex
);
1176 static void WINAPI
ScriptTypeInfo_ReleaseTypeAttr(ITypeInfo
*iface
, TYPEATTR
*pTypeAttr
)
1178 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1180 TRACE("(%p)->(%p)\n", This
, pTypeAttr
);
1182 heap_free(pTypeAttr
);
1185 static void WINAPI
ScriptTypeInfo_ReleaseFuncDesc(ITypeInfo
*iface
, FUNCDESC
*pFuncDesc
)
1187 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1189 TRACE("(%p)->(%p)\n", This
, pFuncDesc
);
1191 heap_free(pFuncDesc
);
1194 static void WINAPI
ScriptTypeInfo_ReleaseVarDesc(ITypeInfo
*iface
, VARDESC
*pVarDesc
)
1196 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1198 TRACE("(%p)->(%p)\n", This
, pVarDesc
);
1200 heap_free(pVarDesc
);
1203 static const ITypeInfoVtbl ScriptTypeInfoVtbl
= {
1204 ScriptTypeInfo_QueryInterface
,
1205 ScriptTypeInfo_AddRef
,
1206 ScriptTypeInfo_Release
,
1207 ScriptTypeInfo_GetTypeAttr
,
1208 ScriptTypeInfo_GetTypeComp
,
1209 ScriptTypeInfo_GetFuncDesc
,
1210 ScriptTypeInfo_GetVarDesc
,
1211 ScriptTypeInfo_GetNames
,
1212 ScriptTypeInfo_GetRefTypeOfImplType
,
1213 ScriptTypeInfo_GetImplTypeFlags
,
1214 ScriptTypeInfo_GetIDsOfNames
,
1215 ScriptTypeInfo_Invoke
,
1216 ScriptTypeInfo_GetDocumentation
,
1217 ScriptTypeInfo_GetDllEntry
,
1218 ScriptTypeInfo_GetRefTypeInfo
,
1219 ScriptTypeInfo_AddressOfMember
,
1220 ScriptTypeInfo_CreateInstance
,
1221 ScriptTypeInfo_GetMops
,
1222 ScriptTypeInfo_GetContainingTypeLib
,
1223 ScriptTypeInfo_ReleaseTypeAttr
,
1224 ScriptTypeInfo_ReleaseFuncDesc
,
1225 ScriptTypeInfo_ReleaseVarDesc
1228 static HRESULT WINAPI
ScriptTypeComp_QueryInterface(ITypeComp
*iface
, REFIID riid
, void **ppv
)
1230 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1231 return ITypeInfo_QueryInterface(&This
->ITypeInfo_iface
, riid
, ppv
);
1234 static ULONG WINAPI
ScriptTypeComp_AddRef(ITypeComp
*iface
)
1236 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1237 return ITypeInfo_AddRef(&This
->ITypeInfo_iface
);
1240 static ULONG WINAPI
ScriptTypeComp_Release(ITypeComp
*iface
)
1242 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1243 return ITypeInfo_Release(&This
->ITypeInfo_iface
);
1246 static HRESULT WINAPI
ScriptTypeComp_Bind(ITypeComp
*iface
, LPOLESTR szName
, ULONG lHashVal
, WORD wFlags
,
1247 ITypeInfo
**ppTInfo
, DESCKIND
*pDescKind
, BINDPTR
*pBindPtr
)
1249 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1250 UINT flags
= wFlags
? wFlags
: ~0;
1251 ITypeInfo
*disp_typeinfo
;
1252 ITypeComp
*disp_typecomp
;
1256 TRACE("(%p)->(%s %08lx %d %p %p %p)\n", This
, debugstr_w(szName
), lHashVal
,
1257 wFlags
, ppTInfo
, pDescKind
, pBindPtr
);
1259 if (!szName
|| !ppTInfo
|| !pDescKind
|| !pBindPtr
)
1260 return E_INVALIDARG
;
1262 for (i
= 0; i
< This
->num_funcs
; i
++)
1264 if (wcsicmp(szName
, This
->funcs
[i
].prop
->name
)) continue;
1265 if (!(flags
& INVOKE_FUNC
)) return TYPE_E_TYPEMISMATCH
;
1267 hr
= ITypeInfo_GetFuncDesc(&This
->ITypeInfo_iface
, i
, &pBindPtr
->lpfuncdesc
);
1268 if (FAILED(hr
)) return hr
;
1270 *pDescKind
= DESCKIND_FUNCDESC
;
1271 *ppTInfo
= &This
->ITypeInfo_iface
;
1272 ITypeInfo_AddRef(*ppTInfo
);
1276 for (i
= 0; i
< This
->num_vars
; i
++)
1278 if (wcsicmp(szName
, This
->vars
[i
]->name
)) continue;
1279 if (!(flags
& INVOKE_PROPERTYGET
)) return TYPE_E_TYPEMISMATCH
;
1281 hr
= ITypeInfo_GetVarDesc(&This
->ITypeInfo_iface
, i
, &pBindPtr
->lpvardesc
);
1282 if (FAILED(hr
)) return hr
;
1284 *pDescKind
= DESCKIND_VARDESC
;
1285 *ppTInfo
= &This
->ITypeInfo_iface
;
1286 ITypeInfo_AddRef(*ppTInfo
);
1290 /* Look into the inherited IDispatch */
1291 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1292 if (FAILED(hr
)) return hr
;
1294 hr
= ITypeInfo_GetTypeComp(disp_typeinfo
, &disp_typecomp
);
1295 if (FAILED(hr
)) return hr
;
1297 hr
= ITypeComp_Bind(disp_typecomp
, szName
, lHashVal
, wFlags
, ppTInfo
, pDescKind
, pBindPtr
);
1298 ITypeComp_Release(disp_typecomp
);
1302 static HRESULT WINAPI
ScriptTypeComp_BindType(ITypeComp
*iface
, LPOLESTR szName
, ULONG lHashVal
,
1303 ITypeInfo
**ppTInfo
, ITypeComp
**ppTComp
)
1305 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1306 ITypeInfo
*disp_typeinfo
;
1307 ITypeComp
*disp_typecomp
;
1310 TRACE("(%p)->(%s %08lx %p %p)\n", This
, debugstr_w(szName
), lHashVal
, ppTInfo
, ppTComp
);
1312 if (!szName
|| !ppTInfo
|| !ppTComp
)
1313 return E_INVALIDARG
;
1315 /* Look into the inherited IDispatch */
1316 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1317 if (FAILED(hr
)) return hr
;
1319 hr
= ITypeInfo_GetTypeComp(disp_typeinfo
, &disp_typecomp
);
1320 if (FAILED(hr
)) return hr
;
1322 hr
= ITypeComp_BindType(disp_typecomp
, szName
, lHashVal
, ppTInfo
, ppTComp
);
1323 ITypeComp_Release(disp_typecomp
);
1327 static const ITypeCompVtbl ScriptTypeCompVtbl
= {
1328 ScriptTypeComp_QueryInterface
,
1329 ScriptTypeComp_AddRef
,
1330 ScriptTypeComp_Release
,
1331 ScriptTypeComp_Bind
,
1332 ScriptTypeComp_BindType
1335 static inline jsdisp_t
*impl_from_IDispatchEx(IDispatchEx
*iface
)
1337 return CONTAINING_RECORD(iface
, jsdisp_t
, IDispatchEx_iface
);
1340 static HRESULT WINAPI
DispatchEx_QueryInterface(IDispatchEx
*iface
, REFIID riid
, void **ppv
)
1342 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1344 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
1345 TRACE("(%p)->(IID_IUnknown %p)\n", This
, ppv
);
1346 *ppv
= &This
->IDispatchEx_iface
;
1347 }else if(IsEqualGUID(&IID_IDispatch
, riid
)) {
1348 TRACE("(%p)->(IID_IDispatch %p)\n", This
, ppv
);
1349 *ppv
= &This
->IDispatchEx_iface
;
1350 }else if(IsEqualGUID(&IID_IDispatchEx
, riid
)) {
1351 TRACE("(%p)->(IID_IDispatchEx %p)\n", This
, ppv
);
1352 *ppv
= &This
->IDispatchEx_iface
;
1354 WARN("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
1356 return E_NOINTERFACE
;
1359 jsdisp_addref(This
);
1363 static ULONG WINAPI
DispatchEx_AddRef(IDispatchEx
*iface
)
1365 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1366 jsdisp_addref(This
);
1370 static ULONG WINAPI
DispatchEx_Release(IDispatchEx
*iface
)
1372 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1373 ULONG ref
= --This
->ref
;
1374 TRACE("(%p) ref=%ld\n", This
, ref
);
1380 static HRESULT WINAPI
DispatchEx_GetTypeInfoCount(IDispatchEx
*iface
, UINT
*pctinfo
)
1382 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1384 TRACE("(%p)->(%p)\n", This
, pctinfo
);
1390 static HRESULT WINAPI
DispatchEx_GetTypeInfo(IDispatchEx
*iface
, UINT iTInfo
, LCID lcid
,
1391 ITypeInfo
**ppTInfo
)
1393 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1394 dispex_prop_t
*prop
, *cur
, *end
, **typevar
;
1395 UINT num_funcs
= 0, num_vars
= 0;
1396 struct typeinfo_func
*typefunc
;
1397 function_code_t
*func_code
;
1398 ScriptTypeInfo
*typeinfo
;
1401 TRACE("(%p)->(%u %lu %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
1403 if (iTInfo
!= 0) return DISP_E_BADINDEX
;
1405 for (prop
= This
->props
, end
= prop
+ This
->prop_cnt
; prop
!= end
; prop
++)
1407 if (prop
->type
!= PROP_JSVAL
|| !(prop
->flags
& PROPF_ENUMERABLE
))
1410 /* If two identifiers differ only by case, the TypeInfo fails */
1411 pos
= This
->props
[get_props_idx(This
, prop
->hash
)].bucket_head
;
1414 cur
= This
->props
+ pos
;
1416 if (prop
->hash
== cur
->hash
&& prop
!= cur
&&
1417 cur
->type
== PROP_JSVAL
&& (cur
->flags
& PROPF_ENUMERABLE
) &&
1418 !wcsicmp(prop
->name
, cur
->name
))
1420 return TYPE_E_AMBIGUOUSNAME
;
1422 pos
= cur
->bucket_next
;
1425 if (is_function_prop(prop
))
1427 if (Function_get_code(as_jsdisp(get_object(prop
->u
.val
))))
1433 if (!(typeinfo
= heap_alloc(sizeof(*typeinfo
))))
1434 return E_OUTOFMEMORY
;
1436 typeinfo
->ITypeInfo_iface
.lpVtbl
= &ScriptTypeInfoVtbl
;
1437 typeinfo
->ITypeComp_iface
.lpVtbl
= &ScriptTypeCompVtbl
;
1439 typeinfo
->num_vars
= num_vars
;
1440 typeinfo
->num_funcs
= num_funcs
;
1441 typeinfo
->jsdisp
= This
;
1443 typeinfo
->funcs
= heap_alloc(sizeof(*typeinfo
->funcs
) * num_funcs
);
1444 if (!typeinfo
->funcs
)
1446 heap_free(typeinfo
);
1447 return E_OUTOFMEMORY
;
1450 typeinfo
->vars
= heap_alloc(sizeof(*typeinfo
->vars
) * num_vars
);
1451 if (!typeinfo
->vars
)
1453 heap_free(typeinfo
->funcs
);
1454 heap_free(typeinfo
);
1455 return E_OUTOFMEMORY
;
1458 typefunc
= typeinfo
->funcs
;
1459 typevar
= typeinfo
->vars
;
1460 for (prop
= This
->props
; prop
!= end
; prop
++)
1462 if (prop
->type
!= PROP_JSVAL
|| !(prop
->flags
& PROPF_ENUMERABLE
))
1465 if (is_function_prop(prop
))
1467 func_code
= Function_get_code(as_jsdisp(get_object(prop
->u
.val
)));
1468 if (!func_code
) continue;
1470 typefunc
->prop
= prop
;
1471 typefunc
->code
= func_code
;
1474 /* The function may be deleted, so keep a ref */
1475 bytecode_addref(func_code
->bytecode
);
1481 /* Keep a ref to the props and their names */
1482 IDispatchEx_AddRef(&This
->IDispatchEx_iface
);
1484 *ppTInfo
= &typeinfo
->ITypeInfo_iface
;
1488 static HRESULT WINAPI
DispatchEx_GetIDsOfNames(IDispatchEx
*iface
, REFIID riid
,
1489 LPOLESTR
*rgszNames
, UINT cNames
, LCID lcid
,
1492 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1496 TRACE("(%p)->(%s %p %u %lu %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
,
1502 hres
= jsdisp_get_id(This
, rgszNames
[0], 0, rgDispId
);
1506 /* DISPIDs for parameters don't seem to be supported */
1508 for(i
= 1; i
< cNames
; i
++)
1509 rgDispId
[i
] = DISPID_UNKNOWN
;
1510 hres
= DISP_E_UNKNOWNNAME
;
1516 static HRESULT WINAPI
DispatchEx_Invoke(IDispatchEx
*iface
, DISPID dispIdMember
,
1517 REFIID riid
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
,
1518 VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
1520 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1522 TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This
, dispIdMember
, debugstr_guid(riid
),
1523 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
1525 return IDispatchEx_InvokeEx(&This
->IDispatchEx_iface
, dispIdMember
, lcid
, wFlags
,
1526 pDispParams
, pVarResult
, pExcepInfo
, NULL
);
1529 static HRESULT WINAPI
DispatchEx_GetDispID(IDispatchEx
*iface
, BSTR bstrName
, DWORD grfdex
, DISPID
*pid
)
1531 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1533 TRACE("(%p)->(%s %lx %p)\n", This
, debugstr_w(bstrName
), grfdex
, pid
);
1535 if(grfdex
& ~(fdexNameCaseSensitive
|fdexNameEnsure
|fdexNameImplicit
|FDEX_VERSION_MASK
)) {
1536 FIXME("Unsupported grfdex %lx\n", grfdex
);
1540 return jsdisp_get_id(This
, bstrName
, grfdex
, pid
);
1543 static HRESULT WINAPI
DispatchEx_InvokeEx(IDispatchEx
*iface
, DISPID id
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pdp
,
1544 VARIANT
*pvarRes
, EXCEPINFO
*pei
, IServiceProvider
*pspCaller
)
1546 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1547 dispex_prop_t
*prop
;
1551 TRACE("(%p)->(%lx %lx %x %p %p %p %p)\n", This
, id
, lcid
, wFlags
, pdp
, pvarRes
, pei
, pspCaller
);
1554 V_VT(pvarRes
) = VT_EMPTY
;
1556 prop
= get_prop(This
, id
);
1557 if(!prop
&& id
!= DISPID_VALUE
) {
1558 TRACE("invalid id\n");
1559 return DISP_E_MEMBERNOTFOUND
;
1562 enter_script(This
->ctx
, &ei
);
1565 case DISPATCH_METHOD
|DISPATCH_PROPERTYGET
:
1566 wFlags
= DISPATCH_METHOD
;
1568 case DISPATCH_METHOD
:
1569 case DISPATCH_CONSTRUCT
: {
1570 jsval_t
*argv
, buf
[6], r
;
1573 hres
= convert_params(This
->ctx
, pdp
, buf
, &argc
, &argv
);
1578 hres
= invoke_prop_func(This
, get_this(pdp
), prop
, wFlags
, argc
, argv
, pvarRes
? &r
: NULL
, pspCaller
);
1580 hres
= jsdisp_call_value(This
, get_this(pdp
), wFlags
, argc
, argv
, pvarRes
? &r
: NULL
);
1584 if(SUCCEEDED(hres
) && pvarRes
) {
1585 hres
= jsval_to_variant(r
, pvarRes
);
1590 case DISPATCH_PROPERTYGET
: {
1594 hres
= prop_get(This
, prop
, &r
);
1596 hres
= to_primitive(This
->ctx
, jsval_obj(This
), &r
, NO_HINT
);
1597 if(hres
== JS_E_TO_PRIMITIVE
)
1598 hres
= DISP_E_MEMBERNOTFOUND
;
1601 if(SUCCEEDED(hres
)) {
1602 hres
= jsval_to_variant(r
, pvarRes
);
1607 case DISPATCH_PROPERTYPUTREF
| DISPATCH_PROPERTYPUT
:
1608 case DISPATCH_PROPERTYPUTREF
:
1609 case DISPATCH_PROPERTYPUT
: {
1614 hres
= DISP_E_MEMBERNOTFOUND
;
1618 for(i
=0; i
< pdp
->cNamedArgs
; i
++) {
1619 if(pdp
->rgdispidNamedArgs
[i
] == DISPID_PROPERTYPUT
)
1623 if(i
== pdp
->cNamedArgs
) {
1624 TRACE("no value to set\n");
1625 hres
= DISP_E_PARAMNOTOPTIONAL
;
1629 hres
= variant_to_jsval(This
->ctx
, pdp
->rgvarg
+i
, &val
);
1633 hres
= prop_put(This
, prop
, val
);
1638 FIXME("Unimplemented flags %x\n", wFlags
);
1639 hres
= E_INVALIDARG
;
1643 return leave_script(This
->ctx
, hres
);
1646 static HRESULT
delete_prop(dispex_prop_t
*prop
, BOOL
*ret
)
1648 if(prop
->type
== PROP_PROTREF
) {
1653 if(!(prop
->flags
& PROPF_CONFIGURABLE
)) {
1660 if(prop
->type
== PROP_JSVAL
)
1661 jsval_release(prop
->u
.val
);
1662 if(prop
->type
== PROP_ACCESSOR
) {
1663 if(prop
->u
.accessor
.getter
)
1664 jsdisp_release(prop
->u
.accessor
.getter
);
1665 if(prop
->u
.accessor
.setter
)
1666 jsdisp_release(prop
->u
.accessor
.setter
);
1668 prop
->type
= PROP_DELETED
;
1672 static HRESULT WINAPI
DispatchEx_DeleteMemberByName(IDispatchEx
*iface
, BSTR bstrName
, DWORD grfdex
)
1674 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1675 dispex_prop_t
*prop
;
1679 TRACE("(%p)->(%s %lx)\n", This
, debugstr_w(bstrName
), grfdex
);
1681 if(grfdex
& ~(fdexNameCaseSensitive
|fdexNameEnsure
|fdexNameImplicit
|FDEX_VERSION_MASK
))
1682 FIXME("Unsupported grfdex %lx\n", grfdex
);
1684 hres
= find_prop_name(This
, string_hash(bstrName
), bstrName
, &prop
);
1688 TRACE("not found\n");
1692 return delete_prop(prop
, &b
);
1695 static HRESULT WINAPI
DispatchEx_DeleteMemberByDispID(IDispatchEx
*iface
, DISPID id
)
1697 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1698 dispex_prop_t
*prop
;
1701 TRACE("(%p)->(%lx)\n", This
, id
);
1703 prop
= get_prop(This
, id
);
1705 WARN("invalid id\n");
1706 return DISP_E_MEMBERNOTFOUND
;
1709 return delete_prop(prop
, &b
);
1712 static HRESULT WINAPI
DispatchEx_GetMemberProperties(IDispatchEx
*iface
, DISPID id
, DWORD grfdexFetch
, DWORD
*pgrfdex
)
1714 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1715 FIXME("(%p)->(%lx %lx %p)\n", This
, id
, grfdexFetch
, pgrfdex
);
1719 static HRESULT WINAPI
DispatchEx_GetMemberName(IDispatchEx
*iface
, DISPID id
, BSTR
*pbstrName
)
1721 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1722 dispex_prop_t
*prop
;
1724 TRACE("(%p)->(%lx %p)\n", This
, id
, pbstrName
);
1726 prop
= get_prop(This
, id
);
1728 return DISP_E_MEMBERNOTFOUND
;
1730 *pbstrName
= SysAllocString(prop
->name
);
1732 return E_OUTOFMEMORY
;
1737 static HRESULT WINAPI
DispatchEx_GetNextDispID(IDispatchEx
*iface
, DWORD grfdex
, DISPID id
, DISPID
*pid
)
1739 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1740 HRESULT hres
= S_FALSE
;
1742 TRACE("(%p)->(%lx %lx %p)\n", This
, grfdex
, id
, pid
);
1744 if(id
!= DISPID_VALUE
)
1745 hres
= jsdisp_next_prop(This
, id
, JSDISP_ENUM_ALL
, pid
);
1747 *pid
= DISPID_STARTENUM
;
1751 static HRESULT WINAPI
DispatchEx_GetNameSpaceParent(IDispatchEx
*iface
, IUnknown
**ppunk
)
1753 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1754 FIXME("(%p)->(%p)\n", This
, ppunk
);
1758 static IDispatchExVtbl DispatchExVtbl
= {
1759 DispatchEx_QueryInterface
,
1762 DispatchEx_GetTypeInfoCount
,
1763 DispatchEx_GetTypeInfo
,
1764 DispatchEx_GetIDsOfNames
,
1766 DispatchEx_GetDispID
,
1767 DispatchEx_InvokeEx
,
1768 DispatchEx_DeleteMemberByName
,
1769 DispatchEx_DeleteMemberByDispID
,
1770 DispatchEx_GetMemberProperties
,
1771 DispatchEx_GetMemberName
,
1772 DispatchEx_GetNextDispID
,
1773 DispatchEx_GetNameSpaceParent
1776 jsdisp_t
*as_jsdisp(IDispatch
*disp
)
1778 assert(disp
->lpVtbl
== (IDispatchVtbl
*)&DispatchExVtbl
);
1779 return impl_from_IDispatchEx((IDispatchEx
*)disp
);
1782 jsdisp_t
*to_jsdisp(IDispatch
*disp
)
1784 return disp
->lpVtbl
== (IDispatchVtbl
*)&DispatchExVtbl
? impl_from_IDispatchEx((IDispatchEx
*)disp
) : NULL
;
1787 HRESULT
init_dispex(jsdisp_t
*dispex
, script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*prototype
)
1791 TRACE("%p (%p)\n", dispex
, prototype
);
1793 dispex
->IDispatchEx_iface
.lpVtbl
= &DispatchExVtbl
;
1795 dispex
->builtin_info
= builtin_info
;
1796 dispex
->extensible
= TRUE
;
1797 dispex
->prop_cnt
= 0;
1799 dispex
->props
= heap_alloc_zero(sizeof(dispex_prop_t
)*(dispex
->buf_size
=4));
1801 return E_OUTOFMEMORY
;
1803 for(i
= 0; i
< dispex
->buf_size
; i
++) {
1804 dispex
->props
[i
].bucket_head
= ~0;
1805 dispex
->props
[i
].bucket_next
= ~0;
1808 dispex
->prototype
= prototype
;
1810 jsdisp_addref(prototype
);
1818 static const builtin_info_t dispex_info
= {
1826 HRESULT
create_dispex(script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*prototype
, jsdisp_t
**dispex
)
1831 ret
= heap_alloc_zero(sizeof(jsdisp_t
));
1833 return E_OUTOFMEMORY
;
1835 hres
= init_dispex(ret
, ctx
, builtin_info
? builtin_info
: &dispex_info
, prototype
);
1845 void jsdisp_free(jsdisp_t
*obj
)
1847 dispex_prop_t
*prop
;
1849 TRACE("(%p)\n", obj
);
1851 for(prop
= obj
->props
; prop
< obj
->props
+obj
->prop_cnt
; prop
++) {
1852 switch(prop
->type
) {
1854 jsval_release(prop
->u
.val
);
1857 if(prop
->u
.accessor
.getter
)
1858 jsdisp_release(prop
->u
.accessor
.getter
);
1859 if(prop
->u
.accessor
.setter
)
1860 jsdisp_release(prop
->u
.accessor
.setter
);
1865 heap_free(prop
->name
);
1867 heap_free(obj
->props
);
1868 script_release(obj
->ctx
);
1870 jsdisp_release(obj
->prototype
);
1872 if(obj
->builtin_info
->destructor
)
1873 obj
->builtin_info
->destructor(obj
);
1880 jsdisp_t
*jsdisp_addref(jsdisp_t
*jsdisp
)
1882 ULONG ref
= ++jsdisp
->ref
;
1883 TRACE("(%p) ref=%d\n", jsdisp
, ref
);
1887 void jsdisp_release(jsdisp_t
*jsdisp
)
1889 ULONG ref
= --jsdisp
->ref
;
1891 TRACE("(%p) ref=%d\n", jsdisp
, ref
);
1894 jsdisp_free(jsdisp
);
1899 HRESULT
init_dispex_from_constr(jsdisp_t
*dispex
, script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*constr
)
1901 jsdisp_t
*prot
= NULL
;
1902 dispex_prop_t
*prop
;
1905 hres
= find_prop_name_prot(constr
, string_hash(L
"prototype"), L
"prototype", &prop
);
1906 if(SUCCEEDED(hres
) && prop
&& prop
->type
!=PROP_DELETED
) {
1909 hres
= prop_get(constr
, prop
, &val
);
1911 ERR("Could not get prototype\n");
1915 if(is_object_instance(val
))
1916 prot
= iface_to_jsdisp(get_object(val
));
1918 prot
= jsdisp_addref(ctx
->object_prototype
);
1923 hres
= init_dispex(dispex
, ctx
, builtin_info
, prot
);
1926 jsdisp_release(prot
);
1930 jsdisp_t
*iface_to_jsdisp(IDispatch
*iface
)
1932 return iface
->lpVtbl
== (const IDispatchVtbl
*)&DispatchExVtbl
1933 ? jsdisp_addref( impl_from_IDispatchEx((IDispatchEx
*)iface
))
1937 HRESULT
jsdisp_get_id(jsdisp_t
*jsdisp
, const WCHAR
*name
, DWORD flags
, DISPID
*id
)
1939 dispex_prop_t
*prop
;
1942 if(jsdisp
->extensible
&& (flags
& fdexNameEnsure
))
1943 hres
= ensure_prop_name(jsdisp
, name
, PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
,
1946 hres
= find_prop_name_prot(jsdisp
, string_hash(name
), name
, &prop
);
1950 if(prop
&& prop
->type
!=PROP_DELETED
) {
1951 *id
= prop_to_id(jsdisp
, prop
);
1955 TRACE("not found %s\n", debugstr_w(name
));
1956 *id
= DISPID_UNKNOWN
;
1957 return DISP_E_UNKNOWNNAME
;
1960 HRESULT
jsdisp_call_value(jsdisp_t
*jsfunc
, IDispatch
*jsthis
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1964 assert(!(flags
& ~(DISPATCH_METHOD
|DISPATCH_CONSTRUCT
|DISPATCH_JSCRIPT_INTERNAL_MASK
)));
1966 if(is_class(jsfunc
, JSCLASS_FUNCTION
)) {
1967 hres
= Function_invoke(jsfunc
, jsthis
, flags
, argc
, argv
, r
);
1969 if(!jsfunc
->builtin_info
->call
) {
1970 WARN("Not a function\n");
1971 return JS_E_FUNCTION_EXPECTED
;
1974 if(jsfunc
->ctx
->state
== SCRIPTSTATE_UNINITIALIZED
|| jsfunc
->ctx
->state
== SCRIPTSTATE_CLOSED
)
1975 return E_UNEXPECTED
;
1977 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
1978 hres
= jsfunc
->builtin_info
->call(jsfunc
->ctx
, jsthis
? jsval_disp(jsthis
) : jsval_null(), flags
, argc
, argv
, r
);
1983 HRESULT
jsdisp_call(jsdisp_t
*disp
, DISPID id
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1985 dispex_prop_t
*prop
;
1987 prop
= get_prop(disp
, id
);
1989 return DISP_E_MEMBERNOTFOUND
;
1991 return invoke_prop_func(disp
, to_disp(disp
), prop
, flags
, argc
, argv
, r
, NULL
);
1994 HRESULT
jsdisp_call_name(jsdisp_t
*disp
, const WCHAR
*name
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1996 dispex_prop_t
*prop
;
1999 hres
= find_prop_name_prot(disp
, string_hash(name
), name
, &prop
);
2003 if(!prop
|| prop
->type
== PROP_DELETED
)
2004 return JS_E_INVALID_PROPERTY
;
2006 return invoke_prop_func(disp
, to_disp(disp
), prop
, flags
, argc
, argv
, r
, NULL
);
2009 static HRESULT
disp_invoke(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, WORD flags
, DISPPARAMS
*params
, VARIANT
*r
)
2011 IDispatchEx
*dispex
;
2015 memset(&ei
, 0, sizeof(ei
));
2016 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2017 if(SUCCEEDED(hres
)) {
2018 hres
= IDispatchEx_InvokeEx(dispex
, id
, ctx
->lcid
, flags
, params
, r
, &ei
, &ctx
->jscaller
->IServiceProvider_iface
);
2019 IDispatchEx_Release(dispex
);
2023 if(flags
== DISPATCH_CONSTRUCT
) {
2024 WARN("IDispatch cannot be constructor\n");
2025 return DISP_E_MEMBERNOTFOUND
;
2028 if(params
->cNamedArgs
== 1 && params
->rgdispidNamedArgs
[0] == DISPID_THIS
) {
2029 params
->cNamedArgs
= 0;
2030 params
->rgdispidNamedArgs
= NULL
;
2035 TRACE("using IDispatch\n");
2036 hres
= IDispatch_Invoke(disp
, id
, &IID_NULL
, ctx
->lcid
, flags
, params
, r
, &ei
, &err
);
2039 if(hres
== DISP_E_EXCEPTION
) {
2040 TRACE("DISP_E_EXCEPTION: %08lx %s %s\n", ei
.scode
, debugstr_w(ei
.bstrSource
), debugstr_w(ei
.bstrDescription
));
2042 ctx
->ei
->error
= (SUCCEEDED(ei
.scode
) || ei
.scode
== DISP_E_EXCEPTION
) ? E_FAIL
: ei
.scode
;
2044 ctx
->ei
->source
= jsstr_alloc_len(ei
.bstrSource
, SysStringLen(ei
.bstrSource
));
2045 if(ei
.bstrDescription
)
2046 ctx
->ei
->message
= jsstr_alloc_len(ei
.bstrDescription
, SysStringLen(ei
.bstrDescription
));
2047 SysFreeString(ei
.bstrSource
);
2048 SysFreeString(ei
.bstrDescription
);
2049 SysFreeString(ei
.bstrHelpFile
);
2055 HRESULT
disp_call(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*ret
)
2057 VARIANT buf
[6], retv
;
2063 jsdisp
= iface_to_jsdisp(disp
);
2064 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2065 if(flags
& DISPATCH_PROPERTYPUT
) {
2066 FIXME("disp_call(propput) on builtin object\n");
2067 jsdisp_release(jsdisp
);
2071 if(ctx
!= jsdisp
->ctx
)
2072 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
2073 hres
= jsdisp_call(jsdisp
, id
, flags
, argc
, argv
, ret
);
2074 jsdisp_release(jsdisp
);
2078 jsdisp_release(jsdisp
);
2080 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
2082 flags
|= DISPATCH_PROPERTYGET
;
2086 if(flags
& DISPATCH_PROPERTYPUT
) {
2087 static DISPID propput_dispid
= DISPID_PROPERTYPUT
;
2090 dp
.rgdispidNamedArgs
= &propput_dispid
;
2093 dp
.rgdispidNamedArgs
= NULL
;
2096 if(dp
.cArgs
> ARRAY_SIZE(buf
)) {
2097 dp
.rgvarg
= heap_alloc(argc
*sizeof(VARIANT
));
2099 return E_OUTOFMEMORY
;
2104 for(i
=0; i
<argc
; i
++) {
2105 hres
= jsval_to_variant(argv
[i
], dp
.rgvarg
+argc
-i
-1);
2108 VariantClear(dp
.rgvarg
+argc
-i
-1);
2109 if(dp
.rgvarg
!= buf
)
2110 heap_free(dp
.rgvarg
);
2115 V_VT(&retv
) = VT_EMPTY
;
2116 hres
= disp_invoke(ctx
, disp
, id
, flags
, &dp
, ret
? &retv
: NULL
);
2118 for(i
=0; i
<argc
; i
++)
2119 VariantClear(dp
.rgvarg
+argc
-i
-1);
2120 if(dp
.rgvarg
!= buf
)
2121 heap_free(dp
.rgvarg
);
2123 if(SUCCEEDED(hres
) && ret
)
2124 hres
= variant_to_jsval(ctx
, &retv
, ret
);
2125 VariantClear(&retv
);
2129 HRESULT
disp_call_name(script_ctx_t
*ctx
, IDispatch
*disp
, const WCHAR
*name
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*ret
)
2131 IDispatchEx
*dispex
;
2137 if((jsdisp
= to_jsdisp(disp
)) && jsdisp
->ctx
== ctx
)
2138 return jsdisp_call_name(jsdisp
, name
, flags
, argc
, argv
, ret
);
2140 if(!(bstr
= SysAllocString(name
)))
2141 return E_OUTOFMEMORY
;
2142 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2143 if(SUCCEEDED(hres
) && dispex
) {
2144 hres
= IDispatchEx_GetDispID(dispex
, bstr
, make_grfdex(ctx
, fdexNameCaseSensitive
), &id
);
2145 IDispatchEx_Release(dispex
);
2147 hres
= IDispatch_GetIDsOfNames(disp
, &IID_NULL
, &bstr
, 1, 0, &id
);
2149 SysFreeString(bstr
);
2153 return disp_call(ctx
, disp
, id
, flags
, argc
, argv
, ret
);
2156 HRESULT
disp_call_value(script_ctx_t
*ctx
, IDispatch
*disp
, IDispatch
*jsthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
2159 VARIANT buf
[6], retv
, *args
= buf
;
2163 HRESULT hres
= S_OK
;
2165 static DISPID this_id
= DISPID_THIS
;
2167 assert(!(flags
& ~(DISPATCH_METHOD
|DISPATCH_CONSTRUCT
|DISPATCH_JSCRIPT_INTERNAL_MASK
)));
2169 jsdisp
= iface_to_jsdisp(disp
);
2170 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2171 hres
= jsdisp_call_value(jsdisp
, jsthis
, flags
, argc
, argv
, r
);
2172 jsdisp_release(jsdisp
);
2176 jsdisp_release(jsdisp
);
2178 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
2179 if(r
&& argc
&& flags
== DISPATCH_METHOD
)
2180 flags
|= DISPATCH_PROPERTYGET
;
2183 dp
.cArgs
= argc
+ 1;
2185 dp
.rgdispidNamedArgs
= &this_id
;
2189 dp
.rgdispidNamedArgs
= NULL
;
2192 if(dp
.cArgs
> ARRAY_SIZE(buf
) && !(args
= heap_alloc(dp
.cArgs
* sizeof(VARIANT
))))
2193 return E_OUTOFMEMORY
;
2197 V_VT(dp
.rgvarg
) = VT_DISPATCH
;
2198 V_DISPATCH(dp
.rgvarg
) = jsthis
;
2201 for(i
=0; SUCCEEDED(hres
) && i
< argc
; i
++)
2202 hres
= jsval_to_variant(argv
[i
], dp
.rgvarg
+dp
.cArgs
-i
-1);
2204 if(SUCCEEDED(hres
)) {
2205 V_VT(&retv
) = VT_EMPTY
;
2206 hres
= disp_invoke(ctx
, disp
, DISPID_VALUE
, flags
, &dp
, r
? &retv
: NULL
);
2209 for(i
= 0; i
< argc
; i
++)
2210 VariantClear(dp
.rgvarg
+ dp
.cArgs
- i
- 1);
2219 hres
= variant_to_jsval(ctx
, &retv
, r
);
2220 VariantClear(&retv
);
2224 HRESULT
jsdisp_propput(jsdisp_t
*obj
, const WCHAR
*name
, DWORD flags
, BOOL
throw, jsval_t val
)
2226 dispex_prop_t
*prop
;
2230 hres
= ensure_prop_name(obj
, name
, flags
, &prop
);
2232 hres
= find_prop_name(obj
, string_hash(name
), name
, &prop
);
2235 if(!prop
|| (prop
->type
== PROP_DELETED
&& !obj
->extensible
))
2236 return throw ? JS_E_INVALID_ACTION
: S_OK
;
2238 return prop_put(obj
, prop
, val
);
2241 HRESULT
jsdisp_propput_name(jsdisp_t
*obj
, const WCHAR
*name
, jsval_t val
)
2243 return jsdisp_propput(obj
, name
, PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
, FALSE
, val
);
2246 HRESULT
jsdisp_propput_idx(jsdisp_t
*obj
, DWORD idx
, jsval_t val
)
2250 swprintf(buf
, ARRAY_SIZE(buf
), L
"%d", idx
);
2251 return jsdisp_propput(obj
, buf
, PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
, TRUE
, val
);
2254 HRESULT
disp_propput(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, jsval_t val
)
2259 jsdisp
= iface_to_jsdisp(disp
);
2260 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2261 dispex_prop_t
*prop
;
2263 prop
= get_prop(jsdisp
, id
);
2265 hres
= prop_put(jsdisp
, prop
, val
);
2267 hres
= DISP_E_MEMBERNOTFOUND
;
2269 jsdisp_release(jsdisp
);
2271 DISPID dispid
= DISPID_PROPERTYPUT
;
2272 DWORD flags
= DISPATCH_PROPERTYPUT
;
2274 DISPPARAMS dp
= {&var
, &dispid
, 1, 1};
2277 jsdisp_release(jsdisp
);
2278 hres
= jsval_to_variant(val
, &var
);
2282 if(V_VT(&var
) == VT_DISPATCH
)
2283 flags
|= DISPATCH_PROPERTYPUTREF
;
2285 hres
= disp_invoke(ctx
, disp
, id
, flags
, &dp
, NULL
);
2292 HRESULT
disp_propput_name(script_ctx_t
*ctx
, IDispatch
*disp
, const WCHAR
*name
, jsval_t val
)
2297 jsdisp
= iface_to_jsdisp(disp
);
2298 if(!jsdisp
|| jsdisp
->ctx
!= ctx
) {
2299 IDispatchEx
*dispex
;
2304 jsdisp_release(jsdisp
);
2305 if(!(str
= SysAllocString(name
)))
2306 return E_OUTOFMEMORY
;
2308 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2309 if(SUCCEEDED(hres
)) {
2310 hres
= IDispatchEx_GetDispID(dispex
, str
, make_grfdex(ctx
, fdexNameEnsure
|fdexNameCaseSensitive
), &id
);
2311 IDispatchEx_Release(dispex
);
2313 TRACE("using IDispatch\n");
2314 hres
= IDispatch_GetIDsOfNames(disp
, &IID_NULL
, &str
, 1, 0, &id
);
2320 return disp_propput(ctx
, disp
, id
, val
);
2323 hres
= jsdisp_propput_name(jsdisp
, name
, val
);
2324 jsdisp_release(jsdisp
);
2328 HRESULT
jsdisp_propget_name(jsdisp_t
*obj
, const WCHAR
*name
, jsval_t
*val
)
2330 dispex_prop_t
*prop
;
2333 hres
= find_prop_name_prot(obj
, string_hash(name
), name
, &prop
);
2337 if(!prop
|| prop
->type
==PROP_DELETED
) {
2338 *val
= jsval_undefined();
2342 return prop_get(obj
, prop
, val
);
2345 HRESULT
jsdisp_get_idx(jsdisp_t
*obj
, DWORD idx
, jsval_t
*r
)
2348 dispex_prop_t
*prop
;
2351 swprintf(name
, ARRAY_SIZE(name
), L
"%d", idx
);
2353 hres
= find_prop_name_prot(obj
, string_hash(name
), name
, &prop
);
2357 if(!prop
|| prop
->type
==PROP_DELETED
) {
2358 *r
= jsval_undefined();
2359 return DISP_E_UNKNOWNNAME
;
2362 return prop_get(obj
, prop
, r
);
2365 HRESULT
jsdisp_propget(jsdisp_t
*jsdisp
, DISPID id
, jsval_t
*val
)
2367 dispex_prop_t
*prop
;
2369 prop
= get_prop(jsdisp
, id
);
2371 return DISP_E_MEMBERNOTFOUND
;
2373 return prop_get(jsdisp
, prop
, val
);
2376 HRESULT
disp_propget(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, jsval_t
*val
)
2378 DISPPARAMS dp
= {NULL
,NULL
,0,0};
2383 jsdisp
= iface_to_jsdisp(disp
);
2384 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2385 hres
= jsdisp_propget(jsdisp
, id
, val
);
2386 jsdisp_release(jsdisp
);
2390 jsdisp_release(jsdisp
);
2392 V_VT(&var
) = VT_EMPTY
;
2393 hres
= disp_invoke(ctx
, disp
, id
, INVOKE_PROPERTYGET
, &dp
, &var
);
2394 if(SUCCEEDED(hres
)) {
2395 hres
= variant_to_jsval(ctx
, &var
, val
);
2401 HRESULT
jsdisp_delete_idx(jsdisp_t
*obj
, DWORD idx
)
2404 dispex_prop_t
*prop
;
2408 swprintf(buf
, ARRAY_SIZE(buf
), L
"%d", idx
);
2410 hres
= find_prop_name(obj
, string_hash(buf
), buf
, &prop
);
2411 if(FAILED(hres
) || !prop
)
2414 hres
= delete_prop(prop
, &b
);
2417 return b
? S_OK
: JS_E_INVALID_ACTION
;
2420 HRESULT
disp_delete(IDispatch
*disp
, DISPID id
, BOOL
*ret
)
2422 IDispatchEx
*dispex
;
2426 jsdisp
= iface_to_jsdisp(disp
);
2428 dispex_prop_t
*prop
;
2430 prop
= get_prop(jsdisp
, id
);
2432 hres
= delete_prop(prop
, ret
);
2434 hres
= DISP_E_MEMBERNOTFOUND
;
2436 jsdisp_release(jsdisp
);
2440 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2446 hres
= IDispatchEx_DeleteMemberByDispID(dispex
, id
);
2447 IDispatchEx_Release(dispex
);
2451 *ret
= hres
== S_OK
;
2455 HRESULT
jsdisp_next_prop(jsdisp_t
*obj
, DISPID id
, enum jsdisp_enum_type enum_type
, DISPID
*ret
)
2457 dispex_prop_t
*iter
;
2461 if(id
== DISPID_STARTENUM
) {
2462 if(obj
->builtin_info
->idx_length
) {
2463 unsigned i
= 0, len
= obj
->builtin_info
->idx_length(obj
);
2466 for(i
= 0; i
< len
; i
++) {
2467 swprintf(name
, ARRAY_SIZE(name
), L
"%d", i
);
2468 hres
= find_prop_name(obj
, string_hash(name
), name
, &iter
);
2474 if (enum_type
== JSDISP_ENUM_ALL
) {
2475 hres
= fill_protrefs(obj
);
2482 if(idx
>= obj
->prop_cnt
)
2485 for(iter
= &obj
->props
[idx
]; iter
< obj
->props
+ obj
->prop_cnt
; iter
++) {
2486 if(iter
->type
== PROP_DELETED
)
2488 if(enum_type
!= JSDISP_ENUM_ALL
&& iter
->type
== PROP_PROTREF
)
2490 if(enum_type
!= JSDISP_ENUM_OWN
&& !(get_flags(obj
, iter
) & PROPF_ENUMERABLE
))
2492 *ret
= prop_to_id(obj
, iter
);
2499 HRESULT
disp_delete_name(script_ctx_t
*ctx
, IDispatch
*disp
, jsstr_t
*name
, BOOL
*ret
)
2501 IDispatchEx
*dispex
;
2506 jsdisp
= iface_to_jsdisp(disp
);
2508 dispex_prop_t
*prop
;
2511 ptr
= jsstr_flatten(name
);
2513 jsdisp_release(jsdisp
);
2514 return E_OUTOFMEMORY
;
2517 hres
= find_prop_name(jsdisp
, string_hash(ptr
), ptr
, &prop
);
2519 hres
= delete_prop(prop
, ret
);
2525 jsdisp_release(jsdisp
);
2529 bstr
= SysAllocStringLen(NULL
, jsstr_length(name
));
2531 return E_OUTOFMEMORY
;
2532 jsstr_flush(name
, bstr
);
2534 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2535 if(SUCCEEDED(hres
)) {
2536 hres
= IDispatchEx_DeleteMemberByName(dispex
, bstr
, make_grfdex(ctx
, fdexNameCaseSensitive
));
2538 *ret
= hres
== S_OK
;
2539 IDispatchEx_Release(dispex
);
2543 hres
= IDispatch_GetIDsOfNames(disp
, &IID_NULL
, &bstr
, 1, 0, &id
);
2544 if(SUCCEEDED(hres
)) {
2545 /* Property exists and we can't delete it from pure IDispatch interface, so return false. */
2547 }else if(hres
== DISP_E_UNKNOWNNAME
) {
2548 /* Property doesn't exist, so nothing to delete */
2554 SysFreeString(bstr
);
2558 HRESULT
jsdisp_get_own_property(jsdisp_t
*obj
, const WCHAR
*name
, BOOL flags_only
,
2559 property_desc_t
*desc
)
2561 dispex_prop_t
*prop
;
2564 hres
= find_prop_name(obj
, string_hash(name
), name
, &prop
);
2569 return DISP_E_UNKNOWNNAME
;
2571 memset(desc
, 0, sizeof(*desc
));
2573 switch(prop
->type
) {
2577 desc
->mask
|= PROPF_WRITABLE
;
2578 desc
->explicit_value
= TRUE
;
2580 hres
= prop_get(obj
, prop
, &desc
->value
);
2586 desc
->explicit_getter
= desc
->explicit_setter
= TRUE
;
2588 desc
->getter
= prop
->u
.accessor
.getter
2589 ? jsdisp_addref(prop
->u
.accessor
.getter
) : NULL
;
2590 desc
->setter
= prop
->u
.accessor
.setter
2591 ? jsdisp_addref(prop
->u
.accessor
.setter
) : NULL
;
2595 return DISP_E_UNKNOWNNAME
;
2598 desc
->flags
= prop
->flags
& (PROPF_ENUMERABLE
| PROPF_WRITABLE
| PROPF_CONFIGURABLE
);
2599 desc
->mask
|= PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
;
2603 HRESULT
jsdisp_define_property(jsdisp_t
*obj
, const WCHAR
*name
, property_desc_t
*desc
)
2605 dispex_prop_t
*prop
;
2608 hres
= find_prop_name(obj
, string_hash(name
), name
, &prop
);
2612 if((!prop
|| prop
->type
== PROP_DELETED
|| prop
->type
== PROP_PROTREF
) && !obj
->extensible
)
2613 return throw_error(obj
->ctx
, JS_E_OBJECT_NONEXTENSIBLE
, name
);
2615 if(!prop
&& !(prop
= alloc_prop(obj
, name
, PROP_DELETED
, 0)))
2616 return E_OUTOFMEMORY
;
2618 if(prop
->type
== PROP_DELETED
|| prop
->type
== PROP_PROTREF
) {
2619 prop
->flags
= desc
->flags
;
2620 if(desc
->explicit_getter
|| desc
->explicit_setter
) {
2621 prop
->type
= PROP_ACCESSOR
;
2622 prop
->u
.accessor
.getter
= desc
->getter
? jsdisp_addref(desc
->getter
) : NULL
;
2623 prop
->u
.accessor
.setter
= desc
->setter
? jsdisp_addref(desc
->setter
) : NULL
;
2624 TRACE("%s = accessor { get: %p set: %p }\n", debugstr_w(name
),
2625 prop
->u
.accessor
.getter
, prop
->u
.accessor
.setter
);
2627 prop
->type
= PROP_JSVAL
;
2628 if(desc
->explicit_value
) {
2629 hres
= jsval_copy(desc
->value
, &prop
->u
.val
);
2633 prop
->u
.val
= jsval_undefined();
2635 TRACE("%s = %s\n", debugstr_w(name
), debugstr_jsval(prop
->u
.val
));
2640 TRACE("existing prop %s prop flags %lx desc flags %x desc mask %x\n", debugstr_w(name
),
2641 prop
->flags
, desc
->flags
, desc
->mask
);
2643 if(!(prop
->flags
& PROPF_CONFIGURABLE
)) {
2644 if(((desc
->mask
& PROPF_CONFIGURABLE
) && (desc
->flags
& PROPF_CONFIGURABLE
))
2645 || ((desc
->mask
& PROPF_ENUMERABLE
)
2646 && ((desc
->flags
& PROPF_ENUMERABLE
) != (prop
->flags
& PROPF_ENUMERABLE
))))
2647 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
2650 if(desc
->explicit_value
|| (desc
->mask
& PROPF_WRITABLE
)) {
2651 if(prop
->type
== PROP_ACCESSOR
) {
2652 if(!(prop
->flags
& PROPF_CONFIGURABLE
))
2653 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
2654 if(prop
->u
.accessor
.getter
)
2655 jsdisp_release(prop
->u
.accessor
.getter
);
2656 if(prop
->u
.accessor
.setter
)
2657 jsdisp_release(prop
->u
.accessor
.setter
);
2659 prop
->type
= PROP_JSVAL
;
2660 hres
= jsval_copy(desc
->value
, &prop
->u
.val
);
2662 prop
->u
.val
= jsval_undefined();
2666 if(!(prop
->flags
& PROPF_CONFIGURABLE
) && !(prop
->flags
& PROPF_WRITABLE
)) {
2667 if((desc
->mask
& PROPF_WRITABLE
) && (desc
->flags
& PROPF_WRITABLE
))
2668 return throw_error(obj
->ctx
, JS_E_NONWRITABLE_MODIFIED
, name
);
2669 if(desc
->explicit_value
) {
2670 if(prop
->type
== PROP_JSVAL
) {
2672 hres
= jsval_strict_equal(desc
->value
, prop
->u
.val
, &eq
);
2676 return throw_error(obj
->ctx
, JS_E_NONWRITABLE_MODIFIED
, name
);
2678 FIXME("redefinition of property type %d\n", prop
->type
);
2682 if(desc
->explicit_value
) {
2683 if(prop
->type
== PROP_JSVAL
)
2684 jsval_release(prop
->u
.val
);
2686 prop
->type
= PROP_JSVAL
;
2687 hres
= jsval_copy(desc
->value
, &prop
->u
.val
);
2689 prop
->u
.val
= jsval_undefined();
2694 }else if(desc
->explicit_getter
|| desc
->explicit_setter
) {
2695 if(prop
->type
!= PROP_ACCESSOR
) {
2696 if(!(prop
->flags
& PROPF_CONFIGURABLE
))
2697 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
2698 if(prop
->type
== PROP_JSVAL
)
2699 jsval_release(prop
->u
.val
);
2700 prop
->type
= PROP_ACCESSOR
;
2701 prop
->u
.accessor
.getter
= prop
->u
.accessor
.setter
= NULL
;
2702 }else if(!(prop
->flags
& PROPF_CONFIGURABLE
)) {
2703 if((desc
->explicit_getter
&& desc
->getter
!= prop
->u
.accessor
.getter
)
2704 || (desc
->explicit_setter
&& desc
->setter
!= prop
->u
.accessor
.setter
))
2705 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
2708 if(desc
->explicit_getter
) {
2709 if(prop
->u
.accessor
.getter
) {
2710 jsdisp_release(prop
->u
.accessor
.getter
);
2711 prop
->u
.accessor
.getter
= NULL
;
2714 prop
->u
.accessor
.getter
= jsdisp_addref(desc
->getter
);
2716 if(desc
->explicit_setter
) {
2717 if(prop
->u
.accessor
.setter
) {
2718 jsdisp_release(prop
->u
.accessor
.setter
);
2719 prop
->u
.accessor
.setter
= NULL
;
2722 prop
->u
.accessor
.setter
= jsdisp_addref(desc
->setter
);
2726 prop
->flags
= (prop
->flags
& ~desc
->mask
) | (desc
->flags
& desc
->mask
);
2730 HRESULT
jsdisp_define_data_property(jsdisp_t
*obj
, const WCHAR
*name
, unsigned flags
, jsval_t value
)
2732 property_desc_t prop_desc
= { flags
, flags
, TRUE
};
2733 prop_desc
.value
= value
;
2734 return jsdisp_define_property(obj
, name
, &prop_desc
);
2737 HRESULT
jsdisp_change_prototype(jsdisp_t
*obj
, jsdisp_t
*proto
)
2742 if(obj
->prototype
== proto
)
2744 if(!obj
->extensible
)
2745 return JS_E_CANNOT_CREATE_FOR_NONEXTENSIBLE
;
2747 for(iter
= proto
; iter
; iter
= iter
->prototype
)
2749 return JS_E_CYCLIC_PROTO_VALUE
;
2751 if(obj
->prototype
) {
2752 for(i
= 0; i
< obj
->prop_cnt
; i
++)
2753 if(obj
->props
[i
].type
== PROP_PROTREF
)
2754 obj
->props
[i
].type
= PROP_DELETED
;
2755 jsdisp_release(obj
->prototype
);
2758 obj
->prototype
= proto
;
2760 jsdisp_addref(proto
);
2764 void jsdisp_freeze(jsdisp_t
*obj
, BOOL seal
)
2768 for(i
= 0; i
< obj
->prop_cnt
; i
++) {
2769 if(!seal
&& obj
->props
[i
].type
== PROP_JSVAL
)
2770 obj
->props
[i
].flags
&= ~PROPF_WRITABLE
;
2771 obj
->props
[i
].flags
&= ~PROPF_CONFIGURABLE
;
2774 obj
->extensible
= FALSE
;
2777 BOOL
jsdisp_is_frozen(jsdisp_t
*obj
, BOOL sealed
)
2784 for(i
= 0; i
< obj
->prop_cnt
; i
++) {
2785 if(obj
->props
[i
].type
== PROP_JSVAL
) {
2786 if(!sealed
&& (obj
->props
[i
].flags
& PROPF_WRITABLE
))
2788 }else if(obj
->props
[i
].type
!= PROP_ACCESSOR
)
2790 if(obj
->props
[i
].flags
& PROPF_CONFIGURABLE
)
2797 HRESULT
jsdisp_get_prop_name(jsdisp_t
*obj
, DISPID id
, jsstr_t
**r
)
2799 dispex_prop_t
*prop
= get_prop(obj
, id
);
2802 return DISP_E_MEMBERNOTFOUND
;
2804 *r
= jsstr_alloc(prop
->name
);
2805 return *r
? S_OK
: E_OUTOFMEMORY
;