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
invoke_prop_func(jsdisp_t
*This
, IDispatch
*jsthis
, dispex_prop_t
*prop
, WORD flags
,
393 unsigned argc
, jsval_t
*argv
, jsval_t
*r
, IServiceProvider
*caller
)
399 if(flags
== DISPATCH_CONSTRUCT
&& (prop
->flags
& PROPF_METHOD
)) {
400 WARN("%s is not a constructor\n", debugstr_w(prop
->name
));
404 if(prop
->name
|| This
->builtin_info
->class != JSCLASS_FUNCTION
) {
407 if(This
->builtin_info
->class != JSCLASS_FUNCTION
&& prop
->u
.p
->invoke
!= JSGlobal_eval
)
408 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
410 set_disp(&vthis
, jsthis
);
412 set_jsdisp(&vthis
, This
);
413 hres
= prop
->u
.p
->invoke(This
->ctx
, &vthis
, flags
, argc
, argv
, r
);
414 vdisp_release(&vthis
);
416 /* Function object calls are special case */
417 hres
= Function_invoke(This
, jsthis
, flags
, argc
, argv
, r
);
422 return invoke_prop_func(This
->prototype
, jsthis
? jsthis
: (IDispatch
*)&This
->IDispatchEx_iface
,
423 This
->prototype
->props
+prop
->u
.ref
, flags
, argc
, argv
, r
, caller
);
425 if(!is_object_instance(prop
->u
.val
)) {
426 FIXME("invoke %s\n", debugstr_jsval(prop
->u
.val
));
430 TRACE("call %s %p\n", debugstr_w(prop
->name
), get_object(prop
->u
.val
));
432 return disp_call_value(This
->ctx
, get_object(prop
->u
.val
),
433 jsthis
? jsthis
: (IDispatch
*)&This
->IDispatchEx_iface
,
434 flags
, argc
, argv
, r
);
440 FIXME("Invoking PROP_IDX not yet supported\n");
450 static HRESULT
prop_get(jsdisp_t
*This
, dispex_prop_t
*prop
, jsval_t
*r
)
452 jsdisp_t
*prop_obj
= This
;
455 while(prop
->type
== PROP_PROTREF
) {
456 prop_obj
= prop_obj
->prototype
;
457 prop
= prop_obj
->props
+ prop
->u
.ref
;
462 if(prop
->u
.p
->getter
) {
463 hres
= prop
->u
.p
->getter(This
->ctx
, This
, r
);
467 assert(prop
->u
.p
->invoke
!= NULL
);
468 hres
= create_builtin_function(This
->ctx
, prop
->u
.p
->invoke
, prop
->u
.p
->name
, NULL
,
469 prop
->u
.p
->flags
, NULL
, &obj
);
473 prop
->type
= PROP_JSVAL
;
474 prop
->u
.val
= jsval_obj(obj
);
481 hres
= jsval_copy(prop
->u
.val
, r
);
484 if(prop
->u
.accessor
.getter
) {
485 hres
= jsdisp_call_value(prop
->u
.accessor
.getter
, to_disp(This
),
486 DISPATCH_METHOD
, 0, NULL
, r
);
488 *r
= jsval_undefined();
493 hres
= prop_obj
->builtin_info
->idx_get(prop_obj
, prop
->u
.idx
, r
);
496 ERR("type %d\n", prop
->type
);
501 TRACE("fail %08x\n", hres
);
505 TRACE("%s ret %s\n", debugstr_w(prop
->name
), debugstr_jsval(*r
));
509 static HRESULT
prop_put(jsdisp_t
*This
, dispex_prop_t
*prop
, jsval_t val
)
513 if(prop
->type
== PROP_PROTREF
) {
514 dispex_prop_t
*prop_iter
= prop
;
515 jsdisp_t
*prototype_iter
= This
;
518 prototype_iter
= prototype_iter
->prototype
;
519 prop_iter
= prototype_iter
->props
+ prop_iter
->u
.ref
;
520 } while(prop_iter
->type
== PROP_PROTREF
);
522 if(prop_iter
->type
== PROP_ACCESSOR
)
528 if(!prop
->u
.p
->setter
) {
529 TRACE("getter with no setter\n");
532 return prop
->u
.p
->setter(This
->ctx
, This
, val
);
535 prop
->type
= PROP_JSVAL
;
536 prop
->flags
= PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
;
537 prop
->u
.val
= jsval_undefined();
540 if(!(prop
->flags
& PROPF_WRITABLE
))
543 jsval_release(prop
->u
.val
);
546 if(!prop
->u
.accessor
.setter
) {
547 TRACE("no setter\n");
550 return jsdisp_call_value(prop
->u
.accessor
.setter
, to_disp(This
), DISPATCH_METHOD
, 1, &val
, NULL
);
552 if(!This
->builtin_info
->idx_put
) {
553 TRACE("no put_idx\n");
556 return This
->builtin_info
->idx_put(This
, prop
->u
.idx
, val
);
558 ERR("type %d\n", prop
->type
);
562 TRACE("%s = %s\n", debugstr_w(prop
->name
), debugstr_jsval(val
));
564 hres
= jsval_copy(val
, &prop
->u
.val
);
568 if(This
->builtin_info
->on_put
)
569 This
->builtin_info
->on_put(This
, prop
->name
);
574 HRESULT
builtin_set_const(script_ctx_t
*ctx
, jsdisp_t
*jsthis
, jsval_t value
)
576 TRACE("%p %s\n", jsthis
, debugstr_jsval(value
));
580 static HRESULT
fill_protrefs(jsdisp_t
*This
)
582 dispex_prop_t
*iter
, *prop
;
588 fill_protrefs(This
->prototype
);
590 for(iter
= This
->prototype
->props
; iter
< This
->prototype
->props
+This
->prototype
->prop_cnt
; iter
++) {
593 hres
= find_prop_name(This
, iter
->hash
, iter
->name
, &prop
);
596 if(!prop
|| prop
->type
==PROP_DELETED
) {
598 prop
->type
= PROP_PROTREF
;
600 prop
->u
.ref
= iter
- This
->prototype
->props
;
602 prop
= alloc_protref(This
, iter
->name
, iter
- This
->prototype
->props
);
604 return E_OUTOFMEMORY
;
612 struct typeinfo_func
{
614 function_code_t
*code
;
618 ITypeInfo ITypeInfo_iface
;
619 ITypeComp ITypeComp_iface
;
624 struct typeinfo_func
*funcs
;
625 dispex_prop_t
**vars
;
630 static struct typeinfo_func
*get_func_from_memid(const ScriptTypeInfo
*typeinfo
, MEMBERID memid
)
632 UINT a
= 0, b
= typeinfo
->num_funcs
;
636 UINT i
= (a
+ b
- 1) / 2;
637 MEMBERID func_memid
= prop_to_id(typeinfo
->jsdisp
, typeinfo
->funcs
[i
].prop
);
639 if (memid
== func_memid
)
640 return &typeinfo
->funcs
[i
];
641 else if (memid
< func_memid
)
649 static dispex_prop_t
*get_var_from_memid(const ScriptTypeInfo
*typeinfo
, MEMBERID memid
)
651 UINT a
= 0, b
= typeinfo
->num_vars
;
655 UINT i
= (a
+ b
- 1) / 2;
656 MEMBERID var_memid
= prop_to_id(typeinfo
->jsdisp
, typeinfo
->vars
[i
]);
658 if (memid
== var_memid
)
659 return typeinfo
->vars
[i
];
660 else if (memid
< var_memid
)
668 static inline ScriptTypeInfo
*ScriptTypeInfo_from_ITypeInfo(ITypeInfo
*iface
)
670 return CONTAINING_RECORD(iface
, ScriptTypeInfo
, ITypeInfo_iface
);
673 static inline ScriptTypeInfo
*ScriptTypeInfo_from_ITypeComp(ITypeComp
*iface
)
675 return CONTAINING_RECORD(iface
, ScriptTypeInfo
, ITypeComp_iface
);
678 static HRESULT WINAPI
ScriptTypeInfo_QueryInterface(ITypeInfo
*iface
, REFIID riid
, void **ppv
)
680 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
682 if (IsEqualGUID(&IID_IUnknown
, riid
) || IsEqualGUID(&IID_ITypeInfo
, riid
))
683 *ppv
= &This
->ITypeInfo_iface
;
684 else if (IsEqualGUID(&IID_ITypeComp
, riid
))
685 *ppv
= &This
->ITypeComp_iface
;
688 WARN("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
690 return E_NOINTERFACE
;
693 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
694 IUnknown_AddRef((IUnknown
*)*ppv
);
698 static ULONG WINAPI
ScriptTypeInfo_AddRef(ITypeInfo
*iface
)
700 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
701 LONG ref
= InterlockedIncrement(&This
->ref
);
703 TRACE("(%p) ref=%d\n", This
, ref
);
708 static ULONG WINAPI
ScriptTypeInfo_Release(ITypeInfo
*iface
)
710 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
711 LONG ref
= InterlockedDecrement(&This
->ref
);
714 TRACE("(%p) ref=%d\n", This
, ref
);
718 for (i
= This
->num_funcs
; i
--;)
719 release_bytecode(This
->funcs
[i
].code
->bytecode
);
720 IDispatchEx_Release(&This
->jsdisp
->IDispatchEx_iface
);
721 heap_free(This
->funcs
);
722 heap_free(This
->vars
);
728 static HRESULT WINAPI
ScriptTypeInfo_GetTypeAttr(ITypeInfo
*iface
, TYPEATTR
**ppTypeAttr
)
730 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
733 TRACE("(%p)->(%p)\n", This
, ppTypeAttr
);
735 if (!ppTypeAttr
) return E_INVALIDARG
;
737 attr
= heap_alloc_zero(sizeof(*attr
));
738 if (!attr
) return E_OUTOFMEMORY
;
740 attr
->guid
= GUID_JScriptTypeInfo
;
741 attr
->lcid
= LOCALE_USER_DEFAULT
;
742 attr
->memidConstructor
= MEMBERID_NIL
;
743 attr
->memidDestructor
= MEMBERID_NIL
;
744 attr
->cbSizeInstance
= 4;
745 attr
->typekind
= TKIND_DISPATCH
;
746 attr
->cFuncs
= This
->num_funcs
;
747 attr
->cVars
= This
->num_vars
;
748 attr
->cImplTypes
= 1;
749 attr
->cbSizeVft
= sizeof(IDispatchVtbl
);
750 attr
->cbAlignment
= 4;
751 attr
->wTypeFlags
= TYPEFLAG_FDISPATCHABLE
;
752 attr
->wMajorVerNum
= JSCRIPT_MAJOR_VERSION
;
753 attr
->wMinorVerNum
= JSCRIPT_MINOR_VERSION
;
759 static HRESULT WINAPI
ScriptTypeInfo_GetTypeComp(ITypeInfo
*iface
, ITypeComp
**ppTComp
)
761 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
763 TRACE("(%p)->(%p)\n", This
, ppTComp
);
765 if (!ppTComp
) return E_INVALIDARG
;
767 *ppTComp
= &This
->ITypeComp_iface
;
768 ITypeInfo_AddRef(iface
);
772 static HRESULT WINAPI
ScriptTypeInfo_GetFuncDesc(ITypeInfo
*iface
, UINT index
, FUNCDESC
**ppFuncDesc
)
774 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
775 struct typeinfo_func
*func
;
779 TRACE("(%p)->(%u %p)\n", This
, index
, ppFuncDesc
);
781 if (!ppFuncDesc
) return E_INVALIDARG
;
782 if (index
>= This
->num_funcs
) return TYPE_E_ELEMENTNOTFOUND
;
783 func
= &This
->funcs
[index
];
785 /* Store the parameter array after the FUNCDESC structure */
786 desc
= heap_alloc_zero(sizeof(*desc
) + sizeof(ELEMDESC
) * func
->code
->param_cnt
);
787 if (!desc
) return E_OUTOFMEMORY
;
789 desc
->memid
= prop_to_id(This
->jsdisp
, func
->prop
);
790 desc
->funckind
= FUNC_DISPATCH
;
791 desc
->invkind
= INVOKE_FUNC
;
792 desc
->callconv
= CC_STDCALL
;
793 desc
->cParams
= func
->code
->param_cnt
;
794 desc
->elemdescFunc
.tdesc
.vt
= VT_VARIANT
;
796 if (func
->code
->param_cnt
) desc
->lprgelemdescParam
= (ELEMDESC
*)(desc
+ 1);
797 for (i
= 0; i
< func
->code
->param_cnt
; i
++)
798 desc
->lprgelemdescParam
[i
].tdesc
.vt
= VT_VARIANT
;
804 static HRESULT WINAPI
ScriptTypeInfo_GetVarDesc(ITypeInfo
*iface
, UINT index
, VARDESC
**ppVarDesc
)
806 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
809 TRACE("(%p)->(%u %p)\n", This
, index
, ppVarDesc
);
811 if (!ppVarDesc
) return E_INVALIDARG
;
812 if (index
>= This
->num_vars
) return TYPE_E_ELEMENTNOTFOUND
;
814 desc
= heap_alloc_zero(sizeof(*desc
));
815 if (!desc
) return E_OUTOFMEMORY
;
817 desc
->memid
= prop_to_id(This
->jsdisp
, This
->vars
[index
]);
818 desc
->varkind
= VAR_DISPATCH
;
819 desc
->elemdescVar
.tdesc
.vt
= VT_VARIANT
;
825 static HRESULT WINAPI
ScriptTypeInfo_GetNames(ITypeInfo
*iface
, MEMBERID memid
, BSTR
*rgBstrNames
,
826 UINT cMaxNames
, UINT
*pcNames
)
828 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
829 struct typeinfo_func
*func
;
830 ITypeInfo
*disp_typeinfo
;
835 TRACE("(%p)->(%d %p %u %p)\n", This
, memid
, rgBstrNames
, cMaxNames
, pcNames
);
837 if (!rgBstrNames
|| !pcNames
) return E_INVALIDARG
;
838 if (memid
<= 0) return TYPE_E_ELEMENTNOTFOUND
;
840 func
= get_func_from_memid(This
, memid
);
843 var
= get_var_from_memid(This
, memid
);
846 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
847 if (FAILED(hr
)) return hr
;
849 return ITypeInfo_GetNames(disp_typeinfo
, memid
, rgBstrNames
, cMaxNames
, pcNames
);
854 if (!cMaxNames
) return S_OK
;
856 rgBstrNames
[0] = SysAllocString(func
? func
->prop
->name
: var
->name
);
857 if (!rgBstrNames
[0]) return E_OUTOFMEMORY
;
862 unsigned num
= min(cMaxNames
, func
->code
->param_cnt
+ 1);
866 if (!(rgBstrNames
[i
] = SysAllocString(func
->code
->params
[i
- 1])))
868 do SysFreeString(rgBstrNames
[--i
]); while (i
);
869 return E_OUTOFMEMORY
;
878 static HRESULT WINAPI
ScriptTypeInfo_GetRefTypeOfImplType(ITypeInfo
*iface
, UINT index
, HREFTYPE
*pRefType
)
880 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
882 TRACE("(%p)->(%u %p)\n", This
, index
, pRefType
);
884 /* We only inherit from IDispatch */
885 if (!pRefType
) return E_INVALIDARG
;
886 if (index
!= 0) return TYPE_E_ELEMENTNOTFOUND
;
892 static HRESULT WINAPI
ScriptTypeInfo_GetImplTypeFlags(ITypeInfo
*iface
, UINT index
, INT
*pImplTypeFlags
)
894 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
896 TRACE("(%p)->(%u %p)\n", This
, index
, pImplTypeFlags
);
898 if (!pImplTypeFlags
) return E_INVALIDARG
;
899 if (index
!= 0) return TYPE_E_ELEMENTNOTFOUND
;
905 static HRESULT WINAPI
ScriptTypeInfo_GetIDsOfNames(ITypeInfo
*iface
, LPOLESTR
*rgszNames
, UINT cNames
,
908 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
909 ITypeInfo
*disp_typeinfo
;
914 TRACE("(%p)->(%p %u %p)\n", This
, rgszNames
, cNames
, pMemId
);
916 if (!rgszNames
|| !cNames
|| !pMemId
) return E_INVALIDARG
;
918 for (i
= 0; i
< cNames
; i
++) pMemId
[i
] = MEMBERID_NIL
;
921 for (i
= 0; i
< This
->num_funcs
; i
++)
923 struct typeinfo_func
*func
= &This
->funcs
[i
];
925 if (wcsicmp(name
, func
->prop
->name
)) continue;
926 pMemId
[0] = prop_to_id(This
->jsdisp
, func
->prop
);
928 for (j
= 1; j
< cNames
; j
++)
931 for (arg
= func
->code
->param_cnt
; --arg
>= 0;)
932 if (!wcsicmp(name
, func
->code
->params
[arg
]))
937 hr
= DISP_E_UNKNOWNNAME
;
942 for (i
= 0; i
< This
->num_vars
; i
++)
944 dispex_prop_t
*var
= This
->vars
[i
];
946 if (wcsicmp(name
, var
->name
)) continue;
947 pMemId
[0] = prop_to_id(This
->jsdisp
, var
);
951 /* Look into the inherited IDispatch */
952 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
953 if (FAILED(hr
)) return hr
;
955 return ITypeInfo_GetIDsOfNames(disp_typeinfo
, rgszNames
, cNames
, pMemId
);
958 static HRESULT WINAPI
ScriptTypeInfo_Invoke(ITypeInfo
*iface
, PVOID pvInstance
, MEMBERID memid
, WORD wFlags
,
959 DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
961 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
962 ITypeInfo
*disp_typeinfo
;
966 TRACE("(%p)->(%p %d %d %p %p %p %p)\n", This
, pvInstance
, memid
, wFlags
,
967 pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
969 if (!pvInstance
) return E_INVALIDARG
;
970 if (memid
<= 0) return TYPE_E_ELEMENTNOTFOUND
;
972 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
974 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
975 if (FAILED(hr
)) return hr
;
977 return ITypeInfo_Invoke(disp_typeinfo
, pvInstance
, memid
, wFlags
, pDispParams
,
978 pVarResult
, pExcepInfo
, puArgErr
);
981 hr
= IUnknown_QueryInterface((IUnknown
*)pvInstance
, &IID_IDispatch
, (void**)&disp
);
982 if (FAILED(hr
)) return hr
;
984 hr
= IDispatch_Invoke(disp
, memid
, &IID_NULL
, LOCALE_USER_DEFAULT
, wFlags
,
985 pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
986 IDispatch_Release(disp
);
991 static HRESULT WINAPI
ScriptTypeInfo_GetDocumentation(ITypeInfo
*iface
, MEMBERID memid
, BSTR
*pBstrName
,
992 BSTR
*pBstrDocString
, DWORD
*pdwHelpContext
, BSTR
*pBstrHelpFile
)
994 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
995 struct typeinfo_func
*func
;
996 ITypeInfo
*disp_typeinfo
;
1000 TRACE("(%p)->(%d %p %p %p %p)\n", This
, memid
, pBstrName
, pBstrDocString
, pdwHelpContext
, pBstrHelpFile
);
1002 if (pBstrDocString
) *pBstrDocString
= NULL
;
1003 if (pdwHelpContext
) *pdwHelpContext
= 0;
1004 if (pBstrHelpFile
) *pBstrHelpFile
= NULL
;
1006 if (memid
== MEMBERID_NIL
)
1008 if (pBstrName
&& !(*pBstrName
= SysAllocString(L
"JScriptTypeInfo")))
1009 return E_OUTOFMEMORY
;
1010 if (pBstrDocString
&&
1011 !(*pBstrDocString
= SysAllocString(L
"JScript Type Info")))
1013 if (pBstrName
) SysFreeString(*pBstrName
);
1014 return E_OUTOFMEMORY
;
1018 if (memid
<= 0) return TYPE_E_ELEMENTNOTFOUND
;
1020 func
= get_func_from_memid(This
, memid
);
1023 var
= get_var_from_memid(This
, memid
);
1026 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1027 if (FAILED(hr
)) return hr
;
1029 return ITypeInfo_GetDocumentation(disp_typeinfo
, memid
, pBstrName
, pBstrDocString
,
1030 pdwHelpContext
, pBstrHelpFile
);
1036 *pBstrName
= SysAllocString(func
? func
->prop
->name
: var
->name
);
1039 return E_OUTOFMEMORY
;
1044 static HRESULT WINAPI
ScriptTypeInfo_GetDllEntry(ITypeInfo
*iface
, MEMBERID memid
, INVOKEKIND invKind
,
1045 BSTR
*pBstrDllName
, BSTR
*pBstrName
, WORD
*pwOrdinal
)
1047 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1048 ITypeInfo
*disp_typeinfo
;
1051 TRACE("(%p)->(%d %d %p %p %p)\n", This
, memid
, invKind
, pBstrDllName
, pBstrName
, pwOrdinal
);
1053 if (pBstrDllName
) *pBstrDllName
= NULL
;
1054 if (pBstrName
) *pBstrName
= NULL
;
1055 if (pwOrdinal
) *pwOrdinal
= 0;
1057 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
1059 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1060 if (FAILED(hr
)) return hr
;
1062 return ITypeInfo_GetDllEntry(disp_typeinfo
, memid
, invKind
, pBstrDllName
, pBstrName
, pwOrdinal
);
1064 return TYPE_E_BADMODULEKIND
;
1067 static HRESULT WINAPI
ScriptTypeInfo_GetRefTypeInfo(ITypeInfo
*iface
, HREFTYPE hRefType
, ITypeInfo
**ppTInfo
)
1069 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1072 TRACE("(%p)->(%x %p)\n", This
, hRefType
, ppTInfo
);
1074 if (!ppTInfo
|| (INT
)hRefType
< 0) return E_INVALIDARG
;
1076 if (hRefType
& ~3) return E_FAIL
;
1079 hr
= get_dispatch_typeinfo(ppTInfo
);
1080 if (FAILED(hr
)) return hr
;
1085 ITypeInfo_AddRef(*ppTInfo
);
1089 static HRESULT WINAPI
ScriptTypeInfo_AddressOfMember(ITypeInfo
*iface
, MEMBERID memid
, INVOKEKIND invKind
, PVOID
*ppv
)
1091 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1092 ITypeInfo
*disp_typeinfo
;
1095 TRACE("(%p)->(%d %d %p)\n", This
, memid
, invKind
, ppv
);
1097 if (!ppv
) return E_INVALIDARG
;
1100 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
1102 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1103 if (FAILED(hr
)) return hr
;
1105 return ITypeInfo_AddressOfMember(disp_typeinfo
, memid
, invKind
, ppv
);
1107 return TYPE_E_BADMODULEKIND
;
1110 static HRESULT WINAPI
ScriptTypeInfo_CreateInstance(ITypeInfo
*iface
, IUnknown
*pUnkOuter
, REFIID riid
, PVOID
*ppvObj
)
1112 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1114 TRACE("(%p)->(%p %s %p)\n", This
, pUnkOuter
, debugstr_guid(riid
), ppvObj
);
1116 if (!ppvObj
) return E_INVALIDARG
;
1119 return TYPE_E_BADMODULEKIND
;
1122 static HRESULT WINAPI
ScriptTypeInfo_GetMops(ITypeInfo
*iface
, MEMBERID memid
, BSTR
*pBstrMops
)
1124 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1125 ITypeInfo
*disp_typeinfo
;
1128 TRACE("(%p)->(%d %p)\n", This
, memid
, pBstrMops
);
1130 if (!pBstrMops
) return E_INVALIDARG
;
1132 if (!get_func_from_memid(This
, memid
) && !get_var_from_memid(This
, memid
))
1134 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1135 if (FAILED(hr
)) return hr
;
1137 return ITypeInfo_GetMops(disp_typeinfo
, memid
, pBstrMops
);
1144 static HRESULT WINAPI
ScriptTypeInfo_GetContainingTypeLib(ITypeInfo
*iface
, ITypeLib
**ppTLib
, UINT
*pIndex
)
1146 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1148 FIXME("(%p)->(%p %p)\n", This
, ppTLib
, pIndex
);
1153 static void WINAPI
ScriptTypeInfo_ReleaseTypeAttr(ITypeInfo
*iface
, TYPEATTR
*pTypeAttr
)
1155 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1157 TRACE("(%p)->(%p)\n", This
, pTypeAttr
);
1159 heap_free(pTypeAttr
);
1162 static void WINAPI
ScriptTypeInfo_ReleaseFuncDesc(ITypeInfo
*iface
, FUNCDESC
*pFuncDesc
)
1164 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1166 TRACE("(%p)->(%p)\n", This
, pFuncDesc
);
1168 heap_free(pFuncDesc
);
1171 static void WINAPI
ScriptTypeInfo_ReleaseVarDesc(ITypeInfo
*iface
, VARDESC
*pVarDesc
)
1173 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeInfo(iface
);
1175 TRACE("(%p)->(%p)\n", This
, pVarDesc
);
1177 heap_free(pVarDesc
);
1180 static const ITypeInfoVtbl ScriptTypeInfoVtbl
= {
1181 ScriptTypeInfo_QueryInterface
,
1182 ScriptTypeInfo_AddRef
,
1183 ScriptTypeInfo_Release
,
1184 ScriptTypeInfo_GetTypeAttr
,
1185 ScriptTypeInfo_GetTypeComp
,
1186 ScriptTypeInfo_GetFuncDesc
,
1187 ScriptTypeInfo_GetVarDesc
,
1188 ScriptTypeInfo_GetNames
,
1189 ScriptTypeInfo_GetRefTypeOfImplType
,
1190 ScriptTypeInfo_GetImplTypeFlags
,
1191 ScriptTypeInfo_GetIDsOfNames
,
1192 ScriptTypeInfo_Invoke
,
1193 ScriptTypeInfo_GetDocumentation
,
1194 ScriptTypeInfo_GetDllEntry
,
1195 ScriptTypeInfo_GetRefTypeInfo
,
1196 ScriptTypeInfo_AddressOfMember
,
1197 ScriptTypeInfo_CreateInstance
,
1198 ScriptTypeInfo_GetMops
,
1199 ScriptTypeInfo_GetContainingTypeLib
,
1200 ScriptTypeInfo_ReleaseTypeAttr
,
1201 ScriptTypeInfo_ReleaseFuncDesc
,
1202 ScriptTypeInfo_ReleaseVarDesc
1205 static HRESULT WINAPI
ScriptTypeComp_QueryInterface(ITypeComp
*iface
, REFIID riid
, void **ppv
)
1207 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1208 return ITypeInfo_QueryInterface(&This
->ITypeInfo_iface
, riid
, ppv
);
1211 static ULONG WINAPI
ScriptTypeComp_AddRef(ITypeComp
*iface
)
1213 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1214 return ITypeInfo_AddRef(&This
->ITypeInfo_iface
);
1217 static ULONG WINAPI
ScriptTypeComp_Release(ITypeComp
*iface
)
1219 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1220 return ITypeInfo_Release(&This
->ITypeInfo_iface
);
1223 static HRESULT WINAPI
ScriptTypeComp_Bind(ITypeComp
*iface
, LPOLESTR szName
, ULONG lHashVal
, WORD wFlags
,
1224 ITypeInfo
**ppTInfo
, DESCKIND
*pDescKind
, BINDPTR
*pBindPtr
)
1226 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1227 UINT flags
= wFlags
? wFlags
: ~0;
1228 ITypeInfo
*disp_typeinfo
;
1229 ITypeComp
*disp_typecomp
;
1233 TRACE("(%p)->(%s %08x %d %p %p %p)\n", This
, debugstr_w(szName
), lHashVal
,
1234 wFlags
, ppTInfo
, pDescKind
, pBindPtr
);
1236 if (!szName
|| !ppTInfo
|| !pDescKind
|| !pBindPtr
)
1237 return E_INVALIDARG
;
1239 for (i
= 0; i
< This
->num_funcs
; i
++)
1241 if (wcsicmp(szName
, This
->funcs
[i
].prop
->name
)) continue;
1242 if (!(flags
& INVOKE_FUNC
)) return TYPE_E_TYPEMISMATCH
;
1244 hr
= ITypeInfo_GetFuncDesc(&This
->ITypeInfo_iface
, i
, &pBindPtr
->lpfuncdesc
);
1245 if (FAILED(hr
)) return hr
;
1247 *pDescKind
= DESCKIND_FUNCDESC
;
1248 *ppTInfo
= &This
->ITypeInfo_iface
;
1249 ITypeInfo_AddRef(*ppTInfo
);
1253 for (i
= 0; i
< This
->num_vars
; i
++)
1255 if (wcsicmp(szName
, This
->vars
[i
]->name
)) continue;
1256 if (!(flags
& INVOKE_PROPERTYGET
)) return TYPE_E_TYPEMISMATCH
;
1258 hr
= ITypeInfo_GetVarDesc(&This
->ITypeInfo_iface
, i
, &pBindPtr
->lpvardesc
);
1259 if (FAILED(hr
)) return hr
;
1261 *pDescKind
= DESCKIND_VARDESC
;
1262 *ppTInfo
= &This
->ITypeInfo_iface
;
1263 ITypeInfo_AddRef(*ppTInfo
);
1267 /* Look into the inherited IDispatch */
1268 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1269 if (FAILED(hr
)) return hr
;
1271 hr
= ITypeInfo_GetTypeComp(disp_typeinfo
, &disp_typecomp
);
1272 if (FAILED(hr
)) return hr
;
1274 hr
= ITypeComp_Bind(disp_typecomp
, szName
, lHashVal
, wFlags
, ppTInfo
, pDescKind
, pBindPtr
);
1275 ITypeComp_Release(disp_typecomp
);
1279 static HRESULT WINAPI
ScriptTypeComp_BindType(ITypeComp
*iface
, LPOLESTR szName
, ULONG lHashVal
,
1280 ITypeInfo
**ppTInfo
, ITypeComp
**ppTComp
)
1282 ScriptTypeInfo
*This
= ScriptTypeInfo_from_ITypeComp(iface
);
1283 ITypeInfo
*disp_typeinfo
;
1284 ITypeComp
*disp_typecomp
;
1287 TRACE("(%p)->(%s %08x %p %p)\n", This
, debugstr_w(szName
), lHashVal
, ppTInfo
, ppTComp
);
1289 if (!szName
|| !ppTInfo
|| !ppTComp
)
1290 return E_INVALIDARG
;
1292 /* Look into the inherited IDispatch */
1293 hr
= get_dispatch_typeinfo(&disp_typeinfo
);
1294 if (FAILED(hr
)) return hr
;
1296 hr
= ITypeInfo_GetTypeComp(disp_typeinfo
, &disp_typecomp
);
1297 if (FAILED(hr
)) return hr
;
1299 hr
= ITypeComp_BindType(disp_typecomp
, szName
, lHashVal
, ppTInfo
, ppTComp
);
1300 ITypeComp_Release(disp_typecomp
);
1304 static const ITypeCompVtbl ScriptTypeCompVtbl
= {
1305 ScriptTypeComp_QueryInterface
,
1306 ScriptTypeComp_AddRef
,
1307 ScriptTypeComp_Release
,
1308 ScriptTypeComp_Bind
,
1309 ScriptTypeComp_BindType
1312 static inline jsdisp_t
*impl_from_IDispatchEx(IDispatchEx
*iface
)
1314 return CONTAINING_RECORD(iface
, jsdisp_t
, IDispatchEx_iface
);
1317 static HRESULT WINAPI
DispatchEx_QueryInterface(IDispatchEx
*iface
, REFIID riid
, void **ppv
)
1319 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1321 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
1322 TRACE("(%p)->(IID_IUnknown %p)\n", This
, ppv
);
1323 *ppv
= &This
->IDispatchEx_iface
;
1324 }else if(IsEqualGUID(&IID_IDispatch
, riid
)) {
1325 TRACE("(%p)->(IID_IDispatch %p)\n", This
, ppv
);
1326 *ppv
= &This
->IDispatchEx_iface
;
1327 }else if(IsEqualGUID(&IID_IDispatchEx
, riid
)) {
1328 TRACE("(%p)->(IID_IDispatchEx %p)\n", This
, ppv
);
1329 *ppv
= &This
->IDispatchEx_iface
;
1331 WARN("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
1333 return E_NOINTERFACE
;
1336 jsdisp_addref(This
);
1340 static ULONG WINAPI
DispatchEx_AddRef(IDispatchEx
*iface
)
1342 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1343 jsdisp_addref(This
);
1347 static ULONG WINAPI
DispatchEx_Release(IDispatchEx
*iface
)
1349 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1350 ULONG ref
= --This
->ref
;
1351 TRACE("(%p) ref=%d\n", This
, ref
);
1357 static HRESULT WINAPI
DispatchEx_GetTypeInfoCount(IDispatchEx
*iface
, UINT
*pctinfo
)
1359 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1361 TRACE("(%p)->(%p)\n", This
, pctinfo
);
1367 static HRESULT WINAPI
DispatchEx_GetTypeInfo(IDispatchEx
*iface
, UINT iTInfo
, LCID lcid
,
1368 ITypeInfo
**ppTInfo
)
1370 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1371 dispex_prop_t
*prop
, *cur
, *end
, **typevar
;
1372 UINT num_funcs
= 0, num_vars
= 0;
1373 struct typeinfo_func
*typefunc
;
1374 function_code_t
*func_code
;
1375 ScriptTypeInfo
*typeinfo
;
1378 TRACE("(%p)->(%u %u %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
1380 if (iTInfo
!= 0) return DISP_E_BADINDEX
;
1382 for (prop
= This
->props
, end
= prop
+ This
->prop_cnt
; prop
!= end
; prop
++)
1384 if (!prop
->name
|| prop
->type
!= PROP_JSVAL
|| !(prop
->flags
& PROPF_ENUMERABLE
))
1387 /* If two identifiers differ only by case, the TypeInfo fails */
1388 pos
= This
->props
[get_props_idx(This
, prop
->hash
)].bucket_head
;
1391 cur
= This
->props
+ pos
;
1393 if (prop
->hash
== cur
->hash
&& prop
!= cur
&&
1394 cur
->type
== PROP_JSVAL
&& (cur
->flags
& PROPF_ENUMERABLE
) &&
1395 !wcsicmp(prop
->name
, cur
->name
))
1397 return TYPE_E_AMBIGUOUSNAME
;
1399 pos
= cur
->bucket_next
;
1402 if (is_function_prop(prop
))
1404 if (Function_get_code(as_jsdisp(get_object(prop
->u
.val
))))
1410 if (!(typeinfo
= heap_alloc(sizeof(*typeinfo
))))
1411 return E_OUTOFMEMORY
;
1413 typeinfo
->ITypeInfo_iface
.lpVtbl
= &ScriptTypeInfoVtbl
;
1414 typeinfo
->ITypeComp_iface
.lpVtbl
= &ScriptTypeCompVtbl
;
1416 typeinfo
->num_vars
= num_vars
;
1417 typeinfo
->num_funcs
= num_funcs
;
1418 typeinfo
->jsdisp
= This
;
1420 typeinfo
->funcs
= heap_alloc(sizeof(*typeinfo
->funcs
) * num_funcs
);
1421 if (!typeinfo
->funcs
)
1423 heap_free(typeinfo
);
1424 return E_OUTOFMEMORY
;
1427 typeinfo
->vars
= heap_alloc(sizeof(*typeinfo
->vars
) * num_vars
);
1428 if (!typeinfo
->vars
)
1430 heap_free(typeinfo
->funcs
);
1431 heap_free(typeinfo
);
1432 return E_OUTOFMEMORY
;
1435 typefunc
= typeinfo
->funcs
;
1436 typevar
= typeinfo
->vars
;
1437 for (prop
= This
->props
; prop
!= end
; prop
++)
1439 if (!prop
->name
|| prop
->type
!= PROP_JSVAL
|| !(prop
->flags
& PROPF_ENUMERABLE
))
1442 if (is_function_prop(prop
))
1444 func_code
= Function_get_code(as_jsdisp(get_object(prop
->u
.val
)));
1445 if (!func_code
) continue;
1447 typefunc
->prop
= prop
;
1448 typefunc
->code
= func_code
;
1451 /* The function may be deleted, so keep a ref */
1452 bytecode_addref(func_code
->bytecode
);
1458 /* Keep a ref to the props and their names */
1459 IDispatchEx_AddRef(&This
->IDispatchEx_iface
);
1461 *ppTInfo
= &typeinfo
->ITypeInfo_iface
;
1465 static HRESULT WINAPI
DispatchEx_GetIDsOfNames(IDispatchEx
*iface
, REFIID riid
,
1466 LPOLESTR
*rgszNames
, UINT cNames
, LCID lcid
,
1469 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1473 TRACE("(%p)->(%s %p %u %u %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
,
1476 for(i
=0; i
< cNames
; i
++) {
1477 hres
= IDispatchEx_GetDispID(&This
->IDispatchEx_iface
, rgszNames
[i
], 0, rgDispId
+i
);
1485 static HRESULT WINAPI
DispatchEx_Invoke(IDispatchEx
*iface
, DISPID dispIdMember
,
1486 REFIID riid
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
,
1487 VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
1489 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1491 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This
, dispIdMember
, debugstr_guid(riid
),
1492 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
1494 return IDispatchEx_InvokeEx(&This
->IDispatchEx_iface
, dispIdMember
, lcid
, wFlags
,
1495 pDispParams
, pVarResult
, pExcepInfo
, NULL
);
1498 static HRESULT WINAPI
DispatchEx_GetDispID(IDispatchEx
*iface
, BSTR bstrName
, DWORD grfdex
, DISPID
*pid
)
1500 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1502 TRACE("(%p)->(%s %x %p)\n", This
, debugstr_w(bstrName
), grfdex
, pid
);
1504 if(grfdex
& ~(fdexNameCaseSensitive
|fdexNameEnsure
|fdexNameImplicit
|FDEX_VERSION_MASK
)) {
1505 FIXME("Unsupported grfdex %x\n", grfdex
);
1509 return jsdisp_get_id(This
, bstrName
, grfdex
, pid
);
1512 static HRESULT WINAPI
DispatchEx_InvokeEx(IDispatchEx
*iface
, DISPID id
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pdp
,
1513 VARIANT
*pvarRes
, EXCEPINFO
*pei
, IServiceProvider
*pspCaller
)
1515 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1516 dispex_prop_t
*prop
;
1520 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This
, id
, lcid
, wFlags
, pdp
, pvarRes
, pei
, pspCaller
);
1523 V_VT(pvarRes
) = VT_EMPTY
;
1525 prop
= get_prop(This
, id
);
1526 if(!prop
|| prop
->type
== PROP_DELETED
) {
1527 TRACE("invalid id\n");
1528 return DISP_E_MEMBERNOTFOUND
;
1531 enter_script(This
->ctx
, &ei
);
1534 case DISPATCH_METHOD
|DISPATCH_PROPERTYGET
:
1535 wFlags
= DISPATCH_METHOD
;
1537 case DISPATCH_METHOD
:
1538 case DISPATCH_CONSTRUCT
: {
1539 jsval_t
*argv
, buf
[6], r
;
1542 hres
= convert_params(pdp
, buf
, &argc
, &argv
);
1546 hres
= invoke_prop_func(This
, get_this(pdp
), prop
, wFlags
, argc
, argv
, pvarRes
? &r
: NULL
, pspCaller
);
1549 if(SUCCEEDED(hres
) && pvarRes
) {
1550 hres
= jsval_to_variant(r
, pvarRes
);
1555 case DISPATCH_PROPERTYGET
: {
1558 hres
= prop_get(This
, prop
, &r
);
1559 if(SUCCEEDED(hres
)) {
1560 hres
= jsval_to_variant(r
, pvarRes
);
1565 case DISPATCH_PROPERTYPUT
: {
1569 for(i
=0; i
< pdp
->cNamedArgs
; i
++) {
1570 if(pdp
->rgdispidNamedArgs
[i
] == DISPID_PROPERTYPUT
)
1574 if(i
== pdp
->cNamedArgs
) {
1575 TRACE("no value to set\n");
1576 hres
= DISP_E_PARAMNOTOPTIONAL
;
1580 hres
= variant_to_jsval(pdp
->rgvarg
+i
, &val
);
1584 hres
= prop_put(This
, prop
, val
);
1589 FIXME("Unimplemented flags %x\n", wFlags
);
1590 hres
= E_INVALIDARG
;
1594 return leave_script(This
->ctx
, hres
);
1597 static HRESULT
delete_prop(dispex_prop_t
*prop
, BOOL
*ret
)
1599 if(!(prop
->flags
& PROPF_CONFIGURABLE
)) {
1604 *ret
= TRUE
; /* FIXME: not exactly right */
1606 if(prop
->type
== PROP_JSVAL
) {
1607 jsval_release(prop
->u
.val
);
1608 prop
->type
= PROP_DELETED
;
1610 if(prop
->type
== PROP_ACCESSOR
)
1611 FIXME("not supported on accessor property\n");
1615 static HRESULT WINAPI
DispatchEx_DeleteMemberByName(IDispatchEx
*iface
, BSTR bstrName
, DWORD grfdex
)
1617 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1618 dispex_prop_t
*prop
;
1622 TRACE("(%p)->(%s %x)\n", This
, debugstr_w(bstrName
), grfdex
);
1624 if(grfdex
& ~(fdexNameCaseSensitive
|fdexNameEnsure
|fdexNameImplicit
|FDEX_VERSION_MASK
))
1625 FIXME("Unsupported grfdex %x\n", grfdex
);
1627 hres
= find_prop_name(This
, string_hash(bstrName
), bstrName
, &prop
);
1631 TRACE("not found\n");
1635 return delete_prop(prop
, &b
);
1638 static HRESULT WINAPI
DispatchEx_DeleteMemberByDispID(IDispatchEx
*iface
, DISPID id
)
1640 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1641 dispex_prop_t
*prop
;
1644 TRACE("(%p)->(%x)\n", This
, id
);
1646 prop
= get_prop(This
, id
);
1648 WARN("invalid id\n");
1649 return DISP_E_MEMBERNOTFOUND
;
1652 return delete_prop(prop
, &b
);
1655 static HRESULT WINAPI
DispatchEx_GetMemberProperties(IDispatchEx
*iface
, DISPID id
, DWORD grfdexFetch
, DWORD
*pgrfdex
)
1657 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1658 FIXME("(%p)->(%x %x %p)\n", This
, id
, grfdexFetch
, pgrfdex
);
1662 static HRESULT WINAPI
DispatchEx_GetMemberName(IDispatchEx
*iface
, DISPID id
, BSTR
*pbstrName
)
1664 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1665 dispex_prop_t
*prop
;
1667 TRACE("(%p)->(%x %p)\n", This
, id
, pbstrName
);
1669 prop
= get_prop(This
, id
);
1670 if(!prop
|| !prop
->name
|| prop
->type
== PROP_DELETED
)
1671 return DISP_E_MEMBERNOTFOUND
;
1673 *pbstrName
= SysAllocString(prop
->name
);
1675 return E_OUTOFMEMORY
;
1680 static HRESULT WINAPI
DispatchEx_GetNextDispID(IDispatchEx
*iface
, DWORD grfdex
, DISPID id
, DISPID
*pid
)
1682 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1685 TRACE("(%p)->(%x %x %p)\n", This
, grfdex
, id
, pid
);
1687 hres
= jsdisp_next_prop(This
, id
, FALSE
, pid
);
1689 *pid
= DISPID_STARTENUM
;
1693 static HRESULT WINAPI
DispatchEx_GetNameSpaceParent(IDispatchEx
*iface
, IUnknown
**ppunk
)
1695 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
1696 FIXME("(%p)->(%p)\n", This
, ppunk
);
1700 static IDispatchExVtbl DispatchExVtbl
= {
1701 DispatchEx_QueryInterface
,
1704 DispatchEx_GetTypeInfoCount
,
1705 DispatchEx_GetTypeInfo
,
1706 DispatchEx_GetIDsOfNames
,
1708 DispatchEx_GetDispID
,
1709 DispatchEx_InvokeEx
,
1710 DispatchEx_DeleteMemberByName
,
1711 DispatchEx_DeleteMemberByDispID
,
1712 DispatchEx_GetMemberProperties
,
1713 DispatchEx_GetMemberName
,
1714 DispatchEx_GetNextDispID
,
1715 DispatchEx_GetNameSpaceParent
1718 jsdisp_t
*as_jsdisp(IDispatch
*disp
)
1720 assert(disp
->lpVtbl
== (IDispatchVtbl
*)&DispatchExVtbl
);
1721 return impl_from_IDispatchEx((IDispatchEx
*)disp
);
1724 jsdisp_t
*to_jsdisp(IDispatch
*disp
)
1726 return disp
->lpVtbl
== (IDispatchVtbl
*)&DispatchExVtbl
? impl_from_IDispatchEx((IDispatchEx
*)disp
) : NULL
;
1729 HRESULT
init_dispex(jsdisp_t
*dispex
, script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*prototype
)
1731 TRACE("%p (%p)\n", dispex
, prototype
);
1733 dispex
->IDispatchEx_iface
.lpVtbl
= &DispatchExVtbl
;
1735 dispex
->builtin_info
= builtin_info
;
1737 dispex
->props
= heap_alloc_zero(sizeof(dispex_prop_t
)*(dispex
->buf_size
=4));
1739 return E_OUTOFMEMORY
;
1741 dispex
->prototype
= prototype
;
1743 jsdisp_addref(prototype
);
1745 dispex
->prop_cnt
= 1;
1746 if(builtin_info
->value_prop
.invoke
|| builtin_info
->value_prop
.getter
) {
1747 dispex
->props
[0].type
= PROP_BUILTIN
;
1748 dispex
->props
[0].u
.p
= &builtin_info
->value_prop
;
1750 dispex
->props
[0].type
= PROP_DELETED
;
1759 static const builtin_info_t dispex_info
= {
1767 HRESULT
create_dispex(script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*prototype
, jsdisp_t
**dispex
)
1772 ret
= heap_alloc_zero(sizeof(jsdisp_t
));
1774 return E_OUTOFMEMORY
;
1776 hres
= init_dispex(ret
, ctx
, builtin_info
? builtin_info
: &dispex_info
, prototype
);
1786 void jsdisp_free(jsdisp_t
*obj
)
1788 dispex_prop_t
*prop
;
1790 TRACE("(%p)\n", obj
);
1792 for(prop
= obj
->props
; prop
< obj
->props
+obj
->prop_cnt
; prop
++) {
1793 switch(prop
->type
) {
1795 jsval_release(prop
->u
.val
);
1798 if(prop
->u
.accessor
.getter
)
1799 jsdisp_release(prop
->u
.accessor
.getter
);
1800 if(prop
->u
.accessor
.setter
)
1801 jsdisp_release(prop
->u
.accessor
.setter
);
1806 heap_free(prop
->name
);
1808 heap_free(obj
->props
);
1809 script_release(obj
->ctx
);
1811 jsdisp_release(obj
->prototype
);
1813 if(obj
->builtin_info
->destructor
)
1814 obj
->builtin_info
->destructor(obj
);
1821 jsdisp_t
*jsdisp_addref(jsdisp_t
*jsdisp
)
1823 ULONG ref
= ++jsdisp
->ref
;
1824 TRACE("(%p) ref=%d\n", jsdisp
, ref
);
1828 void jsdisp_release(jsdisp_t
*jsdisp
)
1830 ULONG ref
= --jsdisp
->ref
;
1832 TRACE("(%p) ref=%d\n", jsdisp
, ref
);
1835 jsdisp_free(jsdisp
);
1840 HRESULT
init_dispex_from_constr(jsdisp_t
*dispex
, script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*constr
)
1842 jsdisp_t
*prot
= NULL
;
1843 dispex_prop_t
*prop
;
1846 hres
= find_prop_name_prot(constr
, string_hash(L
"prototype"), L
"prototype", &prop
);
1847 if(SUCCEEDED(hres
) && prop
&& prop
->type
!=PROP_DELETED
) {
1850 hres
= prop_get(constr
, prop
, &val
);
1852 ERR("Could not get prototype\n");
1856 if(is_object_instance(val
))
1857 prot
= iface_to_jsdisp(get_object(val
));
1861 hres
= init_dispex(dispex
, ctx
, builtin_info
, prot
);
1864 jsdisp_release(prot
);
1868 jsdisp_t
*iface_to_jsdisp(IDispatch
*iface
)
1870 return iface
->lpVtbl
== (const IDispatchVtbl
*)&DispatchExVtbl
1871 ? jsdisp_addref( impl_from_IDispatchEx((IDispatchEx
*)iface
))
1875 HRESULT
jsdisp_get_id(jsdisp_t
*jsdisp
, const WCHAR
*name
, DWORD flags
, DISPID
*id
)
1877 dispex_prop_t
*prop
;
1880 if(flags
& fdexNameEnsure
)
1881 hres
= ensure_prop_name(jsdisp
, name
, PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
,
1884 hres
= find_prop_name_prot(jsdisp
, string_hash(name
), name
, &prop
);
1888 if(prop
&& prop
->type
!=PROP_DELETED
) {
1889 *id
= prop_to_id(jsdisp
, prop
);
1893 TRACE("not found %s\n", debugstr_w(name
));
1894 *id
= DISPID_UNKNOWN
;
1895 return DISP_E_UNKNOWNNAME
;
1898 HRESULT
jsdisp_call_value(jsdisp_t
*jsfunc
, IDispatch
*jsthis
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1902 assert(!(flags
& ~(DISPATCH_METHOD
|DISPATCH_CONSTRUCT
|DISPATCH_JSCRIPT_INTERNAL_MASK
)));
1904 if(is_class(jsfunc
, JSCLASS_FUNCTION
)) {
1905 hres
= Function_invoke(jsfunc
, jsthis
, flags
, argc
, argv
, r
);
1909 if(!jsfunc
->builtin_info
->value_prop
.invoke
) {
1910 WARN("Not a function\n");
1911 return JS_E_FUNCTION_EXPECTED
;
1914 set_disp(&vdisp
, jsthis
);
1915 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
1916 hres
= jsfunc
->builtin_info
->value_prop
.invoke(jsfunc
->ctx
, &vdisp
, flags
, argc
, argv
, r
);
1917 vdisp_release(&vdisp
);
1922 HRESULT
jsdisp_call(jsdisp_t
*disp
, DISPID id
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1924 dispex_prop_t
*prop
;
1926 prop
= get_prop(disp
, id
);
1928 return DISP_E_MEMBERNOTFOUND
;
1930 return invoke_prop_func(disp
, to_disp(disp
), prop
, flags
, argc
, argv
, r
, NULL
);
1933 HRESULT
jsdisp_call_name(jsdisp_t
*disp
, const WCHAR
*name
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1935 dispex_prop_t
*prop
;
1938 hres
= find_prop_name_prot(disp
, string_hash(name
), name
, &prop
);
1942 return invoke_prop_func(disp
, to_disp(disp
), prop
, flags
, argc
, argv
, r
, NULL
);
1945 static HRESULT
disp_invoke(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, WORD flags
, DISPPARAMS
*params
, VARIANT
*r
)
1947 IDispatchEx
*dispex
;
1951 memset(&ei
, 0, sizeof(ei
));
1952 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
1953 if(SUCCEEDED(hres
)) {
1954 hres
= IDispatchEx_InvokeEx(dispex
, id
, ctx
->lcid
, flags
, params
, r
, &ei
, &ctx
->jscaller
->IServiceProvider_iface
);
1955 IDispatchEx_Release(dispex
);
1959 if(flags
== DISPATCH_CONSTRUCT
) {
1960 WARN("IDispatch cannot be constructor\n");
1961 return DISP_E_MEMBERNOTFOUND
;
1964 if(params
->cNamedArgs
== 1 && params
->rgdispidNamedArgs
[0] == DISPID_THIS
) {
1965 params
->cNamedArgs
= 0;
1966 params
->rgdispidNamedArgs
= NULL
;
1971 TRACE("using IDispatch\n");
1972 hres
= IDispatch_Invoke(disp
, id
, &IID_NULL
, ctx
->lcid
, flags
, params
, r
, &ei
, &err
);
1975 if(hres
== DISP_E_EXCEPTION
) {
1976 TRACE("DISP_E_EXCEPTION: %08x %s %s\n", ei
.scode
, debugstr_w(ei
.bstrSource
), debugstr_w(ei
.bstrDescription
));
1978 ctx
->ei
->error
= (SUCCEEDED(ei
.scode
) || ei
.scode
== DISP_E_EXCEPTION
) ? E_FAIL
: ei
.scode
;
1980 ctx
->ei
->source
= jsstr_alloc_len(ei
.bstrSource
, SysStringLen(ei
.bstrSource
));
1981 if(ei
.bstrDescription
)
1982 ctx
->ei
->message
= jsstr_alloc_len(ei
.bstrDescription
, SysStringLen(ei
.bstrDescription
));
1983 SysFreeString(ei
.bstrSource
);
1984 SysFreeString(ei
.bstrDescription
);
1985 SysFreeString(ei
.bstrHelpFile
);
1991 HRESULT
disp_call(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*ret
)
1993 VARIANT buf
[6], retv
;
1999 jsdisp
= iface_to_jsdisp(disp
);
2000 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2001 if(flags
& DISPATCH_PROPERTYPUT
) {
2002 FIXME("disp_call(propput) on builtin object\n");
2006 if(ctx
!= jsdisp
->ctx
)
2007 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
2008 hres
= jsdisp_call(jsdisp
, id
, flags
, argc
, argv
, ret
);
2009 jsdisp_release(jsdisp
);
2013 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
2015 flags
|= DISPATCH_PROPERTYGET
;
2019 if(flags
& DISPATCH_PROPERTYPUT
) {
2020 static DISPID propput_dispid
= DISPID_PROPERTYPUT
;
2023 dp
.rgdispidNamedArgs
= &propput_dispid
;
2026 dp
.rgdispidNamedArgs
= NULL
;
2029 if(dp
.cArgs
> ARRAY_SIZE(buf
)) {
2030 dp
.rgvarg
= heap_alloc(argc
*sizeof(VARIANT
));
2032 return E_OUTOFMEMORY
;
2037 for(i
=0; i
<argc
; i
++) {
2038 hres
= jsval_to_variant(argv
[i
], dp
.rgvarg
+argc
-i
-1);
2041 VariantClear(dp
.rgvarg
+argc
-i
-1);
2042 if(dp
.rgvarg
!= buf
)
2043 heap_free(dp
.rgvarg
);
2048 V_VT(&retv
) = VT_EMPTY
;
2049 hres
= disp_invoke(ctx
, disp
, id
, flags
, &dp
, ret
? &retv
: NULL
);
2051 for(i
=0; i
<argc
; i
++)
2052 VariantClear(dp
.rgvarg
+argc
-i
-1);
2053 if(dp
.rgvarg
!= buf
)
2054 heap_free(dp
.rgvarg
);
2056 if(SUCCEEDED(hres
) && ret
)
2057 hres
= variant_to_jsval(&retv
, ret
);
2058 VariantClear(&retv
);
2062 HRESULT
disp_call_value(script_ctx_t
*ctx
, IDispatch
*disp
, IDispatch
*jsthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
2065 VARIANT buf
[6], retv
, *args
= buf
;
2069 HRESULT hres
= S_OK
;
2071 static DISPID this_id
= DISPID_THIS
;
2073 assert(!(flags
& ~(DISPATCH_METHOD
|DISPATCH_CONSTRUCT
|DISPATCH_JSCRIPT_INTERNAL_MASK
)));
2075 jsdisp
= iface_to_jsdisp(disp
);
2076 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2077 if(ctx
!= jsdisp
->ctx
)
2078 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
2079 hres
= jsdisp_call_value(jsdisp
, jsthis
, flags
, argc
, argv
, r
);
2080 jsdisp_release(jsdisp
);
2084 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
2085 if(r
&& argc
&& flags
== DISPATCH_METHOD
)
2086 flags
|= DISPATCH_PROPERTYGET
;
2089 dp
.cArgs
= argc
+ 1;
2091 dp
.rgdispidNamedArgs
= &this_id
;
2095 dp
.rgdispidNamedArgs
= NULL
;
2098 if(dp
.cArgs
> ARRAY_SIZE(buf
) && !(args
= heap_alloc(dp
.cArgs
* sizeof(VARIANT
))))
2099 return E_OUTOFMEMORY
;
2103 V_VT(dp
.rgvarg
) = VT_DISPATCH
;
2104 V_DISPATCH(dp
.rgvarg
) = jsthis
;
2107 for(i
=0; SUCCEEDED(hres
) && i
< argc
; i
++)
2108 hres
= jsval_to_variant(argv
[i
], dp
.rgvarg
+dp
.cArgs
-i
-1);
2110 if(SUCCEEDED(hres
)) {
2111 V_VT(&retv
) = VT_EMPTY
;
2112 hres
= disp_invoke(ctx
, disp
, DISPID_VALUE
, flags
, &dp
, r
? &retv
: NULL
);
2115 for(i
= 0; i
< argc
; i
++)
2116 VariantClear(dp
.rgvarg
+ dp
.cArgs
- i
- 1);
2123 hres
= variant_to_jsval(&retv
, r
);
2124 VariantClear(&retv
);
2128 HRESULT
jsdisp_propput(jsdisp_t
*obj
, const WCHAR
*name
, DWORD flags
, jsval_t val
)
2130 dispex_prop_t
*prop
;
2133 hres
= ensure_prop_name(obj
, name
, flags
, &prop
);
2137 return prop_put(obj
, prop
, val
);
2140 HRESULT
jsdisp_propput_name(jsdisp_t
*obj
, const WCHAR
*name
, jsval_t val
)
2142 return jsdisp_propput(obj
, name
, PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
, val
);
2145 HRESULT
jsdisp_propput_idx(jsdisp_t
*obj
, DWORD idx
, jsval_t val
)
2149 swprintf(buf
, ARRAY_SIZE(buf
), L
"%d", idx
);
2150 return jsdisp_propput_name(obj
, buf
, val
);
2153 HRESULT
disp_propput(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, jsval_t val
)
2158 jsdisp
= iface_to_jsdisp(disp
);
2159 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2160 dispex_prop_t
*prop
;
2162 prop
= get_prop(jsdisp
, id
);
2164 hres
= prop_put(jsdisp
, prop
, val
);
2166 hres
= DISP_E_MEMBERNOTFOUND
;
2168 jsdisp_release(jsdisp
);
2170 DISPID dispid
= DISPID_PROPERTYPUT
;
2171 DWORD flags
= DISPATCH_PROPERTYPUT
;
2173 DISPPARAMS dp
= {&var
, &dispid
, 1, 1};
2175 hres
= jsval_to_variant(val
, &var
);
2179 if(V_VT(&var
) == VT_DISPATCH
)
2180 flags
|= DISPATCH_PROPERTYPUTREF
;
2182 hres
= disp_invoke(ctx
, disp
, id
, flags
, &dp
, NULL
);
2189 HRESULT
jsdisp_propget_name(jsdisp_t
*obj
, const WCHAR
*name
, jsval_t
*val
)
2191 dispex_prop_t
*prop
;
2194 hres
= find_prop_name_prot(obj
, string_hash(name
), name
, &prop
);
2198 if(!prop
|| prop
->type
==PROP_DELETED
) {
2199 *val
= jsval_undefined();
2203 return prop_get(obj
, prop
, val
);
2206 HRESULT
jsdisp_get_idx(jsdisp_t
*obj
, DWORD idx
, jsval_t
*r
)
2209 dispex_prop_t
*prop
;
2212 swprintf(name
, ARRAY_SIZE(name
), L
"%d", idx
);
2214 hres
= find_prop_name_prot(obj
, string_hash(name
), name
, &prop
);
2218 if(!prop
|| prop
->type
==PROP_DELETED
) {
2219 *r
= jsval_undefined();
2220 return DISP_E_UNKNOWNNAME
;
2223 return prop_get(obj
, prop
, r
);
2226 HRESULT
jsdisp_propget(jsdisp_t
*jsdisp
, DISPID id
, jsval_t
*val
)
2228 dispex_prop_t
*prop
;
2230 prop
= get_prop(jsdisp
, id
);
2232 return DISP_E_MEMBERNOTFOUND
;
2234 return prop_get(jsdisp
, prop
, val
);
2237 HRESULT
disp_propget(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, jsval_t
*val
)
2239 DISPPARAMS dp
= {NULL
,NULL
,0,0};
2244 jsdisp
= iface_to_jsdisp(disp
);
2245 if(jsdisp
&& jsdisp
->ctx
== ctx
) {
2246 hres
= jsdisp_propget(jsdisp
, id
, val
);
2247 jsdisp_release(jsdisp
);
2251 V_VT(&var
) = VT_EMPTY
;
2252 hres
= disp_invoke(ctx
, disp
, id
, INVOKE_PROPERTYGET
, &dp
, &var
);
2253 if(SUCCEEDED(hres
)) {
2254 hres
= variant_to_jsval(&var
, val
);
2260 HRESULT
jsdisp_delete_idx(jsdisp_t
*obj
, DWORD idx
)
2263 dispex_prop_t
*prop
;
2267 swprintf(buf
, ARRAY_SIZE(buf
), L
"%d", idx
);
2269 hres
= find_prop_name(obj
, string_hash(buf
), buf
, &prop
);
2270 if(FAILED(hres
) || !prop
)
2273 return delete_prop(prop
, &b
);
2276 HRESULT
disp_delete(IDispatch
*disp
, DISPID id
, BOOL
*ret
)
2278 IDispatchEx
*dispex
;
2282 jsdisp
= iface_to_jsdisp(disp
);
2284 dispex_prop_t
*prop
;
2286 prop
= get_prop(jsdisp
, id
);
2288 hres
= delete_prop(prop
, ret
);
2290 hres
= DISP_E_MEMBERNOTFOUND
;
2292 jsdisp_release(jsdisp
);
2296 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2302 hres
= IDispatchEx_DeleteMemberByDispID(dispex
, id
);
2303 IDispatchEx_Release(dispex
);
2307 *ret
= hres
== S_OK
;
2311 HRESULT
jsdisp_next_prop(jsdisp_t
*obj
, DISPID id
, BOOL own_only
, DISPID
*ret
)
2313 dispex_prop_t
*iter
;
2316 if(id
== DISPID_STARTENUM
&& !own_only
) {
2317 hres
= fill_protrefs(obj
);
2322 if(id
+ 1 < 0 || id
+1 >= obj
->prop_cnt
)
2325 for(iter
= &obj
->props
[id
+ 1]; iter
< obj
->props
+ obj
->prop_cnt
; iter
++) {
2326 if(!iter
->name
|| iter
->type
== PROP_DELETED
)
2328 if(own_only
&& iter
->type
== PROP_PROTREF
)
2330 if(!(get_flags(obj
, iter
) & PROPF_ENUMERABLE
))
2332 *ret
= prop_to_id(obj
, iter
);
2339 HRESULT
disp_delete_name(script_ctx_t
*ctx
, IDispatch
*disp
, jsstr_t
*name
, BOOL
*ret
)
2341 IDispatchEx
*dispex
;
2346 jsdisp
= iface_to_jsdisp(disp
);
2348 dispex_prop_t
*prop
;
2351 ptr
= jsstr_flatten(name
);
2353 jsdisp_release(jsdisp
);
2354 return E_OUTOFMEMORY
;
2357 hres
= find_prop_name(jsdisp
, string_hash(ptr
), ptr
, &prop
);
2359 hres
= delete_prop(prop
, ret
);
2365 jsdisp_release(jsdisp
);
2369 bstr
= SysAllocStringLen(NULL
, jsstr_length(name
));
2371 return E_OUTOFMEMORY
;
2372 jsstr_flush(name
, bstr
);
2374 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
2375 if(SUCCEEDED(hres
)) {
2376 hres
= IDispatchEx_DeleteMemberByName(dispex
, bstr
, make_grfdex(ctx
, fdexNameCaseSensitive
));
2378 *ret
= hres
== S_OK
;
2379 IDispatchEx_Release(dispex
);
2383 hres
= IDispatch_GetIDsOfNames(disp
, &IID_NULL
, &bstr
, 1, 0, &id
);
2384 if(SUCCEEDED(hres
)) {
2385 /* Property exists and we can't delete it from pure IDispatch interface, so return false. */
2387 }else if(hres
== DISP_E_UNKNOWNNAME
) {
2388 /* Property doesn't exist, so nothing to delete */
2394 SysFreeString(bstr
);
2398 HRESULT
jsdisp_get_own_property(jsdisp_t
*obj
, const WCHAR
*name
, BOOL flags_only
,
2399 property_desc_t
*desc
)
2401 dispex_prop_t
*prop
;
2404 hres
= find_prop_name(obj
, string_hash(name
), name
, &prop
);
2409 return DISP_E_UNKNOWNNAME
;
2411 memset(desc
, 0, sizeof(*desc
));
2413 switch(prop
->type
) {
2416 desc
->mask
|= PROPF_WRITABLE
;
2417 desc
->explicit_value
= TRUE
;
2419 hres
= prop_get(obj
, prop
, &desc
->value
);
2425 desc
->explicit_getter
= desc
->explicit_setter
= TRUE
;
2427 desc
->getter
= prop
->u
.accessor
.getter
2428 ? jsdisp_addref(prop
->u
.accessor
.getter
) : NULL
;
2429 desc
->setter
= prop
->u
.accessor
.setter
2430 ? jsdisp_addref(prop
->u
.accessor
.setter
) : NULL
;
2434 return DISP_E_UNKNOWNNAME
;
2437 desc
->flags
= prop
->flags
& (PROPF_ENUMERABLE
| PROPF_WRITABLE
| PROPF_CONFIGURABLE
);
2438 desc
->mask
|= PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
;
2442 HRESULT
jsdisp_define_property(jsdisp_t
*obj
, const WCHAR
*name
, property_desc_t
*desc
)
2444 dispex_prop_t
*prop
;
2447 hres
= find_prop_name(obj
, string_hash(name
), name
, &prop
);
2451 if(!prop
&& !(prop
= alloc_prop(obj
, name
, PROP_DELETED
, 0)))
2452 return E_OUTOFMEMORY
;
2454 if(prop
->type
== PROP_DELETED
|| prop
->type
== PROP_PROTREF
) {
2455 prop
->flags
= desc
->flags
;
2456 if(desc
->explicit_getter
|| desc
->explicit_setter
) {
2457 prop
->type
= PROP_ACCESSOR
;
2458 prop
->u
.accessor
.getter
= desc
->getter
? jsdisp_addref(desc
->getter
) : NULL
;
2459 prop
->u
.accessor
.setter
= desc
->setter
? jsdisp_addref(desc
->setter
) : NULL
;
2460 TRACE("%s = accessor { get: %p set: %p }\n", debugstr_w(name
),
2461 prop
->u
.accessor
.getter
, prop
->u
.accessor
.setter
);
2463 prop
->type
= PROP_JSVAL
;
2464 if(desc
->explicit_value
) {
2465 hres
= jsval_copy(desc
->value
, &prop
->u
.val
);
2469 prop
->u
.val
= jsval_undefined();
2471 TRACE("%s = %s\n", debugstr_w(name
), debugstr_jsval(prop
->u
.val
));
2476 TRACE("existing prop %s prop flags %x desc flags %x desc mask %x\n", debugstr_w(name
),
2477 prop
->flags
, desc
->flags
, desc
->mask
);
2479 if(!(prop
->flags
& PROPF_CONFIGURABLE
)) {
2480 if(((desc
->mask
& PROPF_CONFIGURABLE
) && (desc
->flags
& PROPF_CONFIGURABLE
))
2481 || ((desc
->mask
& PROPF_ENUMERABLE
)
2482 && ((desc
->flags
& PROPF_ENUMERABLE
) != (prop
->flags
& PROPF_ENUMERABLE
))))
2483 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
2486 if(desc
->explicit_value
|| (desc
->mask
& PROPF_WRITABLE
)) {
2487 if(prop
->type
== PROP_ACCESSOR
) {
2488 if(!(prop
->flags
& PROPF_CONFIGURABLE
))
2489 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
2490 if(prop
->u
.accessor
.getter
)
2491 jsdisp_release(prop
->u
.accessor
.getter
);
2492 if(prop
->u
.accessor
.setter
)
2493 jsdisp_release(prop
->u
.accessor
.setter
);
2495 prop
->type
= PROP_JSVAL
;
2496 hres
= jsval_copy(desc
->value
, &prop
->u
.val
);
2498 prop
->u
.val
= jsval_undefined();
2502 if(!(prop
->flags
& PROPF_CONFIGURABLE
) && !(prop
->flags
& PROPF_WRITABLE
)) {
2503 if((desc
->mask
& PROPF_WRITABLE
) && (desc
->flags
& PROPF_WRITABLE
))
2504 return throw_error(obj
->ctx
, JS_E_NONWRITABLE_MODIFIED
, name
);
2505 if(desc
->explicit_value
) {
2506 if(prop
->type
== PROP_JSVAL
) {
2508 hres
= jsval_strict_equal(desc
->value
, prop
->u
.val
, &eq
);
2512 return throw_error(obj
->ctx
, JS_E_NONWRITABLE_MODIFIED
, name
);
2514 FIXME("redefinition of property type %d\n", prop
->type
);
2518 if(desc
->explicit_value
) {
2519 if(prop
->type
== PROP_JSVAL
)
2520 jsval_release(prop
->u
.val
);
2522 prop
->type
= PROP_JSVAL
;
2523 hres
= jsval_copy(desc
->value
, &prop
->u
.val
);
2525 prop
->u
.val
= jsval_undefined();
2530 }else if(desc
->explicit_getter
|| desc
->explicit_setter
) {
2531 if(prop
->type
!= PROP_ACCESSOR
) {
2532 if(!(prop
->flags
& PROPF_CONFIGURABLE
))
2533 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
2534 if(prop
->type
== PROP_JSVAL
)
2535 jsval_release(prop
->u
.val
);
2536 prop
->type
= PROP_ACCESSOR
;
2537 prop
->u
.accessor
.getter
= prop
->u
.accessor
.setter
= NULL
;
2538 }else if(!(prop
->flags
& PROPF_CONFIGURABLE
)) {
2539 if((desc
->explicit_getter
&& desc
->getter
!= prop
->u
.accessor
.getter
)
2540 || (desc
->explicit_setter
&& desc
->setter
!= prop
->u
.accessor
.setter
))
2541 return throw_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
2544 if(desc
->explicit_getter
) {
2545 if(prop
->u
.accessor
.getter
) {
2546 jsdisp_release(prop
->u
.accessor
.getter
);
2547 prop
->u
.accessor
.getter
= NULL
;
2550 prop
->u
.accessor
.getter
= jsdisp_addref(desc
->getter
);
2552 if(desc
->explicit_setter
) {
2553 if(prop
->u
.accessor
.setter
) {
2554 jsdisp_release(prop
->u
.accessor
.setter
);
2555 prop
->u
.accessor
.setter
= NULL
;
2558 prop
->u
.accessor
.setter
= jsdisp_addref(desc
->setter
);
2562 prop
->flags
= (prop
->flags
& ~desc
->mask
) | (desc
->flags
& desc
->mask
);
2566 HRESULT
jsdisp_define_data_property(jsdisp_t
*obj
, const WCHAR
*name
, unsigned flags
, jsval_t value
)
2568 property_desc_t prop_desc
= { flags
, flags
, TRUE
};
2569 prop_desc
.value
= value
;
2570 return jsdisp_define_property(obj
, name
, &prop_desc
);
2573 HRESULT
jsdisp_get_prop_name(jsdisp_t
*obj
, DISPID id
, jsstr_t
**r
)
2575 dispex_prop_t
*prop
= get_prop(obj
, id
);
2577 if(!prop
|| !prop
->name
|| prop
->type
== PROP_DELETED
)
2578 return DISP_E_MEMBERNOTFOUND
;
2580 *r
= jsstr_alloc(prop
->name
);
2581 return *r
? S_OK
: E_OUTOFMEMORY
;