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 inline DISPID
prop_to_id(jsdisp_t
*This
, dispex_prop_t
*prop
)
65 return prop
- This
->props
;
68 static inline dispex_prop_t
*get_prop(jsdisp_t
*This
, DISPID id
)
70 if(id
< 0 || id
>= This
->prop_cnt
|| This
->props
[id
].type
== PROP_DELETED
)
73 return This
->props
+id
;
76 static inline BOOL
is_function_prop(dispex_prop_t
*prop
)
80 if (is_object_instance(prop
->u
.val
))
82 jsdisp_t
*jsdisp
= iface_to_jsdisp(get_object(prop
->u
.val
));
84 if (jsdisp
) ret
= is_class(jsdisp
, JSCLASS_FUNCTION
);
85 jsdisp_release(jsdisp
);
90 static DWORD
get_flags(jsdisp_t
*This
, dispex_prop_t
*prop
)
92 if(prop
->type
== PROP_PROTREF
) {
93 dispex_prop_t
*parent
= get_prop(This
->prototype
, prop
->u
.ref
);
95 prop
->type
= PROP_DELETED
;
99 return get_flags(This
->prototype
, parent
);
105 static const builtin_prop_t
*find_builtin_prop(jsdisp_t
*This
, const WCHAR
*name
)
107 int min
= 0, max
, i
, r
;
109 max
= This
->builtin_info
->props_cnt
-1;
113 r
= wcscmp(name
, This
->builtin_info
->props
[i
].name
);
115 /* Skip prop if it's available only in higher compatibility mode. */
116 unsigned version
= (This
->builtin_info
->props
[i
].flags
& PROPF_VERSION_MASK
)
117 >> PROPF_VERSION_SHIFT
;
118 if(version
&& version
> This
->ctx
->version
)
121 /* Skip prop if it's available only in HTML mode and we're not running in HTML mode. */
122 if((This
->builtin_info
->props
[i
].flags
& PROPF_HTML
) && !This
->ctx
->html_mode
)
125 return This
->builtin_info
->props
+ i
;
137 static inline unsigned string_hash(const WCHAR
*name
)
141 h
= (h
>>(sizeof(unsigned)*8-4)) ^ (h
<<4) ^ towlower(*name
);
145 static inline unsigned get_props_idx(jsdisp_t
*This
, unsigned hash
)
147 return (hash
*GOLDEN_RATIO
) & (This
->buf_size
-1);
150 static inline HRESULT
resize_props(jsdisp_t
*This
)
152 dispex_prop_t
*props
;
155 if(This
->buf_size
!= This
->prop_cnt
)
158 props
= heap_realloc(This
->props
, sizeof(dispex_prop_t
)*This
->buf_size
*2);
160 return E_OUTOFMEMORY
;
164 for(i
=0; i
<This
->buf_size
; i
++) {
165 This
->props
[i
].bucket_head
= 0;
166 This
->props
[i
].bucket_next
= 0;
169 for(i
=1; i
<This
->prop_cnt
; i
++) {
170 props
= This
->props
+i
;
172 bucket
= get_props_idx(This
, props
->hash
);
173 props
->bucket_next
= This
->props
[bucket
].bucket_head
;
174 This
->props
[bucket
].bucket_head
= i
;
180 static inline dispex_prop_t
* alloc_prop(jsdisp_t
*This
, const WCHAR
*name
, prop_type_t type
, DWORD flags
)
185 if(FAILED(resize_props(This
)))
188 prop
= &This
->props
[This
->prop_cnt
];
189 prop
->name
= heap_strdupW(name
);
194 prop
->hash
= string_hash(name
);
196 bucket
= get_props_idx(This
, prop
->hash
);
197 prop
->bucket_next
= This
->props
[bucket
].bucket_head
;
198 This
->props
[bucket
].bucket_head
= This
->prop_cnt
++;
202 static dispex_prop_t
*alloc_protref(jsdisp_t
*This
, const WCHAR
*name
, DWORD ref
)
206 ret
= alloc_prop(This
, name
, PROP_PROTREF
, 0);
214 static HRESULT
find_prop_name(jsdisp_t
*This
, unsigned hash
, const WCHAR
*name
, dispex_prop_t
**ret
)
216 const builtin_prop_t
*builtin
;
217 unsigned bucket
, pos
, prev
= 0;
220 bucket
= get_props_idx(This
, hash
);
221 pos
= This
->props
[bucket
].bucket_head
;
223 if(!wcscmp(name
, This
->props
[pos
].name
)) {
225 This
->props
[prev
].bucket_next
= This
->props
[pos
].bucket_next
;
226 This
->props
[pos
].bucket_next
= This
->props
[bucket
].bucket_head
;
227 This
->props
[bucket
].bucket_head
= pos
;
230 *ret
= &This
->props
[pos
];
235 pos
= This
->props
[pos
].bucket_next
;
238 builtin
= find_builtin_prop(This
, name
);
240 unsigned flags
= builtin
->flags
;
241 if(flags
& PROPF_METHOD
)
242 flags
|= PROPF_WRITABLE
| PROPF_CONFIGURABLE
;
243 else if(builtin
->setter
)
244 flags
|= PROPF_WRITABLE
;
245 flags
&= PROPF_ENUMERABLE
| PROPF_WRITABLE
| PROPF_CONFIGURABLE
;
246 prop
= alloc_prop(This
, name
, PROP_BUILTIN
, flags
);
248 return E_OUTOFMEMORY
;
255 if(This
->builtin_info
->idx_length
) {
259 for(ptr
= name
; is_digit(*ptr
) && idx
< 0x10000; ptr
++)
260 idx
= idx
*10 + (*ptr
-'0');
261 if(!*ptr
&& idx
< This
->builtin_info
->idx_length(This
)) {
262 prop
= alloc_prop(This
, name
, PROP_IDX
, This
->builtin_info
->idx_put
? PROPF_WRITABLE
: 0);
264 return E_OUTOFMEMORY
;
276 static HRESULT
find_prop_name_prot(jsdisp_t
*This
, unsigned hash
, const WCHAR
*name
, dispex_prop_t
**ret
)
278 dispex_prop_t
*prop
, *del
=NULL
;
281 hres
= find_prop_name(This
, hash
, name
, &prop
);
284 if(prop
&& prop
->type
==PROP_DELETED
) {
291 if(This
->prototype
) {
292 hres
= find_prop_name_prot(This
->prototype
, hash
, name
, &prop
);
297 del
->type
= PROP_PROTREF
;
298 del
->u
.ref
= prop
- This
->prototype
->props
;
301 prop
= alloc_protref(This
, prop
->name
, prop
- This
->prototype
->props
);
303 return E_OUTOFMEMORY
;
315 static HRESULT
ensure_prop_name(jsdisp_t
*This
, const WCHAR
*name
, DWORD create_flags
, dispex_prop_t
**ret
)
320 hres
= find_prop_name_prot(This
, string_hash(name
), name
, &prop
);
321 if(SUCCEEDED(hres
) && (!prop
|| prop
->type
== PROP_DELETED
)) {
322 TRACE("creating prop %s flags %x\n", debugstr_w(name
), create_flags
);
325 prop
->type
= PROP_JSVAL
;
326 prop
->flags
= create_flags
;
327 prop
->u
.val
= jsval_undefined();
329 prop
= alloc_prop(This
, name
, PROP_JSVAL
, create_flags
);
331 return E_OUTOFMEMORY
;
334 prop
->u
.val
= jsval_undefined();
341 static IDispatch
*get_this(DISPPARAMS
*dp
)
345 for(i
=0; i
< dp
->cNamedArgs
; i
++) {
346 if(dp
->rgdispidNamedArgs
[i
] == DISPID_THIS
) {
347 if(V_VT(dp
->rgvarg
+i
) == VT_DISPATCH
)
348 return V_DISPATCH(dp
->rgvarg
+i
);
350 WARN("This is not VT_DISPATCH\n");
355 TRACE("no this passed\n");
359 static HRESULT
convert_params(const DISPPARAMS
*dp
, jsval_t
*buf
, unsigned *argc
, jsval_t
**ret
)
366 cnt
= dp
->cArgs
- dp
->cNamedArgs
;
369 argv
= heap_alloc(cnt
* sizeof(*argv
));
371 return E_OUTOFMEMORY
;
376 for(i
= 0; i
< cnt
; i
++) {
377 hres
= variant_to_jsval(dp
->rgvarg
+dp
->cArgs
-i
-1, argv
+i
);
380 jsval_release(argv
[i
]);
392 static HRESULT
prop_get(jsdisp_t
*This
, dispex_prop_t
*prop
, jsval_t
*r
)
394 jsdisp_t
*prop_obj
= This
;
397 while(prop
->type
== PROP_PROTREF
) {
398 prop_obj
= prop_obj
->prototype
;
399 prop
= prop_obj
->props
+ prop
->u
.ref
;
404 if(prop
->u
.p
->getter
) {
405 hres
= prop
->u
.p
->getter(This
->ctx
, This
, r
);
409 assert(prop
->u
.p
->invoke
!= NULL
);
410 hres
= create_builtin_function(This
->ctx
, prop
->u
.p
->invoke
, prop
->u
.p
->name
, NULL
,
411 prop
->u
.p
->flags
, NULL
, &obj
);
415 prop
->type
= PROP_JSVAL
;
416 prop
->u
.val
= jsval_obj(obj
);
423 hres
= jsval_copy(prop
->u
.val
, r
);
426 if(prop
->u
.accessor
.getter
) {
427 hres
= jsdisp_call_value(prop
->u
.accessor
.getter
, to_disp(This
),
428 DISPATCH_METHOD
, 0, NULL
, r
);
430 *r
= jsval_undefined();
435 hres
= prop_obj
->builtin_info
->idx_get(prop_obj
, prop
->u
.idx
, r
);
438 ERR("type %d\n", prop
->type
);
443 TRACE("fail %08x\n", hres
);
447 TRACE("%p.%s ret %s\n", This
, debugstr_w(prop
->name
), debugstr_jsval(*r
));
451 static HRESULT
prop_put(jsdisp_t
*This
, dispex_prop_t
*prop
, jsval_t val
)
455 if(prop
->type
== PROP_PROTREF
) {
456 dispex_prop_t
*prop_iter
= prop
;
457 jsdisp_t
*prototype_iter
= This
;
460 prototype_iter
= prototype_iter
->prototype
;
461 prop_iter
= prototype_iter
->props
+ prop_iter
->u
.ref
;
462 } while(prop_iter
->type
== PROP_PROTREF
);
464 if(prop_iter
->type
== PROP_ACCESSOR
)
470 if(!prop
->u
.p
->setter
) {
471 TRACE("getter with no setter\n");
474 return prop
->u
.p
->setter(This
->ctx
, This
, val
);
477 if(!This
->extensible
)
479 prop
->type
= PROP_JSVAL
;
480 prop
->flags
= PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
;
481 prop
->u
.val
= jsval_undefined();
484 if(!(prop
->flags
& PROPF_WRITABLE
))
487 jsval_release(prop
->u
.val
);
490 if(!prop
->u
.accessor
.setter
) {
491 TRACE("no setter\n");
494 return jsdisp_call_value(prop
->u
.accessor
.setter
, to_disp(This
), DISPATCH_METHOD
, 1, &val
, NULL
);
496 if(!This
->builtin_info
->idx_put
) {
497 TRACE("no put_idx\n");
500 return This
->builtin_info
->idx_put(This
, prop
->u
.idx
, val
);
502 ERR("type %d\n", prop
->type
);
506 TRACE("%p.%s = %s\n", This
, debugstr_w(prop
->name
), debugstr_jsval(val
));
508 hres
= jsval_copy(val
, &prop
->u
.val
);
512 if(This
->builtin_info
->on_put
)
513 This
->builtin_info
->on_put(This
, prop
->name
);
518 static HRESULT
invoke_prop_func(jsdisp_t
*This
, IDispatch
*jsthis
, dispex_prop_t
*prop
, WORD flags
,
519 unsigned argc
, jsval_t
*argv
, jsval_t
*r
, IServiceProvider
*caller
)
525 if(flags
== DISPATCH_CONSTRUCT
&& (prop
->flags
& PROPF_METHOD
)) {
526 WARN("%s is not a constructor\n", debugstr_w(prop
->name
));
530 if(prop
->name
|| This
->builtin_info
->class != JSCLASS_FUNCTION
) {
533 if(This
->builtin_info
->class != JSCLASS_FUNCTION
&& prop
->u
.p
->invoke
!= JSGlobal_eval
)
534 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
536 set_disp(&vthis
, jsthis
);
538 set_jsdisp(&vthis
, This
);
539 hres
= prop
->u
.p
->invoke(This
->ctx
, &vthis
, flags
, argc
, argv
, r
);
540 vdisp_release(&vthis
);
542 /* Function object calls are special case */
543 hres
= Function_invoke(This
, jsthis
, flags
, argc
, argv
, r
);
548 return invoke_prop_func(This
->prototype
, jsthis
? jsthis
: (IDispatch
*)&This
->IDispatchEx_iface
,
549 This
->prototype
->props
+prop
->u
.ref
, flags
, argc
, argv
, r
, caller
);
551 if(!is_object_instance(prop
->u
.val
) || !get_object(prop
->u
.val
)) {
552 FIXME("invoke %s\n", debugstr_jsval(prop
->u
.val
));
556 TRACE("call %s %p\n", debugstr_w(prop
->name
), get_object(prop
->u
.val
));
558 return disp_call_value(This
->ctx
, get_object(prop
->u
.val
),
559 jsthis
? jsthis
: (IDispatch
*)&This
->IDispatchEx_iface
,
560 flags
, argc
, argv
, r
);
566 hres
= prop_get(This
, prop
, &val
);
570 if(is_object_instance(val
) && get_object(val
)) {
571 hres
= disp_call_value(This
->ctx
, get_object(val
),
572 jsthis
? jsthis
: (IDispatch
*)&This
->IDispatchEx_iface
,
573 flags
, argc
, argv
, r
);
575 FIXME("invoke %s\n", debugstr_jsval(val
));
590 HRESULT
builtin_set_const(script_ctx_t
*ctx
, jsdisp_t
*jsthis
, jsval_t value
)
592 TRACE("%p %s\n", jsthis
, debugstr_jsval(value
));
596 static HRESULT
fill_protrefs(jsdisp_t
*This
)
598 dispex_prop_t
*iter
, *prop
;
604 fill_protrefs(This
->prototype
);
606 for(iter
= This
->prototype
->props
; iter
< This
->prototype
->props
+This
->prototype
->prop_cnt
; iter
++) {
609 hres
= find_prop_name(This
, iter
->hash
, iter
->name
, &prop
);
612 if(!prop
|| prop
->type
==PROP_DELETED
) {
614 prop
->type
= PROP_PROTREF
;
616 prop
->u
.ref
= iter
- This
->prototype
->props
;
618 prop
= alloc_protref(This
, iter
->name
, iter
- This
->prototype
->props
);
620 return E_OUTOFMEMORY
;
628 struct typeinfo_func
{
630 function_code_t
*code
;
634 ITypeInfo ITypeInfo_iface
;
635 ITypeComp ITypeComp_iface
;
640 struct typeinfo_func
*funcs
;
641 dispex_prop_t
**vars
;
646 static struct typeinfo_func
*get_func_from_memid(const ScriptTypeInfo
*typeinfo
, MEMBERID memid
)
648 UINT a
= 0, b
= typeinfo
->num_funcs
;
652 UINT i
= (a
+ b
- 1) / 2;
653 MEMBERID func_memid
= prop_to_id(typeinfo
->jsdisp
, typeinfo
->funcs
[i
].prop
);
655 if (memid
== func_memid
)
656 return &typeinfo
->funcs
[i
];
657 else if (memid
< func_memid
)
665 static dispex_prop_t
*get_var_from_memid(const ScriptTypeInfo
*typeinfo
, MEMBERID memid
)
667 UINT a
= 0, b
= typeinfo
->num_vars
;
671 UINT i
= (a
+ b
- 1) / 2;
672 MEMBERID var_memid
= prop_to_id(typeinfo
->jsdisp
, typeinfo
->vars
[i
]);
674 if (memid
== var_memid
)
675 return typeinfo
->vars
[i
];
676 else if (memid
< var_memid
)
684 static inline ScriptTypeInfo
*ScriptTypeInfo_from_ITypeInfo(ITypeInfo
*iface
)
686 return CONTAINING_RECORD(iface
, ScriptTypeInfo
, ITypeInfo_iface
);
689 static inline ScriptTypeInfo
*ScriptTypeInfo_from_ITypeComp(ITypeComp
*iface
)
691 return CONTAINING_RECORD(iface
, ScriptTypeInfo
, ITypeComp_iface
);
694 static HRESULT WINAPI
ScriptTypeInfo_QueryInterface(ITypeInfo
*iface
, REFIID riid
, void **ppv
)
696 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
698 if (IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_ITypeInfo
, riid
))
699 *ppv
= &This
->ITypeInfo_iface
;
700 else if (IsEqualGUID(&IID_ITypeComp
, riid
))
701 *ppv
= &This
->ITypeComp_iface
;
704 WARN("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
706 return E_NOINTERFACE
;
709 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
710 IUnknown_AddRef((IUnknown
*)*ppv
);
714 static ULONG WINAPI
ScriptTypeInfo_AddRef(ITypeInfo
*iface
)
716 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
717 LONG ref
= InterlockedIncrement(&This
->ref
);
719 TRACE("(%p) ref=%d\n", This
, ref
);
724 static ULONG WINAPI
ScriptTypeInfo_Release(ITypeInfo
*iface
)
726 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
727 LONG ref
= InterlockedDecrement(&This
->ref
);
730 TRACE("(%p) ref=%d\n", This
, ref
);
734 for (i
= This
->num_funcs
; i
--;)
735 release_bytecode(This
->funcs
[i
].code
->bytecode
);
736 IDispatchEx_Release(&This
->jsdisp
->IDispatchEx_iface
);
737 heap_free(This
->funcs
);
738 heap_free(This
->vars
);
744 static HRESULT WINAPI
ScriptTypeInfo_GetTypeAttr(ITypeInfo
*iface
, TYPEATTR
**ppTypeAttr
)
746 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
749 TRACE("(%p)->(%p)\n", This
, ppTypeAttr
);
751 if (!ppTypeAttr
) return E_INVALIDARG
;
753 attr
= heap_alloc_zero(sizeof(*attr
));
754 if (!attr
) return E_OUTOFMEMORY
;
756 attr
->guid
= GUID_JScriptTypeInfo
;
757 attr
->lcid
= LOCALE_USER_DEFAULT
;
758 attr
->memidConstructor
= MEMBERID_NIL
;
759 attr
->memidDestructor
= MEMBERID_NIL
;
760 attr
->cbSizeInstance
= 4;
761 attr
->typekind
= TKIND_DISPATCH
;
762 attr
->cFuncs
= This
->num_funcs
;
763 attr
->cVars
= This
->num_vars
;
764 attr
->cImplTypes
= 1;
765 attr
->cbSizeVft
= sizeof(IDispatchVtbl
);
766 attr
->cbAlignment
= 4;
767 attr
->wTypeFlags
= TYPEFLAG_FDISPATCHABLE
;
768 attr
->wMajorVerNum
= JSCRIPT_MAJOR_VERSION
;
769 attr
->wMinorVerNum
= JSCRIPT_MINOR_VERSION
;
775 static HRESULT WINAPI
ScriptTypeInfo_GetTypeComp(ITypeInfo
*iface
, ITypeComp
**ppTComp
)
777 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
779 TRACE("(%p)->(%p)\n", This
, ppTComp
);
781 if (!ppTComp
) return E_INVALIDARG
;
783 *ppTComp
= &This
->ITypeComp_iface
;
784 ITypeInfo_AddRef(iface
);
788 static HRESULT WINAPI
ScriptTypeInfo_GetFuncDesc(ITypeInfo
*iface
, UINT index
, FUNCDESC
**ppFuncDesc
)
790 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
791 struct typeinfo_func
*func
;
795 TRACE("(%p)->(%u %p)\n", This
, index
, ppFuncDesc
);
797 if (!ppFuncDesc
) return E_INVALIDARG
;
798 if (index
>= This
->num_funcs
) return TYPE_E_ELEMENTNOTFOUND
;
799 func
= &This
->funcs
[index
];
801 /* Store the parameter array after the FUNCDESC structure */
802 desc
= heap_alloc_zero(sizeof(*desc
) + sizeof(ELEMDESC
) * func
->code
->param_cnt
);
803 if (!desc
) return E_OUTOFMEMORY
;
805 desc
->memid
= prop_to_id(This
->jsdisp
, func
->prop
);
806 desc
->funckind
= FUNC_DISPATCH
;
807 desc
->invkind
= INVOKE_FUNC
;
808 desc
->callconv
= CC_STDCALL
;
809 desc
->cParams
= func
->code
->param_cnt
;
810 desc
->elemdescFunc
.tdesc
.vt
= VT_VARIANT
;
812 if (func
->code
->param_cnt
) desc
->lprgelemdescParam
= (ELEMDESC
*)(desc
+ 1);
813 for (i
= 0; i
< func
->code
->param_cnt
; i
++)
814 desc
->lprgelemdescParam
[i
].tdesc
.vt
= VT_VARIANT
;
820 static HRESULT WINAPI
ScriptTypeInfo_GetVarDesc(ITypeInfo
*iface
, UINT index
, VARDESC
**ppVarDesc
)
822 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
825 TRACE("(%p)->(%u %p)\n", This
, index
, ppVarDesc
);
827 if (!ppVarDesc
) return E_INVALIDARG
;
828 if (index
>= This
->num_vars
) return TYPE_E_ELEMENTNOTFOUND
;
830 desc
= heap_alloc_zero(sizeof(*desc
));
831 if (!desc
) return E_OUTOFMEMORY
;
833 desc
->memid
= prop_to_id(This
->jsdisp
, This
->vars
[index
]);
834 desc
->varkind
= VAR_DISPATCH
;
835 desc
->elemdescVar
.tdesc
.vt
= VT_VARIANT
;
841 static HRESULT WINAPI
ScriptTypeInfo_GetNames(ITypeInfo
*iface
, MEMBERID memid
, BSTR
*rgBstrNames
,
842 UINT cMaxNames
, UINT
*pcNames
)
844 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
845 struct typeinfo_func
*func
;
846 ITypeInfo
*disp_typeinfo
;
851 TRACE("(%p)->(%d %p %u %p)\n", This
, memid
, rgBstrNames
, cMaxNames
, pcNames
);
853 if (!rgBstrNames
|| !pcNames
) return E_INVALIDARG
;
854 if (memid
<= 0) return TYPE_E_ELEMENTNOTFOUND
;
856 func
= get_func_from_memid(This
, memid
);
859 var
= get_var_from_memid(This
, memid
);
862 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
863 if (FAILED(hr
)) return hr
;
865 return ITypeInfo_GetNames(disp_typeinfo
, memid
, rgBstrNames
, cMaxNames
, pcNames
);
870 if (!cMaxNames
) return S_OK
;
872 rgBstrNames
[0] = SysAllocString(func
? func
->prop
->name
: var
->name
);
873 if (!rgBstrNames
[0]) return E_OUTOFMEMORY
;
878 unsigned num
= min(cMaxNames
, func
->code
->param_cnt
+ 1);
882 if (!(rgBstrNames
[i
] = SysAllocString(func
->code
->params
[i
- 1])))
884 do SysFreeString(rgBstrNames
[--i
]); while (i
);
885 return E_OUTOFMEMORY
;
894 static HRESULT WINAPI
ScriptTypeInfo_GetRefTypeOfImplType(ITypeInfo
*iface
, UINT index
, HREFTYPE
*pRefType
)
896 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
898 TRACE("(%p)->(%u %p)\n", This
, index
, pRefType
);
900 /* We only inherit from IDispatch */
901 if (!pRefType
) return E_INVALIDARG
;
902 if (index
!= 0) return TYPE_E_ELEMENTNOTFOUND
;
908 static HRESULT WINAPI
ScriptTypeInfo_GetImplTypeFlags(ITypeInfo
*iface
, UINT index
, INT
*pImplTypeFlags
)
910 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
912 TRACE("(%p)->(%u %p)\n", This
, index
, pImplTypeFlags
);
914 if (!pImplTypeFlags
) return E_INVALIDARG
;
915 if (index
!= 0) return TYPE_E_ELEMENTNOTFOUND
;
921 static HRESULT WINAPI
ScriptTypeInfo_GetIDsOfNames(ITypeInfo
*iface
, LPOLESTR
*rgszNames
, UINT cNames
,
924 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
925 ITypeInfo
*disp_typeinfo
;
930 TRACE("(%p)->(%p %u %p)\n", This
, rgszNames
, cNames
, pMemId
);
932 if (!rgszNames
|| !cNames
|| !pMemId
) return E_INVALIDARG
;
934 for (i
= 0; i
< cNames
; i
++) pMemId
[i
] = MEMBERID_NIL
;
937 for (i
= 0; i
< This
->num_funcs
; i
++)
939 struct typeinfo_func
*func
= &This
->funcs
[i
];
941 if (wcsicmp(name
, func
->prop
->name
)) continue;
942 pMemId
[0] = prop_to_id(This
->jsdisp
, func
->prop
);
944 for (j
= 1; j
< cNames
; j
++)
947 for (arg
= func
->code
->param_cnt
; --arg
>= 0;)
948 if (!wcsicmp(name
, func
->code
->params
[arg
]))
953 hr
= DISP_E_UNKNOWNNAME
;
958 for (i
= 0; i
< This
->num_vars
; i
++)
960 dispex_prop_t
*var
= This
->vars
[i
];
962 if (wcsicmp(name
, var
->name
)) continue;
963 pMemId
[0] = prop_to_id(This
->jsdisp
, var
);
967 /* Look into the inherited IDispatch */
968 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
969 if (FAILED(hr
)) return hr
;
971 return ITypeInfo_GetIDsOfNames(disp_typeinfo
, rgszNames
, cNames
, pMemId
);
974 static HRESULT WINAPI
ScriptTypeInfo_Invoke(ITypeInfo
*iface
, PVOID pvInstance
, MEMBERID memid
, WORD wFlags
,
975 DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
977 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
978 ITypeInfo
*disp_typeinfo
;
982 TRACE("(%p)->(%p %d %d %p %p %p %p)\n", This
, pvInstance
, memid
, wFlags
,
983 pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
985 if (!pvInstance
) return E_INVALIDARG
;
986 if (memid
<= 0) return TYPE_E_ELEMENTNOTFOUND
;
988 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
990 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
991 if (FAILED(hr
)) return hr
;
993 return ITypeInfo_Invoke(disp_typeinfo
, pvInstance
, memid
, wFlags
, pDispParams
,
994 pVarResult
, pExcepInfo
, puArgErr
);
997 hr
= IUnknown_QueryInterface((IUnknown
*)pvInstance
, &IID_IDispatch
, (void**)&disp
);
998 if (FAILED(hr
)) return hr
;
1000 hr
= IDispatch_Invoke(disp
, memid
, &IID_NULL
, LOCALE_USER_DEFAULT
, wFlags
,
1001 pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
1002 IDispatch_Release(disp
);
1007 static HRESULT WINAPI
ScriptTypeInfo_GetDocumentation(ITypeInfo
*iface
, MEMBERID memid
, BSTR
*pBstrName
,
1008 BSTR
*pBstrDocString
, DWORD
*pdwHelpContext
, BSTR
*pBstrHelpFile
)
1010 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1011 struct typeinfo_func
*func
;
1012 ITypeInfo
*disp_typeinfo
;
1016 TRACE("(%p)->(%d %p %p %p %p)\n", This
, memid
, pBstrName
, pBstrDocString
, pdwHelpContext
, pBstrHelpFile
);
1018 if (pBstrDocString
) *pBstrDocString
= NULL
;
1019 if (pdwHelpContext
) *pdwHelpContext
= 0;
1020 if (pBstrHelpFile
) *pBstrHelpFile
= NULL
;
1022 if (memid
== MEMBERID_NIL
)
1024 if (pBstrName
&& !(*pBstrName
= SysAllocString(L
"JScriptTypeInfo")))
1025 return E_OUTOFMEMORY
;
1026 if (pBstrDocString
&&
1027 !(*pBstrDocString
= SysAllocString(L
"JScript Type Info")))
1029 if (pBstrName
) SysFreeString(*pBstrName
);
1030 return E_OUTOFMEMORY
;
1034 if (memid
<= 0) return TYPE_E_ELEMENTNOTFOUND
;
1036 func
= get_func_from_memid(This
, memid
);
1039 var
= get_var_from_memid(This
, memid
);
1042 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1043 if (FAILED(hr
)) return hr
;
1045 return ITypeInfo_GetDocumentation(disp_typeinfo
, memid
, pBstrName
, pBstrDocString
,
1046 pdwHelpContext
, pBstrHelpFile
);
1052 *pBstrName
= SysAllocString(func
? func
->prop
->name
: var
->name
);
1055 return E_OUTOFMEMORY
;
1060 static HRESULT WINAPI
ScriptTypeInfo_GetDllEntry(ITypeInfo
*iface
, MEMBERID memid
, INVOKEKIND invKind
,
1061 BSTR
*pBstrDllName
, BSTR
*pBstrName
, WORD
*pwOrdinal
)
1063 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1064 ITypeInfo
*disp_typeinfo
;
1067 TRACE("(%p)->(%d %d %p %p %p)\n", This
, memid
, invKind
, pBstrDllName
, pBstrName
, pwOrdinal
);
1069 if (pBstrDllName
) *pBstrDllName
= NULL
;
1070 if (pBstrName
) *pBstrName
= NULL
;
1071 if (pwOrdinal
) *pwOrdinal
= 0;
1073 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
1075 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1076 if (FAILED(hr
)) return hr
;
1078 return ITypeInfo_GetDllEntry(disp_typeinfo
, memid
, invKind
, pBstrDllName
, pBstrName
, pwOrdinal
);
1080 return TYPE_E_BADMODULEKIND
;
1083 static HRESULT WINAPI
ScriptTypeInfo_GetRefTypeInfo(ITypeInfo
*iface
, HREFTYPE hRefType
, ITypeInfo
**ppTInfo
)
1085 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1088 TRACE("(%p)->(%x %p)\n", This
, hRefType
, ppTInfo
);
1090 if (!ppTInfo
|| (INT
)hRefType
< 0) return E_INVALIDARG
;
1092 if (hRefType
& ~3) return E_FAIL
;
1095 hr
= get_dispatch_typeinfo(ppTInfo
);
1096 if (FAILED(hr
)) return hr
;
1101 ITypeInfo_AddRef(*ppTInfo
);
1105 static HRESULT WINAPI
ScriptTypeInfo_AddressOfMember(ITypeInfo
*iface
, MEMBERID memid
, INVOKEKIND invKind
, PVOID
*ppv
)
1107 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1108 ITypeInfo
*disp_typeinfo
;
1111 TRACE("(%p)->(%d %d %p)\n", This
, memid
, invKind
, ppv
);
1113 if (!ppv
) return E_INVALIDARG
;
1116 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
1118 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1119 if (FAILED(hr
)) return hr
;
1121 return ITypeInfo_AddressOfMember(disp_typeinfo
, memid
, invKind
, ppv
);
1123 return TYPE_E_BADMODULEKIND
;
1126 static HRESULT WINAPI
ScriptTypeInfo_CreateInstance(ITypeInfo
*iface
, IUnknown
*pUnkOuter
, REFIID riid
, PVOID
*ppvObj
)
1128 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1130 TRACE("(%p)->(%p %s %p)\n", This
, pUnkOuter
, debugstr_guid(riid
), ppvObj
);
1132 if (!ppvObj
) return E_INVALIDARG
;
1135 return TYPE_E_BADMODULEKIND
;
1138 static HRESULT WINAPI
ScriptTypeInfo_GetMops(ITypeInfo
*iface
, MEMBERID memid
, BSTR
*pBstrMops
)
1140 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1141 ITypeInfo
*disp_typeinfo
;
1144 TRACE("(%p)->(%d %p)\n", This
, memid
, pBstrMops
);
1146 if (!pBstrMops
) return E_INVALIDARG
;
1148 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
1150 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1151 if (FAILED(hr
)) return hr
;
1153 return ITypeInfo_GetMops(disp_typeinfo
, memid
, pBstrMops
);
1160 static HRESULT WINAPI
ScriptTypeInfo_GetContainingTypeLib(ITypeInfo
*iface
, ITypeLib
**ppTLib
, UINT
*pIndex
)
1162 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1164 FIXME("(%p)->(%p %p)\n", This
, ppTLib
, pIndex
);
1169 static void WINAPI
ScriptTypeInfo_ReleaseTypeAttr(ITypeInfo
*iface
, TYPEATTR
*pTypeAttr
)
1171 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1173 TRACE("(%p)->(%p)\n", This
, pTypeAttr
);
1175 heap_free(pTypeAttr
);
1178 static void WINAPI
ScriptTypeInfo_ReleaseFuncDesc(ITypeInfo
*iface
, FUNCDESC
*pFuncDesc
)
1180 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1182 TRACE("(%p)->(%p)\n", This
, pFuncDesc
);
1184 heap_free(pFuncDesc
);
1187 static void WINAPI
ScriptTypeInfo_ReleaseVarDesc(ITypeInfo
*iface
, VARDESC
*pVarDesc
)
1189 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1191 TRACE("(%p)->(%p)\n", This
, pVarDesc
);
1193 heap_free(pVarDesc
);
1196 static const ITypeInfoVtbl ScriptTypeInfoVtbl
= {
1197 ScriptTypeInfo_QueryInterface
,
1198 ScriptTypeInfo_AddRef
,
1199 ScriptTypeInfo_Release
,
1200 ScriptTypeInfo_GetTypeAttr
,
1201 ScriptTypeInfo_GetTypeComp
,
1202 ScriptTypeInfo_GetFuncDesc
,
1203 ScriptTypeInfo_GetVarDesc
,
1204 ScriptTypeInfo_GetNames
,
1205 ScriptTypeInfo_GetRefTypeOfImplType
,
1206 ScriptTypeInfo_GetImplTypeFlags
,
1207 ScriptTypeInfo_GetIDsOfNames
,
1208 ScriptTypeInfo_Invoke
,
1209 ScriptTypeInfo_GetDocumentation
,
1210 ScriptTypeInfo_GetDllEntry
,
1211 ScriptTypeInfo_GetRefTypeInfo
,
1212 ScriptTypeInfo_AddressOfMember
,
1213 ScriptTypeInfo_CreateInstance
,
1214 ScriptTypeInfo_GetMops
,
1215 ScriptTypeInfo_GetContainingTypeLib
,
1216 ScriptTypeInfo_ReleaseTypeAttr
,
1217 ScriptTypeInfo_ReleaseFuncDesc
,
1218 ScriptTypeInfo_ReleaseVarDesc
1221 static HRESULT WINAPI
ScriptTypeComp_QueryInterface(ITypeComp
*iface
, REFIID riid
, void **ppv
)
1223 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1224 return ITypeInfo_QueryInterface(&This
->ITypeInfo_iface
, riid
, ppv
);
1227 static ULONG WINAPI
ScriptTypeComp_AddRef(ITypeComp
*iface
)
1229 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1230 return ITypeInfo_AddRef(&This
->ITypeInfo_iface
);
1233 static ULONG WINAPI
ScriptTypeComp_Release(ITypeComp
*iface
)
1235 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1236 return ITypeInfo_Release(&This
->ITypeInfo_iface
);
1239 static HRESULT WINAPI
ScriptTypeComp_Bind(ITypeComp
*iface
, LPOLESTR szName
, ULONG lHashVal
, WORD wFlags
,
1240 ITypeInfo
**ppTInfo
, DESCKIND
*pDescKind
, BINDPTR
*pBindPtr
)
1242 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1243 UINT flags
= wFlags
? wFlags
: ~0;
1244 ITypeInfo
*disp_typeinfo
;
1245 ITypeComp
*disp_typecomp
;
1249 TRACE("(%p)->(%s %08x %d %p %p %p)\n", This
, debugstr_w(szName
), lHashVal
,
1250 wFlags
, ppTInfo
, pDescKind
, pBindPtr
);
1252 if (!szName
|| !ppTInfo
|| !pDescKind
|| !pBindPtr
)
1253 return E_INVALIDARG
;
1255 for (i
= 0; i
< This
->num_funcs
; i
++)
1257 if (wcsicmp(szName
, This
->funcs
[i
].prop
->name
)) continue;
1258 if (!(flags
& INVOKE_FUNC
)) return TYPE_E_TYPEMISMATCH
;
1260 hr
= ITypeInfo_GetFuncDesc(&This
->ITypeInfo_iface
, i
, &pBindPtr
->lpfuncdesc
);
1261 if (FAILED(hr
)) return hr
;
1263 *pDescKind
= DESCKIND_FUNCDESC
;
1264 *ppTInfo
= &This
->ITypeInfo_iface
;
1265 ITypeInfo_AddRef(*ppTInfo
);
1269 for (i
= 0; i
< This
->num_vars
; i
++)
1271 if (wcsicmp(szName
, This
->vars
[i
]->name
)) continue;
1272 if (!(flags
& INVOKE_PROPERTYGET
)) return TYPE_E_TYPEMISMATCH
;
1274 hr
= ITypeInfo_GetVarDesc(&This
->ITypeInfo_iface
, i
, &pBindPtr
->lpvardesc
);
1275 if (FAILED(hr
)) return hr
;
1277 *pDescKind
= DESCKIND_VARDESC
;
1278 *ppTInfo
= &This
->ITypeInfo_iface
;
1279 ITypeInfo_AddRef(*ppTInfo
);
1283 /* Look into the inherited IDispatch */
1284 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1285 if (FAILED(hr
)) return hr
;
1287 hr
= ITypeInfo_GetTypeComp(disp_typeinfo
, &disp_typecomp
);
1288 if (FAILED(hr
)) return hr
;
1290 hr
= ITypeComp_Bind(disp_typecomp
, szName
, lHashVal
, wFlags
, ppTInfo
, pDescKind
, pBindPtr
);
1291 ITypeComp_Release(disp_typecomp
);
1295 static HRESULT WINAPI
ScriptTypeComp_BindType(ITypeComp
*iface
, LPOLESTR szName
, ULONG lHashVal
,
1296 ITypeInfo
**ppTInfo
, ITypeComp
**ppTComp
)
1298 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1299 ITypeInfo
*disp_typeinfo
;
1300 ITypeComp
*disp_typecomp
;
1303 TRACE("(%p)->(%s %08x %p %p)\n", This
, debugstr_w(szName
), lHashVal
, ppTInfo
, ppTComp
);
1305 if (!szName
|| !ppTInfo
|| !ppTComp
)
1306 return E_INVALIDARG
;
1308 /* Look into the inherited IDispatch */
1309 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1310 if (FAILED(hr
)) return hr
;
1312 hr
= ITypeInfo_GetTypeComp(disp_typeinfo
, &disp_typecomp
);
1313 if (FAILED(hr
)) return hr
;
1315 hr
= ITypeComp_BindType(disp_typecomp
, szName
, lHashVal
, ppTInfo
, ppTComp
);
1316 ITypeComp_Release(disp_typecomp
);
1320 static const ITypeCompVtbl ScriptTypeCompVtbl
= {
1321 ScriptTypeComp_QueryInterface
,
1322 ScriptTypeComp_AddRef
,
1323 ScriptTypeComp_Release
,
1324 ScriptTypeComp_Bind
,
1325 ScriptTypeComp_BindType
1328 static inline jsdisp_t
*impl_from_IDispatchEx(IDispatchEx
*iface
)
1330 return CONTAINING_RECORD(iface
, jsdisp_t
, IDispatchEx_iface
);
1333 static HRESULT WINAPI
DispatchEx_QueryInterface(IDispatchEx
*iface
, REFIID riid
, void **ppv
)
1335 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1337 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
1338 TRACE("(%p)->(IID_IUnknown %p)\n", This
, ppv
);
1339 *ppv
= &This
->IDispatchEx_iface
;
1340 }else if(IsEqualGUID(&IID_IDispatch
, riid
)) {
1341 TRACE("(%p)->(IID_IDispatch %p)\n", This
, ppv
);
1342 *ppv
= &This
->IDispatchEx_iface
;
1343 }else if(IsEqualGUID(&IID_IDispatchEx
, riid
)) {
1344 TRACE("(%p)->(IID_IDispatchEx %p)\n", This
, ppv
);
1345 *ppv
= &This
->IDispatchEx_iface
;
1347 WARN("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
1349 return E_NOINTERFACE
;
1352 jsdisp_addref(This
);
1356 static ULONG WINAPI
DispatchEx_AddRef(IDispatchEx
*iface
)
1358 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1359 jsdisp_addref(This
);
1363 static ULONG WINAPI
DispatchEx_Release(IDispatchEx
*iface
)
1365 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1366 ULONG ref
= --This
->ref
;
1367 TRACE("(%p) ref=%d\n", This
, ref
);
1373 static HRESULT WINAPI
DispatchEx_GetTypeInfoCount(IDispatchEx
*iface
, UINT
*pctinfo
)
1375 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1377 TRACE("(%p)->(%p)\n", This
, pctinfo
);
1383 static HRESULT WINAPI
DispatchEx_GetTypeInfo(IDispatchEx
*iface
, UINT iTInfo
, LCID lcid
,
1384 ITypeInfo
**ppTInfo
)
1386 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1387 dispex_prop_t
*prop
, *cur
, *end
, **typevar
;
1388 UINT num_funcs
= 0, num_vars
= 0;
1389 struct typeinfo_func
*typefunc
;
1390 function_code_t
*func_code
;
1391 ScriptTypeInfo
*typeinfo
;
1394 TRACE("(%p)->(%u %u %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
1396 if (iTInfo
!= 0) return DISP_E_BADINDEX
;
1398 for (prop
= This
->props
, end
= prop
+ This
->prop_cnt
; prop
!= end
; prop
++)
1400 if (!prop
->name
|| prop
->type
!= PROP_JSVAL
|| !(prop
->flags
& PROPF_ENUMERABLE
))
1403 /* If two identifiers differ only by case, the TypeInfo fails */
1404 pos
= This
->props
[get_props_idx(This
, prop
->hash
)].bucket_head
;
1407 cur
= This
->props
+ pos
;
1409 if (prop
->hash
== cur
->hash
&& prop
!= cur
&&
1410 cur
->type
== PROP_JSVAL
&& (cur
->flags
& PROPF_ENUMERABLE
) &&
1411 !wcsicmp(prop
->name
, cur
->name
))
1413 return TYPE_E_AMBIGUOUSNAME
;
1415 pos
= cur
->bucket_next
;
1418 if (is_function_prop(prop
))
1420 if (Function_get_code(as_jsdisp(get_object(prop
->u
.val
))))
1426 if (!(typeinfo
= heap_alloc(sizeof(*typeinfo
))))
1427 return E_OUTOFMEMORY
;
1429 typeinfo
->ITypeInfo_iface
.lpVtbl
= &ScriptTypeInfoVtbl
;
1430 typeinfo
->ITypeComp_iface
.lpVtbl
= &ScriptTypeCompVtbl
;
1432 typeinfo
->num_vars
= num_vars
;
1433 typeinfo
->num_funcs
= num_funcs
;
1434 typeinfo
->jsdisp
= This
;
1436 typeinfo
->funcs
= heap_alloc(sizeof(*typeinfo
->funcs
) * num_funcs
);
1437 if (!typeinfo
->funcs
)
1439 heap_free(typeinfo
);
1440 return E_OUTOFMEMORY
;
1443 typeinfo
->vars
= heap_alloc(sizeof(*typeinfo
->vars
) * num_vars
);
1444 if (!typeinfo
->vars
)
1446 heap_free(typeinfo
->funcs
);
1447 heap_free(typeinfo
);
1448 return E_OUTOFMEMORY
;
1451 typefunc
= typeinfo
->funcs
;
1452 typevar
= typeinfo
->vars
;
1453 for (prop
= This
->props
; prop
!= end
; prop
++)
1455 if (!prop
->name
|| prop
->type
!= PROP_JSVAL
|| !(prop
->flags
& PROPF_ENUMERABLE
))
1458 if (is_function_prop(prop
))
1460 func_code
= Function_get_code(as_jsdisp(get_object(prop
->u
.val
)));
1461 if (!func_code
) continue;
1463 typefunc
->prop
= prop
;
1464 typefunc
->code
= func_code
;
1467 /* The function may be deleted, so keep a ref */
1468 bytecode_addref(func_code
->bytecode
);
1474 /* Keep a ref to the props and their names */
1475 IDispatchEx_AddRef(&This
->IDispatchEx_iface
);
1477 *ppTInfo
= &typeinfo
->ITypeInfo_iface
;
1481 static HRESULT WINAPI
DispatchEx_GetIDsOfNames(IDispatchEx
*iface
, REFIID riid
,
1482 LPOLESTR
*rgszNames
, UINT cNames
, LCID lcid
,
1485 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1489 TRACE("(%p)->(%s %p %u %u %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
,
1492 for(i
=0; i
< cNames
; i
++) {
1493 hres
= IDispatchEx_GetDispID(&This
->IDispatchEx_iface
, rgszNames
[i
], 0, rgDispId
+i
);
1501 static HRESULT WINAPI
DispatchEx_Invoke(IDispatchEx
*iface
, DISPID dispIdMember
,
1502 REFIID riid
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
,
1503 VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
1505 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1507 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This
, dispIdMember
, debugstr_guid(riid
),
1508 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
1510 return IDispatchEx_InvokeEx(&This
->IDispatchEx_iface
, dispIdMember
, lcid
, wFlags
,
1511 pDispParams
, pVarResult
, pExcepInfo
, NULL
);
1514 static HRESULT WINAPI
DispatchEx_GetDispID(IDispatchEx
*iface
, BSTR bstrName
, DWORD grfdex
, DISPID
*pid
)
1516 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1518 TRACE("(%p)->(%s %x %p)\n", This
, debugstr_w(bstrName
), grfdex
, pid
);
1520 if(grfdex
& ~(fdexNameCaseSensitive
|fdexNameEnsure
|fdexNameImplicit
|FDEX_VERSION_MASK
)) {
1521 FIXME("Unsupported grfdex %x\n", grfdex
);
1525 return jsdisp_get_id(This
, bstrName
, grfdex
, pid
);
1528 static HRESULT WINAPI
DispatchEx_InvokeEx(IDispatchEx
*iface
, DISPID id
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pdp
,
1529 VARIANT
*pvarRes
, EXCEPINFO
*pei
, IServiceProvider
*pspCaller
)
1531 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1532 dispex_prop_t
*prop
;
1536 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This
, id
, lcid
, wFlags
, pdp
, pvarRes
, pei
, pspCaller
);
1539 V_VT(pvarRes
) = VT_EMPTY
;
1541 prop
= get_prop(This
, id
);
1542 if(!prop
|| prop
->type
== PROP_DELETED
) {
1543 TRACE("invalid id\n");
1544 return DISP_E_MEMBERNOTFOUND
;
1547 enter_script(This
->ctx
, &ei
);
1550 case DISPATCH_METHOD
|DISPATCH_PROPERTYGET
:
1551 wFlags
= DISPATCH_METHOD
;
1553 case DISPATCH_METHOD
:
1554 case DISPATCH_CONSTRUCT
: {
1555 jsval_t
*argv
, buf
[6], r
;
1558 hres
= convert_params(pdp
, buf
, &argc
, &argv
);
1562 hres
= invoke_prop_func(This
, get_this(pdp
), prop
, wFlags
, argc
, argv
, pvarRes
? &r
: NULL
, pspCaller
);
1565 if(SUCCEEDED(hres
) && pvarRes
) {
1566 hres
= jsval_to_variant(r
, pvarRes
);
1571 case DISPATCH_PROPERTYGET
: {
1574 hres
= prop_get(This
, prop
, &r
);
1575 if(SUCCEEDED(hres
)) {
1576 hres
= jsval_to_variant(r
, pvarRes
);
1581 case DISPATCH_PROPERTYPUT
: {
1585 for(i
=0; i
< pdp
->cNamedArgs
; i
++) {
1586 if(pdp
->rgdispidNamedArgs
[i
] == DISPID_PROPERTYPUT
)
1590 if(i
== pdp
->cNamedArgs
) {
1591 TRACE("no value to set\n");
1592 hres
= DISP_E_PARAMNOTOPTIONAL
;
1596 hres
= variant_to_jsval(pdp
->rgvarg
+i
, &val
);
1600 hres
= prop_put(This
, prop
, val
);
1605 FIXME("Unimplemented flags %x\n", wFlags
);
1606 hres
= E_INVALIDARG
;
1610 return leave_script(This
->ctx
, hres
);
1613 static HRESULT
delete_prop(dispex_prop_t
*prop
, BOOL
*ret
)
1615 if(!(prop
->flags
& PROPF_CONFIGURABLE
)) {
1620 *ret
= TRUE
; /* FIXME: not exactly right */
1622 if(prop
->type
== PROP_JSVAL
) {
1623 jsval_release(prop
->u
.val
);
1624 prop
->type
= PROP_DELETED
;
1626 if(prop
->type
== PROP_ACCESSOR
)
1627 FIXME("not supported on accessor property\n");
1631 static HRESULT WINAPI
DispatchEx_DeleteMemberByName(IDispatchEx
*iface
, BSTR bstrName
, DWORD grfdex
)
1633 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1634 dispex_prop_t
*prop
;
1638 TRACE("(%p)->(%s %x)\n", This
, debugstr_w(bstrName
), grfdex
);
1640 if(grfdex
& ~(fdexNameCaseSensitive
|fdexNameEnsure
|fdexNameImplicit
|FDEX_VERSION_MASK
))
1641 FIXME("Unsupported grfdex %x\n", grfdex
);
1643 hres
= find_prop_name(This
, string_hash(bstrName
), bstrName
, &prop
);
1647 TRACE("not found\n");
1651 return delete_prop(prop
, &b
);
1654 static HRESULT WINAPI
DispatchEx_DeleteMemberByDispID(IDispatchEx
*iface
, DISPID id
)
1656 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1657 dispex_prop_t
*prop
;
1660 TRACE("(%p)->(%x)\n", This
, id
);
1662 prop
= get_prop(This
, id
);
1664 WARN("invalid id\n");
1665 return DISP_E_MEMBERNOTFOUND
;
1668 return delete_prop(prop
, &b
);
1671 static HRESULT WINAPI
DispatchEx_GetMemberProperties(IDispatchEx
*iface
, DISPID id
, DWORD grfdexFetch
, DWORD
*pgrfdex
)
1673 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1674 FIXME("(%p)->(%x %x %p)\n", This
, id
, grfdexFetch
, pgrfdex
);
1678 static HRESULT WINAPI
DispatchEx_GetMemberName(IDispatchEx
*iface
, DISPID id
, BSTR
*pbstrName
)
1680 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1681 dispex_prop_t
*prop
;
1683 TRACE("(%p)->(%x %p)\n", This
, id
, pbstrName
);
1685 prop
= get_prop(This
, id
);
1686 if(!prop
|| !prop
->name
|| prop
->type
== PROP_DELETED
)
1687 return DISP_E_MEMBERNOTFOUND
;
1689 *pbstrName
= SysAllocString(prop
->name
);
1691 return E_OUTOFMEMORY
;
1696 static HRESULT WINAPI
DispatchEx_GetNextDispID(IDispatchEx
*iface
, DWORD grfdex
, DISPID id
, DISPID
*pid
)
1698 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1701 TRACE("(%p)->(%x %x %p)\n", This
, grfdex
, id
, pid
);
1703 hres
= jsdisp_next_prop(This
, id
, FALSE
, pid
);
1705 *pid
= DISPID_STARTENUM
;
1709 static HRESULT WINAPI
DispatchEx_GetNameSpaceParent(IDispatchEx
*iface
, IUnknown
**ppunk
)
1711 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1712 FIXME("(%p)->(%p)\n", This
, ppunk
);
1716 static IDispatchExVtbl DispatchExVtbl
= {
1717 DispatchEx_QueryInterface
,
1720 DispatchEx_GetTypeInfoCount
,
1721 DispatchEx_GetTypeInfo
,
1722 DispatchEx_GetIDsOfNames
,
1724 DispatchEx_GetDispID
,
1725 DispatchEx_InvokeEx
,
1726 DispatchEx_DeleteMemberByName
,
1727 DispatchEx_DeleteMemberByDispID
,
1728 DispatchEx_GetMemberProperties
,
1729 DispatchEx_GetMemberName
,
1730 DispatchEx_GetNextDispID
,
1731 DispatchEx_GetNameSpaceParent
1734 jsdisp_t
*as_jsdisp(IDispatch
*disp
)
1736 assert(disp
->lpVtbl
== (IDispatchVtbl
*)&DispatchExVtbl
);
1737 return impl_from_IDispatchEx((IDispatchEx
*)disp
);
1740 jsdisp_t
*to_jsdisp(IDispatch
*disp
)
1742 return disp
->lpVtbl
== (IDispatchVtbl
*)&DispatchExVtbl
? impl_from_IDispatchEx((IDispatchEx
*)disp
) : NULL
;
1745 HRESULT
init_dispex(jsdisp_t
*dispex
, script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*prototype
)
1747 TRACE("%p (%p)\n", dispex
, prototype
);
1749 dispex
->IDispatchEx_iface
.lpVtbl
= &DispatchExVtbl
;
1751 dispex
->builtin_info
= builtin_info
;
1752 dispex
->extensible
= TRUE
;
1754 dispex
->props
= heap_alloc_zero(sizeof(dispex_prop_t
)*(dispex
->buf_size
=4));
1756 return E_OUTOFMEMORY
;
1758 dispex
->prototype
= prototype
;
1760 jsdisp_addref(prototype
);
1762 dispex
->prop_cnt
= 1;
1763 if(builtin_info
->value_prop
.invoke
|| builtin_info
->value_prop
.getter
) {
1764 dispex
->props
[0].type
= PROP_BUILTIN
;
1765 dispex
->props
[0].u
.p
= &builtin_info
->value_prop
;
1767 dispex
->props
[0].type
= PROP_DELETED
;
1776 static const builtin_info_t dispex_info
= {
1784 HRESULT
create_dispex(script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*prototype
, jsdisp_t
**dispex
)
1789 ret
= heap_alloc_zero(sizeof(jsdisp_t
));
1791 return E_OUTOFMEMORY
;
1793 hres
= init_dispex(ret
, ctx
, builtin_info
? builtin_info
: &dispex_info
, prototype
);
1803 void jsdisp_free(jsdisp_t
*obj
)
1805 dispex_prop_t
*prop
;
1807 TRACE("(%p)\n", obj
);
1809 for(prop
= obj
->props
; prop
< obj
->props
+obj
->prop_cnt
; prop
++) {
1810 switch(prop
->type
) {
1812 jsval_release(prop
->u
.val
);
1815 if(prop
->u
.accessor
.getter
)
1816 jsdisp_release(prop
->u
.accessor
.getter
);
1817 if(prop
->u
.accessor
.setter
)
1818 jsdisp_release(prop
->u
.accessor
.setter
);
1823 heap_free(prop
->name
);
1825 heap_free(obj
->props
);
1826 script_release(obj
->ctx
);
1828 jsdisp_release(obj
->prototype
);
1830 if(obj
->builtin_info
->destructor
)
1831 obj
->builtin_info
->destructor(obj
);
1838 jsdisp_t
*jsdisp_addref(jsdisp_t
*jsdisp
)
1840 ULONG ref
= ++jsdisp
->ref
;
1841 TRACE("(%p) ref=%d\n", jsdisp
, ref
);
1845 void jsdisp_release(jsdisp_t
*jsdisp
)
1847 ULONG ref
= --jsdisp
->ref
;
1849 TRACE("(%p) ref=%d\n", jsdisp
, ref
);
1852 jsdisp_free(jsdisp
);
1857 HRESULT
init_dispex_from_constr(jsdisp_t
*dispex
, script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*constr
)
1859 jsdisp_t
*prot
= NULL
;
1860 dispex_prop_t
*prop
;
1863 hres
= find_prop_name_prot(constr
, string_hash(L
"prototype"), L
"prototype", &prop
);
1864 if(SUCCEEDED(hres
) && prop
&& prop
->type
!=PROP_DELETED
) {
1867 hres
= prop_get(constr
, prop
, &val
);
1869 ERR("Could not get prototype\n");
1873 if(is_object_instance(val
) && get_object(val
))
1874 prot
= iface_to_jsdisp(get_object(val
));
1876 prot
= ctx
->object_prototype
;
1881 hres
= init_dispex(dispex
, ctx
, builtin_info
, prot
);
1884 jsdisp_release(prot
);
1888 jsdisp_t
*iface_to_jsdisp(IDispatch
*iface
)
1890 return iface
->lpVtbl
== (const IDispatchVtbl
*)&DispatchExVtbl
1891 ? jsdisp_addref( impl_from_IDispatchEx((IDispatchEx
*)iface
))
1895 HRESULT
jsdisp_get_id(jsdisp_t
*jsdisp
, const WCHAR
*name
, DWORD flags
, DISPID
*id
)
1897 dispex_prop_t
*prop
;
1900 if(jsdisp
->extensible
&& (flags
& fdexNameEnsure
))
1901 hres
= ensure_prop_name(jsdisp
, name
, PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
,
1904 hres
= find_prop_name_prot(jsdisp
, string_hash(name
), name
, &prop
);
1908 if(prop
&& prop
->type
!=PROP_DELETED
) {
1909 *id
= prop_to_id(jsdisp
, prop
);
1913 TRACE("not found %s\n", debugstr_w(name
));
1914 *id
= DISPID_UNKNOWN
;
1915 return DISP_E_UNKNOWNNAME
;
1918 HRESULT
jsdisp_call_value(jsdisp_t
*jsfunc
, IDispatch
*jsthis
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1922 assert(!(flags
& ~(DISPATCH_METHOD
|DISPATCH_CONSTRUCT
|DISPATCH_JSCRIPT_INTERNAL_MASK
)));
1924 if(is_class(jsfunc
, JSCLASS_FUNCTION
)) {
1925 hres
= Function_invoke(jsfunc
, jsthis
, flags
, argc
, argv
, r
);
1929 if(!jsfunc
->builtin_info
->value_prop
.invoke
) {
1930 WARN("Not a function\n");
1931 return JS_E_FUNCTION_EXPECTED
;
1934 set_disp(&vdisp
, jsthis
);
1935 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
1936 hres
= jsfunc
->builtin_info
->value_prop
.invoke(jsfunc
->ctx
, &vdisp
, flags
, argc
, argv
, r
);
1937 vdisp_release(&vdisp
);
1942 HRESULT
jsdisp_call(jsdisp_t
*disp
, DISPID id
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1944 dispex_prop_t
*prop
;
1946 prop
= get_prop(disp
, id
);
1948 return DISP_E_MEMBERNOTFOUND
;
1950 return invoke_prop_func(disp
, to_disp(disp
), prop
, flags
, argc
, argv
, r
, NULL
);
1953 HRESULT
jsdisp_call_name(jsdisp_t
*disp
, const WCHAR
*name
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1955 dispex_prop_t
*prop
;
1958 hres
= find_prop_name_prot(disp
, string_hash(name
), name
, &prop
);
1962 return invoke_prop_func(disp
, to_disp(disp
), prop
, flags
, argc
, argv
, r
, NULL
);
1965 static HRESULT
disp_invoke(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, WORD flags
, DISPPARAMS
*params
, VARIANT
*r
)
1967 IDispatchEx
*dispex
;
1971 memset(&ei
, 0, sizeof(ei
));
1972 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
1973 if(SUCCEEDED(hres
)) {
1974 hres
= IDispatchEx_InvokeEx(dispex
, id
, ctx
->lcid
, flags
, params
, r
, &ei
, &ctx
->jscaller
->IServiceProvider_iface
);
1975 IDispatchEx_Release(dispex
);
1979 if(flags
== DISPATCH_CONSTRUCT
) {
1980 WARN("IDispatch cannot be constructor\n");
1981 return DISP_E_MEMBERNOTFOUND
;
1984 if(params
->cNamedArgs
== 1 && params
->rgdispidNamedArgs
[0] == DISPID_THIS
) {
1985 params
->cNamedArgs
= 0;
1986 params
->rgdispidNamedArgs
= NULL
;
1991 TRACE("using IDispatch\n");
1992 hres
= IDispatch_Invoke(disp
, id
, &IID_NULL
, ctx
->lcid
, flags
, params
, r
, &ei
, &err
);
1995 if(hres
== DISP_E_EXCEPTION
) {
1996 TRACE("DISP_E_EXCEPTION: %08x %s %s\n", ei
.scode
, debugstr_w(ei
.bstrSource
), debugstr_w(ei
.bstrDescription
));
1998 ctx
->ei
->error
= (SUCCEEDED(ei
.scode
) || ei
.scode
== DISP_E_EXCEPTION
) ? E_FAIL
: ei
.scode
;
2000 ctx
->ei
->source
= jsstr_alloc_len(ei
.bstrSource
, SysStringLen(ei
.bstrSource
));
2001 if(ei
.bstrDescription
)
2002 ctx
->ei
->message
= jsstr_alloc_len(ei
.bstrDescription
, SysStringLen(ei
.bstrDescription
));
2003 SysFreeString(ei
.bstrSource
);
2004 SysFreeString(ei
.bstrDescription
);
2005 SysFreeString(ei
.bstrHelpFile
);
2011 HRESULT
disp_call(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*ret
)
2013 VARIANT buf
[6], retv
;
2019 jsdisp
= iface_to_jsdisp(disp
);
2020 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2021 if(flags
& DISPATCH_PROPERTYPUT
) {
2022 FIXME("disp_call(propput) on builtin object\n");
2026 if(ctx
!= jsdisp
->ctx
)
2027 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
2028 hres
= jsdisp_call(jsdisp
, id
, flags
, argc
, argv
, ret
);
2029 jsdisp_release(jsdisp
);
2033 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
2035 flags
|= DISPATCH_PROPERTYGET
;
2039 if(flags
& DISPATCH_PROPERTYPUT
) {
2040 static DISPID propput_dispid
= DISPID_PROPERTYPUT
;
2043 dp
.rgdispidNamedArgs
= &propput_dispid
;
2046 dp
.rgdispidNamedArgs
= NULL
;
2049 if(dp
.cArgs
> ARRAY_SIZE(buf
)) {
2050 dp
.rgvarg
= heap_alloc(argc
*sizeof(VARIANT
));
2052 return E_OUTOFMEMORY
;
2057 for(i
=0; i
<argc
; i
++) {
2058 hres
= jsval_to_variant(argv
[i
], dp
.rgvarg
+argc
-i
-1);
2061 VariantClear(dp
.rgvarg
+argc
-i
-1);
2062 if(dp
.rgvarg
!= buf
)
2063 heap_free(dp
.rgvarg
);
2068 V_VT(&retv
) = VT_EMPTY
;
2069 hres
= disp_invoke(ctx
, disp
, id
, flags
, &dp
, ret
? &retv
: NULL
);
2071 for(i
=0; i
<argc
; i
++)
2072 VariantClear(dp
.rgvarg
+argc
-i
-1);
2073 if(dp
.rgvarg
!= buf
)
2074 heap_free(dp
.rgvarg
);
2076 if(SUCCEEDED(hres
) && ret
)
2077 hres
= variant_to_jsval(&retv
, ret
);
2078 VariantClear(&retv
);
2082 HRESULT
disp_call_value(script_ctx_t
*ctx
, IDispatch
*disp
, IDispatch
*jsthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
2085 VARIANT buf
[6], retv
, *args
= buf
;
2089 HRESULT hres
= S_OK
;
2091 static DISPID this_id
= DISPID_THIS
;
2093 assert(!(flags
& ~(DISPATCH_METHOD
|DISPATCH_CONSTRUCT
|DISPATCH_JSCRIPT_INTERNAL_MASK
)));
2095 jsdisp
= iface_to_jsdisp(disp
);
2096 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2097 if(ctx
!= jsdisp
->ctx
)
2098 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
2099 hres
= jsdisp_call_value(jsdisp
, jsthis
, flags
, argc
, argv
, r
);
2100 jsdisp_release(jsdisp
);
2104 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
2105 if(r
&& argc
&& flags
== DISPATCH_METHOD
)
2106 flags
|= DISPATCH_PROPERTYGET
;
2109 dp
.cArgs
= argc
+ 1;
2111 dp
.rgdispidNamedArgs
= &this_id
;
2115 dp
.rgdispidNamedArgs
= NULL
;
2118 if(dp
.cArgs
> ARRAY_SIZE(buf
) && !(args
= heap_alloc(dp
.cArgs
* sizeof(VARIANT
))))
2119 return E_OUTOFMEMORY
;
2123 V_VT(dp
.rgvarg
) = VT_DISPATCH
;
2124 V_DISPATCH(dp
.rgvarg
) = jsthis
;
2127 for(i
=0; SUCCEEDED(hres
) && i
< argc
; i
++)
2128 hres
= jsval_to_variant(argv
[i
], dp
.rgvarg
+dp
.cArgs
-i
-1);
2130 if(SUCCEEDED(hres
)) {
2131 V_VT(&retv
) = VT_EMPTY
;
2132 hres
= disp_invoke(ctx
, disp
, DISPID_VALUE
, flags
, &dp
, r
? &retv
: NULL
);
2135 for(i
= 0; i
< argc
; i
++)
2136 VariantClear(dp
.rgvarg
+ dp
.cArgs
- i
- 1);
2143 hres
= variant_to_jsval(&retv
, r
);
2144 VariantClear(&retv
);
2148 HRESULT
jsdisp_propput(jsdisp_t
*obj
, const WCHAR
*name
, DWORD flags
, BOOL
throw, jsval_t val
)
2150 dispex_prop_t
*prop
;
2154 hres
= ensure_prop_name(obj
, name
, flags
, &prop
);
2156 hres
= find_prop_name(obj
, string_hash(name
), name
, &prop
);
2159 if(!prop
|| (prop
->type
== PROP_DELETED
&& !obj
->extensible
))
2160 return throw ? JS_E_INVALID_ACTION
: S_OK
;
2162 return prop_put(obj
, prop
, val
);
2165 HRESULT
jsdisp_propput_name(jsdisp_t
*obj
, const WCHAR
*name
, jsval_t val
)
2167 return jsdisp_propput(obj
, name
, PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
, FALSE
, val
);
2170 HRESULT
jsdisp_propput_idx(jsdisp_t
*obj
, DWORD idx
, jsval_t val
)
2174 swprintf(buf
, ARRAY_SIZE(buf
), L
"%d", idx
);
2175 return jsdisp_propput(obj
, buf
, PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
, TRUE
, val
);
2178 HRESULT
disp_propput(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, jsval_t val
)
2183 jsdisp
= iface_to_jsdisp(disp
);
2184 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2185 dispex_prop_t
*prop
;
2187 prop
= get_prop(jsdisp
, id
);
2189 hres
= prop_put(jsdisp
, prop
, val
);
2191 hres
= DISP_E_MEMBERNOTFOUND
;
2193 jsdisp_release(jsdisp
);
2195 DISPID dispid
= DISPID_PROPERTYPUT
;
2196 DWORD flags
= DISPATCH_PROPERTYPUT
;
2198 DISPPARAMS dp
= {&var
, &dispid
, 1, 1};
2200 hres
= jsval_to_variant(val
, &var
);
2204 if(V_VT(&var
) == VT_DISPATCH
)
2205 flags
|= DISPATCH_PROPERTYPUTREF
;
2207 hres
= disp_invoke(ctx
, disp
, id
, flags
, &dp
, NULL
);
2214 HRESULT
disp_propput_name(script_ctx_t
*ctx
, IDispatch
*disp
, const WCHAR
*name
, jsval_t val
)
2219 jsdisp
= iface_to_jsdisp(disp
);
2220 if(!jsdisp
|| jsdisp
->ctx
!= ctx
) {
2221 IDispatchEx
*dispex
;
2225 if(!(str
= SysAllocString(name
)))
2226 return E_OUTOFMEMORY
;
2228 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2229 if(SUCCEEDED(hres
)) {
2230 hres
= IDispatchEx_GetDispID(dispex
, str
, make_grfdex(ctx
, fdexNameEnsure
|fdexNameCaseSensitive
), &id
);
2231 IDispatchEx_Release(dispex
);
2233 TRACE("using IDispatch\n");
2234 hres
= IDispatch_GetIDsOfNames(disp
, &IID_NULL
, &str
, 1, 0, &id
);
2240 return disp_propput(ctx
, disp
, id
, val
);
2243 return jsdisp_propput_name(jsdisp
, name
, val
);
2246 HRESULT
jsdisp_propget_name(jsdisp_t
*obj
, const WCHAR
*name
, jsval_t
*val
)
2248 dispex_prop_t
*prop
;
2251 hres
= find_prop_name_prot(obj
, string_hash(name
), name
, &prop
);
2255 if(!prop
|| prop
->type
==PROP_DELETED
) {
2256 *val
= jsval_undefined();
2260 return prop_get(obj
, prop
, val
);
2263 HRESULT
jsdisp_get_idx(jsdisp_t
*obj
, DWORD idx
, jsval_t
*r
)
2266 dispex_prop_t
*prop
;
2269 swprintf(name
, ARRAY_SIZE(name
), L
"%d", idx
);
2271 hres
= find_prop_name_prot(obj
, string_hash(name
), name
, &prop
);
2275 if(!prop
|| prop
->type
==PROP_DELETED
) {
2276 *r
= jsval_undefined();
2277 return DISP_E_UNKNOWNNAME
;
2280 return prop_get(obj
, prop
, r
);
2283 HRESULT
jsdisp_propget(jsdisp_t
*jsdisp
, DISPID id
, jsval_t
*val
)
2285 dispex_prop_t
*prop
;
2287 prop
= get_prop(jsdisp
, id
);
2289 return DISP_E_MEMBERNOTFOUND
;
2291 return prop_get(jsdisp
, prop
, val
);
2294 HRESULT
disp_propget(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, jsval_t
*val
)
2296 DISPPARAMS dp
= {NULL
,NULL
,0,0};
2301 jsdisp
= iface_to_jsdisp(disp
);
2302 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2303 hres
= jsdisp_propget(jsdisp
, id
, val
);
2304 jsdisp_release(jsdisp
);
2308 V_VT(&var
) = VT_EMPTY
;
2309 hres
= disp_invoke(ctx
, disp
, id
, INVOKE_PROPERTYGET
, &dp
, &var
);
2310 if(SUCCEEDED(hres
)) {
2311 hres
= variant_to_jsval(&var
, val
);
2317 HRESULT
jsdisp_delete_idx(jsdisp_t
*obj
, DWORD idx
)
2320 dispex_prop_t
*prop
;
2324 swprintf(buf
, ARRAY_SIZE(buf
), L
"%d", idx
);
2326 hres
= find_prop_name(obj
, string_hash(buf
), buf
, &prop
);
2327 if(FAILED(hres
) || !prop
)
2330 hres
= delete_prop(prop
, &b
);
2333 return b
? S_OK
: JS_E_INVALID_ACTION
;
2336 HRESULT
disp_delete(IDispatch
*disp
, DISPID id
, BOOL
*ret
)
2338 IDispatchEx
*dispex
;
2342 jsdisp
= iface_to_jsdisp(disp
);
2344 dispex_prop_t
*prop
;
2346 prop
= get_prop(jsdisp
, id
);
2348 hres
= delete_prop(prop
, ret
);
2350 hres
= DISP_E_MEMBERNOTFOUND
;
2352 jsdisp_release(jsdisp
);
2356 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2362 hres
= IDispatchEx_DeleteMemberByDispID(dispex
, id
);
2363 IDispatchEx_Release(dispex
);
2367 *ret
= hres
== S_OK
;
2371 HRESULT
jsdisp_next_prop(jsdisp_t
*obj
, DISPID id
, BOOL own_only
, DISPID
*ret
)
2373 dispex_prop_t
*iter
;
2376 if(id
== DISPID_STARTENUM
&& !own_only
) {
2377 hres
= fill_protrefs(obj
);
2382 if(id
+ 1 < 0 || id
+1 >= obj
->prop_cnt
)
2385 for(iter
= &obj
->props
[id
+ 1]; iter
< obj
->props
+ obj
->prop_cnt
; iter
++) {
2386 if(!iter
->name
|| iter
->type
== PROP_DELETED
)
2388 if(own_only
&& iter
->type
== PROP_PROTREF
)
2390 if(!(get_flags(obj
, iter
) & PROPF_ENUMERABLE
))
2392 *ret
= prop_to_id(obj
, iter
);
2399 HRESULT
disp_delete_name(script_ctx_t
*ctx
, IDispatch
*disp
, jsstr_t
*name
, BOOL
*ret
)
2401 IDispatchEx
*dispex
;
2406 jsdisp
= iface_to_jsdisp(disp
);
2408 dispex_prop_t
*prop
;
2411 ptr
= jsstr_flatten(name
);
2413 jsdisp_release(jsdisp
);
2414 return E_OUTOFMEMORY
;
2417 hres
= find_prop_name(jsdisp
, string_hash(ptr
), ptr
, &prop
);
2419 hres
= delete_prop(prop
, ret
);
2425 jsdisp_release(jsdisp
);
2429 bstr
= SysAllocStringLen(NULL
, jsstr_length(name
));
2431 return E_OUTOFMEMORY
;
2432 jsstr_flush(name
, bstr
);
2434 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2435 if(SUCCEEDED(hres
)) {
2436 hres
= IDispatchEx_DeleteMemberByName(dispex
, bstr
, make_grfdex(ctx
, fdexNameCaseSensitive
));
2438 *ret
= hres
== S_OK
;
2439 IDispatchEx_Release(dispex
);
2443 hres
= IDispatch_GetIDsOfNames(disp
, &IID_NULL
, &bstr
, 1, 0, &id
);
2444 if(SUCCEEDED(hres
)) {
2445 /* Property exists and we can't delete it from pure IDispatch interface, so return false. */
2447 }else if(hres
== DISP_E_UNKNOWNNAME
) {
2448 /* Property doesn't exist, so nothing to delete */
2454 SysFreeString(bstr
);
2458 HRESULT
jsdisp_get_own_property(jsdisp_t
*obj
, const WCHAR
*name
, BOOL flags_only
,
2459 property_desc_t
*desc
)
2461 dispex_prop_t
*prop
;
2464 hres
= find_prop_name(obj
, string_hash(name
), name
, &prop
);
2469 return DISP_E_UNKNOWNNAME
;
2471 memset(desc
, 0, sizeof(*desc
));
2473 switch(prop
->type
) {
2476 desc
->mask
|= PROPF_WRITABLE
;
2477 desc
->explicit_value
= TRUE
;
2479 hres
= prop_get(obj
, prop
, &desc
->value
);
2485 desc
->explicit_getter
= desc
->explicit_setter
= TRUE
;
2487 desc
->getter
= prop
->u
.accessor
.getter
2488 ? jsdisp_addref(prop
->u
.accessor
.getter
) : NULL
;
2489 desc
->setter
= prop
->u
.accessor
.setter
2490 ? jsdisp_addref(prop
->u
.accessor
.setter
) : NULL
;
2494 return DISP_E_UNKNOWNNAME
;
2497 desc
->flags
= prop
->flags
& (PROPF_ENUMERABLE
| PROPF_WRITABLE
| PROPF_CONFIGURABLE
);
2498 desc
->mask
|= PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
;
2502 HRESULT
jsdisp_define_property(jsdisp_t
*obj
, const WCHAR
*name
, property_desc_t
*desc
)
2504 dispex_prop_t
*prop
;
2507 hres
= find_prop_name(obj
, string_hash(name
), name
, &prop
);
2511 if((!prop
|| prop
->type
== PROP_DELETED
) && !obj
->extensible
)
2512 return throw_error(obj
->ctx
, JS_E_OBJECT_NONEXTENSIBLE
, name
);
2514 if(!prop
&& !(prop
= alloc_prop(obj
, name
, PROP_DELETED
, 0)))
2515 return E_OUTOFMEMORY
;
2517 if(prop
->type
== PROP_DELETED
|| prop
->type
== PROP_PROTREF
) {
2518 prop
->flags
= desc
->flags
;
2519 if(desc
->explicit_getter
|| desc
->explicit_setter
) {
2520 prop
->type
= PROP_ACCESSOR
;
2521 prop
->u
.accessor
.getter
= desc
->getter
? jsdisp_addref(desc
->getter
) : NULL
;
2522 prop
->u
.accessor
.setter
= desc
->setter
? jsdisp_addref(desc
->setter
) : NULL
;
2523 TRACE("%s = accessor { get: %p set: %p }\n", debugstr_w(name
),
2524 prop
->u
.accessor
.getter
, prop
->u
.accessor
.setter
);
2526 prop
->type
= PROP_JSVAL
;
2527 if(desc
->explicit_value
) {
2528 hres
= jsval_copy(desc
->value
, &prop
->u
.val
);
2532 prop
->u
.val
= jsval_undefined();
2534 TRACE("%s = %s\n", debugstr_w(name
), debugstr_jsval(prop
->u
.val
));
2539 TRACE("existing prop %s prop flags %x desc flags %x desc mask %x\n", debugstr_w(name
),
2540 prop
->flags
, desc
->flags
, desc
->mask
);
2542 if(!(prop
->flags
& PROPF_CONFIGURABLE
)) {
2543 if(((desc
->mask
& PROPF_CONFIGURABLE
) && (desc
->flags
& PROPF_CONFIGURABLE
))
2544 || ((desc
->mask
& PROPF_ENUMERABLE
)
2545 && ((desc
->flags
& PROPF_ENUMERABLE
) != (prop
->flags
& PROPF_ENUMERABLE
))))
2546 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
2549 if(desc
->explicit_value
|| (desc
->mask
& PROPF_WRITABLE
)) {
2550 if(prop
->type
== PROP_ACCESSOR
) {
2551 if(!(prop
->flags
& PROPF_CONFIGURABLE
))
2552 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
2553 if(prop
->u
.accessor
.getter
)
2554 jsdisp_release(prop
->u
.accessor
.getter
);
2555 if(prop
->u
.accessor
.setter
)
2556 jsdisp_release(prop
->u
.accessor
.setter
);
2558 prop
->type
= PROP_JSVAL
;
2559 hres
= jsval_copy(desc
->value
, &prop
->u
.val
);
2561 prop
->u
.val
= jsval_undefined();
2565 if(!(prop
->flags
& PROPF_CONFIGURABLE
) && !(prop
->flags
& PROPF_WRITABLE
)) {
2566 if((desc
->mask
& PROPF_WRITABLE
) && (desc
->flags
& PROPF_WRITABLE
))
2567 return throw_error(obj
->ctx
, JS_E_NONWRITABLE_MODIFIED
, name
);
2568 if(desc
->explicit_value
) {
2569 if(prop
->type
== PROP_JSVAL
) {
2571 hres
= jsval_strict_equal(desc
->value
, prop
->u
.val
, &eq
);
2575 return throw_error(obj
->ctx
, JS_E_NONWRITABLE_MODIFIED
, name
);
2577 FIXME("redefinition of property type %d\n", prop
->type
);
2581 if(desc
->explicit_value
) {
2582 if(prop
->type
== PROP_JSVAL
)
2583 jsval_release(prop
->u
.val
);
2585 prop
->type
= PROP_JSVAL
;
2586 hres
= jsval_copy(desc
->value
, &prop
->u
.val
);
2588 prop
->u
.val
= jsval_undefined();
2593 }else if(desc
->explicit_getter
|| desc
->explicit_setter
) {
2594 if(prop
->type
!= PROP_ACCESSOR
) {
2595 if(!(prop
->flags
& PROPF_CONFIGURABLE
))
2596 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
2597 if(prop
->type
== PROP_JSVAL
)
2598 jsval_release(prop
->u
.val
);
2599 prop
->type
= PROP_ACCESSOR
;
2600 prop
->u
.accessor
.getter
= prop
->u
.accessor
.setter
= NULL
;
2601 }else if(!(prop
->flags
& PROPF_CONFIGURABLE
)) {
2602 if((desc
->explicit_getter
&& desc
->getter
!= prop
->u
.accessor
.getter
)
2603 || (desc
->explicit_setter
&& desc
->setter
!= prop
->u
.accessor
.setter
))
2604 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
2607 if(desc
->explicit_getter
) {
2608 if(prop
->u
.accessor
.getter
) {
2609 jsdisp_release(prop
->u
.accessor
.getter
);
2610 prop
->u
.accessor
.getter
= NULL
;
2613 prop
->u
.accessor
.getter
= jsdisp_addref(desc
->getter
);
2615 if(desc
->explicit_setter
) {
2616 if(prop
->u
.accessor
.setter
) {
2617 jsdisp_release(prop
->u
.accessor
.setter
);
2618 prop
->u
.accessor
.setter
= NULL
;
2621 prop
->u
.accessor
.setter
= jsdisp_addref(desc
->setter
);
2625 prop
->flags
= (prop
->flags
& ~desc
->mask
) | (desc
->flags
& desc
->mask
);
2629 HRESULT
jsdisp_define_data_property(jsdisp_t
*obj
, const WCHAR
*name
, unsigned flags
, jsval_t value
)
2631 property_desc_t prop_desc
= { flags
, flags
, TRUE
};
2632 prop_desc
.value
= value
;
2633 return jsdisp_define_property(obj
, name
, &prop_desc
);
2636 void jsdisp_freeze(jsdisp_t
*obj
, BOOL seal
)
2640 for(i
= 0; i
< obj
->prop_cnt
; i
++) {
2641 if(!seal
&& obj
->props
[i
].type
== PROP_JSVAL
)
2642 obj
->props
[i
].flags
&= ~PROPF_WRITABLE
;
2643 obj
->props
[i
].flags
&= ~PROPF_CONFIGURABLE
;
2646 obj
->extensible
= FALSE
;
2649 BOOL
jsdisp_is_frozen(jsdisp_t
*obj
, BOOL sealed
)
2656 for(i
= 0; i
< obj
->prop_cnt
; i
++) {
2657 if(obj
->props
[i
].type
== PROP_JSVAL
) {
2658 if(!sealed
&& (obj
->props
[i
].flags
& PROPF_WRITABLE
))
2660 }else if(obj
->props
[i
].type
!= PROP_ACCESSOR
)
2662 if(obj
->props
[i
].flags
& PROPF_CONFIGURABLE
)
2669 HRESULT
jsdisp_get_prop_name(jsdisp_t
*obj
, DISPID id
, jsstr_t
**r
)
2671 dispex_prop_t
*prop
= get_prop(obj
, id
);
2673 if(!prop
|| !prop
->name
|| prop
->type
== PROP_DELETED
)
2674 return DISP_E_MEMBERNOTFOUND
;
2676 *r
= jsstr_alloc(prop
->name
);
2677 return *r
? S_OK
: E_OUTOFMEMORY
;