2 * Copyright 2008 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wine/debug.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(jscript
);
27 #define FDEX_VERSION_MASK 0xf0000000
28 #define GOLDEN_RATIO 0x9E3779B9U
39 struct _dispex_prop_t
{
47 const builtin_prop_t
*p
;
60 static inline DISPID
prop_to_id(jsdisp_t
*This
, dispex_prop_t
*prop
)
62 return prop
- This
->props
;
65 static inline dispex_prop_t
*get_prop(jsdisp_t
*This
, DISPID id
)
67 if(id
< 0 || id
>= This
->prop_cnt
|| This
->props
[id
].type
== PROP_DELETED
)
70 return This
->props
+id
;
73 static DWORD
get_flags(jsdisp_t
*This
, dispex_prop_t
*prop
)
75 if(prop
->type
== PROP_PROTREF
) {
76 dispex_prop_t
*parent
= get_prop(This
->prototype
, prop
->u
.ref
);
78 prop
->type
= PROP_DELETED
;
82 return get_flags(This
->prototype
, parent
);
88 static const builtin_prop_t
*find_builtin_prop(jsdisp_t
*This
, const WCHAR
*name
)
90 int min
= 0, max
, i
, r
;
92 max
= This
->builtin_info
->props_cnt
-1;
96 r
= wcscmp(name
, This
->builtin_info
->props
[i
].name
);
98 /* Skip prop if it's available only in higher compatibility mode. */
99 unsigned version
= (This
->builtin_info
->props
[i
].flags
& PROPF_VERSION_MASK
)
100 >> PROPF_VERSION_SHIFT
;
101 if(version
&& version
> This
->ctx
->version
)
104 /* Skip prop if it's available only in HTML mode and we're not running in HTML mode. */
105 if((This
->builtin_info
->props
[i
].flags
& PROPF_HTML
) && !This
->ctx
->html_mode
)
108 return This
->builtin_info
->props
+ i
;
120 static inline unsigned string_hash(const WCHAR
*name
)
124 h
= (h
>>(sizeof(unsigned)*8-4)) ^ (h
<<4) ^ towlower(*name
);
128 static inline unsigned get_props_idx(jsdisp_t
*This
, unsigned hash
)
130 return (hash
*GOLDEN_RATIO
) & (This
->buf_size
-1);
133 static inline HRESULT
resize_props(jsdisp_t
*This
)
135 dispex_prop_t
*props
;
138 if(This
->buf_size
!= This
->prop_cnt
)
141 props
= heap_realloc(This
->props
, sizeof(dispex_prop_t
)*This
->buf_size
*2);
143 return E_OUTOFMEMORY
;
147 for(i
=0; i
<This
->buf_size
; i
++) {
148 This
->props
[i
].bucket_head
= 0;
149 This
->props
[i
].bucket_next
= 0;
152 for(i
=1; i
<This
->prop_cnt
; i
++) {
153 props
= This
->props
+i
;
155 bucket
= get_props_idx(This
, props
->hash
);
156 props
->bucket_next
= This
->props
[bucket
].bucket_head
;
157 This
->props
[bucket
].bucket_head
= i
;
163 static inline dispex_prop_t
* alloc_prop(jsdisp_t
*This
, const WCHAR
*name
, prop_type_t type
, DWORD flags
)
168 if(FAILED(resize_props(This
)))
171 prop
= &This
->props
[This
->prop_cnt
];
172 prop
->name
= heap_strdupW(name
);
177 prop
->hash
= string_hash(name
);
179 bucket
= get_props_idx(This
, prop
->hash
);
180 prop
->bucket_next
= This
->props
[bucket
].bucket_head
;
181 This
->props
[bucket
].bucket_head
= This
->prop_cnt
++;
185 static dispex_prop_t
*alloc_protref(jsdisp_t
*This
, const WCHAR
*name
, DWORD ref
)
189 ret
= alloc_prop(This
, name
, PROP_PROTREF
, 0);
197 static HRESULT
find_prop_name(jsdisp_t
*This
, unsigned hash
, const WCHAR
*name
, dispex_prop_t
**ret
)
199 const builtin_prop_t
*builtin
;
200 unsigned bucket
, pos
, prev
= 0;
203 bucket
= get_props_idx(This
, hash
);
204 pos
= This
->props
[bucket
].bucket_head
;
206 if(!wcscmp(name
, This
->props
[pos
].name
)) {
208 This
->props
[prev
].bucket_next
= This
->props
[pos
].bucket_next
;
209 This
->props
[pos
].bucket_next
= This
->props
[bucket
].bucket_head
;
210 This
->props
[bucket
].bucket_head
= pos
;
213 *ret
= &This
->props
[pos
];
218 pos
= This
->props
[pos
].bucket_next
;
221 builtin
= find_builtin_prop(This
, name
);
223 unsigned flags
= builtin
->flags
;
224 if(flags
& PROPF_METHOD
)
225 flags
|= PROPF_WRITABLE
| PROPF_CONFIGURABLE
;
226 else if(builtin
->setter
)
227 flags
|= PROPF_WRITABLE
;
228 flags
&= PROPF_ENUMERABLE
| PROPF_WRITABLE
| PROPF_CONFIGURABLE
;
229 prop
= alloc_prop(This
, name
, PROP_BUILTIN
, flags
);
231 return E_OUTOFMEMORY
;
238 if(This
->builtin_info
->idx_length
) {
242 for(ptr
= name
; iswdigit(*ptr
) && idx
< 0x10000; ptr
++)
243 idx
= idx
*10 + (*ptr
-'0');
244 if(!*ptr
&& idx
< This
->builtin_info
->idx_length(This
)) {
245 prop
= alloc_prop(This
, name
, PROP_IDX
, This
->builtin_info
->idx_put
? PROPF_WRITABLE
: 0);
247 return E_OUTOFMEMORY
;
259 static HRESULT
find_prop_name_prot(jsdisp_t
*This
, unsigned hash
, const WCHAR
*name
, dispex_prop_t
**ret
)
261 dispex_prop_t
*prop
, *del
=NULL
;
264 hres
= find_prop_name(This
, hash
, name
, &prop
);
267 if(prop
&& prop
->type
==PROP_DELETED
) {
274 if(This
->prototype
) {
275 hres
= find_prop_name_prot(This
->prototype
, hash
, name
, &prop
);
280 del
->type
= PROP_PROTREF
;
281 del
->u
.ref
= prop
- This
->prototype
->props
;
284 prop
= alloc_protref(This
, prop
->name
, prop
- This
->prototype
->props
);
286 return E_OUTOFMEMORY
;
298 static HRESULT
ensure_prop_name(jsdisp_t
*This
, const WCHAR
*name
, DWORD create_flags
, dispex_prop_t
**ret
)
303 hres
= find_prop_name_prot(This
, string_hash(name
), name
, &prop
);
304 if(SUCCEEDED(hres
) && (!prop
|| prop
->type
== PROP_DELETED
)) {
305 TRACE("creating prop %s flags %x\n", debugstr_w(name
), create_flags
);
308 prop
->type
= PROP_JSVAL
;
309 prop
->flags
= create_flags
;
310 prop
->u
.val
= jsval_undefined();
312 prop
= alloc_prop(This
, name
, PROP_JSVAL
, create_flags
);
314 return E_OUTOFMEMORY
;
317 prop
->u
.val
= jsval_undefined();
324 static IDispatch
*get_this(DISPPARAMS
*dp
)
328 for(i
=0; i
< dp
->cNamedArgs
; i
++) {
329 if(dp
->rgdispidNamedArgs
[i
] == DISPID_THIS
) {
330 if(V_VT(dp
->rgvarg
+i
) == VT_DISPATCH
)
331 return V_DISPATCH(dp
->rgvarg
+i
);
333 WARN("This is not VT_DISPATCH\n");
338 TRACE("no this passed\n");
342 static HRESULT
convert_params(const DISPPARAMS
*dp
, jsval_t
*buf
, unsigned *argc
, jsval_t
**ret
)
349 cnt
= dp
->cArgs
- dp
->cNamedArgs
;
352 argv
= heap_alloc(cnt
* sizeof(*argv
));
354 return E_OUTOFMEMORY
;
359 for(i
= 0; i
< cnt
; i
++) {
360 hres
= variant_to_jsval(dp
->rgvarg
+dp
->cArgs
-i
-1, argv
+i
);
363 jsval_release(argv
[i
]);
375 static HRESULT
invoke_prop_func(jsdisp_t
*This
, IDispatch
*jsthis
, dispex_prop_t
*prop
, WORD flags
,
376 unsigned argc
, jsval_t
*argv
, jsval_t
*r
, IServiceProvider
*caller
)
382 if(flags
== DISPATCH_CONSTRUCT
&& (prop
->flags
& PROPF_METHOD
)) {
383 WARN("%s is not a constructor\n", debugstr_w(prop
->name
));
387 if(prop
->name
|| This
->builtin_info
->class != JSCLASS_FUNCTION
) {
390 if(This
->builtin_info
->class != JSCLASS_FUNCTION
&& prop
->u
.p
->invoke
!= JSGlobal_eval
)
391 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
393 set_disp(&vthis
, jsthis
);
395 set_jsdisp(&vthis
, This
);
396 hres
= prop
->u
.p
->invoke(This
->ctx
, &vthis
, flags
, argc
, argv
, r
);
397 vdisp_release(&vthis
);
399 /* Function object calls are special case */
400 hres
= Function_invoke(This
, jsthis
, flags
, argc
, argv
, r
);
405 return invoke_prop_func(This
->prototype
, jsthis
, This
->prototype
->props
+prop
->u
.ref
,
406 flags
, argc
, argv
, r
, caller
);
408 if(!is_object_instance(prop
->u
.val
)) {
409 FIXME("invoke %s\n", debugstr_jsval(prop
->u
.val
));
413 TRACE("call %s %p\n", debugstr_w(prop
->name
), get_object(prop
->u
.val
));
415 return disp_call_value(This
->ctx
, get_object(prop
->u
.val
), jsthis
, flags
, argc
, argv
, r
);
421 FIXME("Invoking PROP_IDX not yet supported\n");
431 static HRESULT
prop_get(jsdisp_t
*This
, dispex_prop_t
*prop
, jsval_t
*r
)
433 jsdisp_t
*prop_obj
= This
;
436 while(prop
->type
== PROP_PROTREF
) {
437 prop_obj
= prop_obj
->prototype
;
438 prop
= prop_obj
->props
+ prop
->u
.ref
;
443 if(prop
->u
.p
->getter
) {
444 hres
= prop
->u
.p
->getter(This
->ctx
, This
, r
);
448 assert(prop
->u
.p
->invoke
!= NULL
);
449 hres
= create_builtin_function(This
->ctx
, prop
->u
.p
->invoke
, prop
->u
.p
->name
, NULL
,
450 prop
->u
.p
->flags
, NULL
, &obj
);
454 prop
->type
= PROP_JSVAL
;
455 prop
->u
.val
= jsval_obj(obj
);
462 hres
= jsval_copy(prop
->u
.val
, r
);
465 if(prop
->u
.accessor
.getter
) {
466 hres
= jsdisp_call_value(prop
->u
.accessor
.getter
, to_disp(This
),
467 DISPATCH_METHOD
, 0, NULL
, r
);
469 *r
= jsval_undefined();
474 hres
= prop_obj
->builtin_info
->idx_get(prop_obj
, prop
->u
.idx
, r
);
477 ERR("type %d\n", prop
->type
);
482 TRACE("fail %08x\n", hres
);
486 TRACE("%s ret %s\n", debugstr_w(prop
->name
), debugstr_jsval(*r
));
490 static HRESULT
prop_put(jsdisp_t
*This
, dispex_prop_t
*prop
, jsval_t val
)
494 if(prop
->type
== PROP_PROTREF
) {
495 dispex_prop_t
*prop_iter
= prop
;
496 jsdisp_t
*prototype_iter
= This
;
499 prototype_iter
= prototype_iter
->prototype
;
500 prop_iter
= prototype_iter
->props
+ prop_iter
->u
.ref
;
501 } while(prop_iter
->type
== PROP_PROTREF
);
503 if(prop_iter
->type
== PROP_ACCESSOR
)
509 if(!prop
->u
.p
->setter
) {
510 TRACE("getter with no setter\n");
513 return prop
->u
.p
->setter(This
->ctx
, This
, val
);
516 prop
->type
= PROP_JSVAL
;
517 prop
->flags
= PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
;
518 prop
->u
.val
= jsval_undefined();
521 if(!(prop
->flags
& PROPF_WRITABLE
))
524 jsval_release(prop
->u
.val
);
527 if(!prop
->u
.accessor
.setter
) {
528 TRACE("no setter\n");
531 return jsdisp_call_value(prop
->u
.accessor
.setter
, to_disp(This
), DISPATCH_METHOD
, 1, &val
, NULL
);
533 if(!This
->builtin_info
->idx_put
) {
534 TRACE("no put_idx\n");
537 return This
->builtin_info
->idx_put(This
, prop
->u
.idx
, val
);
539 ERR("type %d\n", prop
->type
);
543 TRACE("%s = %s\n", debugstr_w(prop
->name
), debugstr_jsval(val
));
545 hres
= jsval_copy(val
, &prop
->u
.val
);
549 if(This
->builtin_info
->on_put
)
550 This
->builtin_info
->on_put(This
, prop
->name
);
555 HRESULT
builtin_set_const(script_ctx_t
*ctx
, jsdisp_t
*jsthis
, jsval_t value
)
557 TRACE("%p %s\n", jsthis
, debugstr_jsval(value
));
561 static HRESULT
fill_protrefs(jsdisp_t
*This
)
563 dispex_prop_t
*iter
, *prop
;
569 fill_protrefs(This
->prototype
);
571 for(iter
= This
->prototype
->props
; iter
< This
->prototype
->props
+This
->prototype
->prop_cnt
; iter
++) {
574 hres
= find_prop_name(This
, iter
->hash
, iter
->name
, &prop
);
577 if(!prop
|| prop
->type
==PROP_DELETED
) {
579 prop
->type
= PROP_PROTREF
;
581 prop
->u
.ref
= iter
- This
->prototype
->props
;
583 prop
= alloc_protref(This
, iter
->name
, iter
- This
->prototype
->props
);
585 return E_OUTOFMEMORY
;
593 static inline jsdisp_t
*impl_from_IDispatchEx(IDispatchEx
*iface
)
595 return CONTAINING_RECORD(iface
, jsdisp_t
, IDispatchEx_iface
);
598 static HRESULT WINAPI
DispatchEx_QueryInterface(IDispatchEx
*iface
, REFIID riid
, void **ppv
)
600 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
602 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
603 TRACE("(%p)->(IID_IUnknown %p)\n", This
, ppv
);
604 *ppv
= &This
->IDispatchEx_iface
;
605 }else if(IsEqualGUID(&IID_IDispatch
, riid
)) {
606 TRACE("(%p)->(IID_IDispatch %p)\n", This
, ppv
);
607 *ppv
= &This
->IDispatchEx_iface
;
608 }else if(IsEqualGUID(&IID_IDispatchEx
, riid
)) {
609 TRACE("(%p)->(IID_IDispatchEx %p)\n", This
, ppv
);
610 *ppv
= &This
->IDispatchEx_iface
;
612 WARN("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
614 return E_NOINTERFACE
;
621 static ULONG WINAPI
DispatchEx_AddRef(IDispatchEx
*iface
)
623 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
628 static ULONG WINAPI
DispatchEx_Release(IDispatchEx
*iface
)
630 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
631 ULONG ref
= --This
->ref
;
632 TRACE("(%p) ref=%d\n", This
, ref
);
638 static HRESULT WINAPI
DispatchEx_GetTypeInfoCount(IDispatchEx
*iface
, UINT
*pctinfo
)
640 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
642 TRACE("(%p)->(%p)\n", This
, pctinfo
);
648 static HRESULT WINAPI
DispatchEx_GetTypeInfo(IDispatchEx
*iface
, UINT iTInfo
, LCID lcid
,
651 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
652 FIXME("(%p)->(%u %u %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
656 static HRESULT WINAPI
DispatchEx_GetIDsOfNames(IDispatchEx
*iface
, REFIID riid
,
657 LPOLESTR
*rgszNames
, UINT cNames
, LCID lcid
,
660 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
664 TRACE("(%p)->(%s %p %u %u %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
,
667 for(i
=0; i
< cNames
; i
++) {
668 hres
= IDispatchEx_GetDispID(&This
->IDispatchEx_iface
, rgszNames
[i
], 0, rgDispId
+i
);
676 static HRESULT WINAPI
DispatchEx_Invoke(IDispatchEx
*iface
, DISPID dispIdMember
,
677 REFIID riid
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
,
678 VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
680 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
682 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This
, dispIdMember
, debugstr_guid(riid
),
683 lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
685 return IDispatchEx_InvokeEx(&This
->IDispatchEx_iface
, dispIdMember
, lcid
, wFlags
,
686 pDispParams
, pVarResult
, pExcepInfo
, NULL
);
689 static HRESULT WINAPI
DispatchEx_GetDispID(IDispatchEx
*iface
, BSTR bstrName
, DWORD grfdex
, DISPID
*pid
)
691 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
693 TRACE("(%p)->(%s %x %p)\n", This
, debugstr_w(bstrName
), grfdex
, pid
);
695 if(grfdex
& ~(fdexNameCaseSensitive
|fdexNameEnsure
|fdexNameImplicit
|FDEX_VERSION_MASK
)) {
696 FIXME("Unsupported grfdex %x\n", grfdex
);
700 return jsdisp_get_id(This
, bstrName
, grfdex
, pid
);
703 static HRESULT WINAPI
DispatchEx_InvokeEx(IDispatchEx
*iface
, DISPID id
, LCID lcid
, WORD wFlags
, DISPPARAMS
*pdp
,
704 VARIANT
*pvarRes
, EXCEPINFO
*pei
, IServiceProvider
*pspCaller
)
706 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
710 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This
, id
, lcid
, wFlags
, pdp
, pvarRes
, pei
, pspCaller
);
713 V_VT(pvarRes
) = VT_EMPTY
;
715 prop
= get_prop(This
, id
);
716 if(!prop
|| prop
->type
== PROP_DELETED
) {
717 TRACE("invalid id\n");
718 return DISP_E_MEMBERNOTFOUND
;
724 case DISPATCH_METHOD
|DISPATCH_PROPERTYGET
:
725 wFlags
= DISPATCH_METHOD
;
727 case DISPATCH_METHOD
:
728 case DISPATCH_CONSTRUCT
: {
729 jsval_t
*argv
, buf
[6], r
;
732 hres
= convert_params(pdp
, buf
, &argc
, &argv
);
736 hres
= invoke_prop_func(This
, get_this(pdp
), prop
, wFlags
, argc
, argv
, pvarRes
? &r
: NULL
, pspCaller
);
739 if(SUCCEEDED(hres
) && pvarRes
) {
740 hres
= jsval_to_variant(r
, pvarRes
);
745 case DISPATCH_PROPERTYGET
: {
748 hres
= prop_get(This
, prop
, &r
);
749 if(SUCCEEDED(hres
)) {
750 hres
= jsval_to_variant(r
, pvarRes
);
755 case DISPATCH_PROPERTYPUT
: {
759 for(i
=0; i
< pdp
->cNamedArgs
; i
++) {
760 if(pdp
->rgdispidNamedArgs
[i
] == DISPID_PROPERTYPUT
)
764 if(i
== pdp
->cNamedArgs
) {
765 TRACE("no value to set\n");
766 return DISP_E_PARAMNOTOPTIONAL
;
769 hres
= variant_to_jsval(pdp
->rgvarg
+i
, &val
);
773 hres
= prop_put(This
, prop
, val
);
778 FIXME("Unimplemented flags %x\n", wFlags
);
783 *pei
= This
->ctx
->ei
.ei
;
787 static HRESULT
delete_prop(dispex_prop_t
*prop
, BOOL
*ret
)
789 if(!(prop
->flags
& PROPF_CONFIGURABLE
)) {
794 *ret
= TRUE
; /* FIXME: not exactly right */
796 if(prop
->type
== PROP_JSVAL
) {
797 jsval_release(prop
->u
.val
);
798 prop
->type
= PROP_DELETED
;
800 if(prop
->type
== PROP_ACCESSOR
)
801 FIXME("not supported on accessor property\n");
805 static HRESULT WINAPI
DispatchEx_DeleteMemberByName(IDispatchEx
*iface
, BSTR bstrName
, DWORD grfdex
)
807 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
812 TRACE("(%p)->(%s %x)\n", This
, debugstr_w(bstrName
), grfdex
);
814 if(grfdex
& ~(fdexNameCaseSensitive
|fdexNameEnsure
|fdexNameImplicit
|FDEX_VERSION_MASK
))
815 FIXME("Unsupported grfdex %x\n", grfdex
);
817 hres
= find_prop_name(This
, string_hash(bstrName
), bstrName
, &prop
);
821 TRACE("not found\n");
825 return delete_prop(prop
, &b
);
828 static HRESULT WINAPI
DispatchEx_DeleteMemberByDispID(IDispatchEx
*iface
, DISPID id
)
830 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
834 TRACE("(%p)->(%x)\n", This
, id
);
836 prop
= get_prop(This
, id
);
838 WARN("invalid id\n");
839 return DISP_E_MEMBERNOTFOUND
;
842 return delete_prop(prop
, &b
);
845 static HRESULT WINAPI
DispatchEx_GetMemberProperties(IDispatchEx
*iface
, DISPID id
, DWORD grfdexFetch
, DWORD
*pgrfdex
)
847 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
848 FIXME("(%p)->(%x %x %p)\n", This
, id
, grfdexFetch
, pgrfdex
);
852 static HRESULT WINAPI
DispatchEx_GetMemberName(IDispatchEx
*iface
, DISPID id
, BSTR
*pbstrName
)
854 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
857 TRACE("(%p)->(%x %p)\n", This
, id
, pbstrName
);
859 prop
= get_prop(This
, id
);
860 if(!prop
|| !prop
->name
|| prop
->type
== PROP_DELETED
)
861 return DISP_E_MEMBERNOTFOUND
;
863 *pbstrName
= SysAllocString(prop
->name
);
865 return E_OUTOFMEMORY
;
870 static HRESULT WINAPI
DispatchEx_GetNextDispID(IDispatchEx
*iface
, DWORD grfdex
, DISPID id
, DISPID
*pid
)
872 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
875 TRACE("(%p)->(%x %x %p)\n", This
, grfdex
, id
, pid
);
877 hres
= jsdisp_next_prop(This
, id
, FALSE
, pid
);
879 *pid
= DISPID_STARTENUM
;
883 static HRESULT WINAPI
DispatchEx_GetNameSpaceParent(IDispatchEx
*iface
, IUnknown
**ppunk
)
885 jsdisp_t
*This
= impl_from_IDispatchEx(iface
);
886 FIXME("(%p)->(%p)\n", This
, ppunk
);
890 static IDispatchExVtbl DispatchExVtbl
= {
891 DispatchEx_QueryInterface
,
894 DispatchEx_GetTypeInfoCount
,
895 DispatchEx_GetTypeInfo
,
896 DispatchEx_GetIDsOfNames
,
898 DispatchEx_GetDispID
,
900 DispatchEx_DeleteMemberByName
,
901 DispatchEx_DeleteMemberByDispID
,
902 DispatchEx_GetMemberProperties
,
903 DispatchEx_GetMemberName
,
904 DispatchEx_GetNextDispID
,
905 DispatchEx_GetNameSpaceParent
908 jsdisp_t
*as_jsdisp(IDispatch
*disp
)
910 assert(disp
->lpVtbl
== (IDispatchVtbl
*)&DispatchExVtbl
);
911 return impl_from_IDispatchEx((IDispatchEx
*)disp
);
914 jsdisp_t
*to_jsdisp(IDispatch
*disp
)
916 return disp
->lpVtbl
== (IDispatchVtbl
*)&DispatchExVtbl
? impl_from_IDispatchEx((IDispatchEx
*)disp
) : NULL
;
919 HRESULT
init_dispex(jsdisp_t
*dispex
, script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*prototype
)
921 TRACE("%p (%p)\n", dispex
, prototype
);
923 dispex
->IDispatchEx_iface
.lpVtbl
= &DispatchExVtbl
;
925 dispex
->builtin_info
= builtin_info
;
927 dispex
->props
= heap_alloc_zero(sizeof(dispex_prop_t
)*(dispex
->buf_size
=4));
929 return E_OUTOFMEMORY
;
931 dispex
->prototype
= prototype
;
933 jsdisp_addref(prototype
);
935 dispex
->prop_cnt
= 1;
936 if(builtin_info
->value_prop
.invoke
|| builtin_info
->value_prop
.getter
) {
937 dispex
->props
[0].type
= PROP_BUILTIN
;
938 dispex
->props
[0].u
.p
= &builtin_info
->value_prop
;
940 dispex
->props
[0].type
= PROP_DELETED
;
949 static const builtin_info_t dispex_info
= {
957 HRESULT
create_dispex(script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*prototype
, jsdisp_t
**dispex
)
962 ret
= heap_alloc_zero(sizeof(jsdisp_t
));
964 return E_OUTOFMEMORY
;
966 hres
= init_dispex(ret
, ctx
, builtin_info
? builtin_info
: &dispex_info
, prototype
);
976 void jsdisp_free(jsdisp_t
*obj
)
980 TRACE("(%p)\n", obj
);
982 for(prop
= obj
->props
; prop
< obj
->props
+obj
->prop_cnt
; prop
++) {
985 jsval_release(prop
->u
.val
);
988 if(prop
->u
.accessor
.getter
)
989 jsdisp_release(prop
->u
.accessor
.getter
);
990 if(prop
->u
.accessor
.setter
)
991 jsdisp_release(prop
->u
.accessor
.setter
);
996 heap_free(prop
->name
);
998 heap_free(obj
->props
);
999 script_release(obj
->ctx
);
1001 jsdisp_release(obj
->prototype
);
1003 if(obj
->builtin_info
->destructor
)
1004 obj
->builtin_info
->destructor(obj
);
1011 jsdisp_t
*jsdisp_addref(jsdisp_t
*jsdisp
)
1013 ULONG ref
= ++jsdisp
->ref
;
1014 TRACE("(%p) ref=%d\n", jsdisp
, ref
);
1018 void jsdisp_release(jsdisp_t
*jsdisp
)
1020 ULONG ref
= --jsdisp
->ref
;
1022 TRACE("(%p) ref=%d\n", jsdisp
, ref
);
1025 jsdisp_free(jsdisp
);
1030 HRESULT
init_dispex_from_constr(jsdisp_t
*dispex
, script_ctx_t
*ctx
, const builtin_info_t
*builtin_info
, jsdisp_t
*constr
)
1032 jsdisp_t
*prot
= NULL
;
1033 dispex_prop_t
*prop
;
1036 static const WCHAR prototypeW
[] = {'p','r','o','t','o','t','y','p','e',0};
1038 hres
= find_prop_name_prot(constr
, string_hash(prototypeW
), prototypeW
, &prop
);
1039 if(SUCCEEDED(hres
) && prop
&& prop
->type
!=PROP_DELETED
) {
1042 hres
= prop_get(constr
, prop
, &val
);
1044 ERR("Could not get prototype\n");
1048 if(is_object_instance(val
))
1049 prot
= iface_to_jsdisp(get_object(val
));
1053 hres
= init_dispex(dispex
, ctx
, builtin_info
, prot
);
1056 jsdisp_release(prot
);
1060 jsdisp_t
*iface_to_jsdisp(IDispatch
*iface
)
1062 return iface
->lpVtbl
== (const IDispatchVtbl
*)&DispatchExVtbl
1063 ? jsdisp_addref( impl_from_IDispatchEx((IDispatchEx
*)iface
))
1067 HRESULT
jsdisp_get_id(jsdisp_t
*jsdisp
, const WCHAR
*name
, DWORD flags
, DISPID
*id
)
1069 dispex_prop_t
*prop
;
1072 if(flags
& fdexNameEnsure
)
1073 hres
= ensure_prop_name(jsdisp
, name
, PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
,
1076 hres
= find_prop_name_prot(jsdisp
, string_hash(name
), name
, &prop
);
1080 if(prop
&& prop
->type
!=PROP_DELETED
) {
1081 *id
= prop_to_id(jsdisp
, prop
);
1085 TRACE("not found %s\n", debugstr_w(name
));
1086 return DISP_E_UNKNOWNNAME
;
1089 HRESULT
jsdisp_call_value(jsdisp_t
*jsfunc
, IDispatch
*jsthis
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1093 assert(!(flags
& ~(DISPATCH_METHOD
|DISPATCH_CONSTRUCT
|DISPATCH_JSCRIPT_INTERNAL_MASK
)));
1095 if(is_class(jsfunc
, JSCLASS_FUNCTION
)) {
1096 hres
= Function_invoke(jsfunc
, jsthis
, flags
, argc
, argv
, r
);
1100 if(!jsfunc
->builtin_info
->value_prop
.invoke
) {
1101 WARN("Not a function\n");
1102 return throw_type_error(jsfunc
->ctx
, JS_E_FUNCTION_EXPECTED
, NULL
);
1105 set_disp(&vdisp
, jsthis
);
1106 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
1107 hres
= jsfunc
->builtin_info
->value_prop
.invoke(jsfunc
->ctx
, &vdisp
, flags
, argc
, argv
, r
);
1108 vdisp_release(&vdisp
);
1113 HRESULT
jsdisp_call(jsdisp_t
*disp
, DISPID id
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1115 dispex_prop_t
*prop
;
1117 prop
= get_prop(disp
, id
);
1119 return DISP_E_MEMBERNOTFOUND
;
1121 return invoke_prop_func(disp
, to_disp(disp
), prop
, flags
, argc
, argv
, r
, NULL
);
1124 HRESULT
jsdisp_call_name(jsdisp_t
*disp
, const WCHAR
*name
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*r
)
1126 dispex_prop_t
*prop
;
1129 hres
= find_prop_name_prot(disp
, string_hash(name
), name
, &prop
);
1133 return invoke_prop_func(disp
, to_disp(disp
), prop
, flags
, argc
, argv
, r
, NULL
);
1136 HRESULT
disp_call(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, WORD flags
, unsigned argc
, jsval_t
*argv
, jsval_t
*ret
)
1138 IDispatchEx
*dispex
;
1140 VARIANT buf
[6], retv
;
1145 jsdisp
= iface_to_jsdisp(disp
);
1147 if(flags
& DISPATCH_PROPERTYPUT
) {
1148 FIXME("disp_call(propput) on builtin object\n");
1152 if(ctx
!= jsdisp
->ctx
)
1153 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
1154 hres
= jsdisp_call(jsdisp
, id
, flags
, argc
, argv
, ret
);
1155 jsdisp_release(jsdisp
);
1159 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
1161 flags
|= DISPATCH_PROPERTYGET
;
1165 if(flags
& DISPATCH_PROPERTYPUT
) {
1166 static DISPID propput_dispid
= DISPID_PROPERTYPUT
;
1169 dp
.rgdispidNamedArgs
= &propput_dispid
;
1172 dp
.rgdispidNamedArgs
= NULL
;
1176 dp
.rgvarg
= heap_alloc(argc
*sizeof(VARIANT
));
1178 return E_OUTOFMEMORY
;
1183 for(i
=0; i
<argc
; i
++) {
1184 hres
= jsval_to_variant(argv
[i
], dp
.rgvarg
+argc
-i
-1);
1187 VariantClear(dp
.rgvarg
+argc
-i
-1);
1188 if(dp
.rgvarg
!= buf
)
1189 heap_free(dp
.rgvarg
);
1194 V_VT(&retv
) = VT_EMPTY
;
1196 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
1197 if(SUCCEEDED(hres
)) {
1198 hres
= IDispatchEx_InvokeEx(dispex
, id
, ctx
->lcid
, flags
, &dp
, ret
? &retv
: NULL
, &ctx
->ei
.ei
,
1199 &ctx
->jscaller
->IServiceProvider_iface
);
1200 IDispatchEx_Release(dispex
);
1204 if(flags
== DISPATCH_CONSTRUCT
) {
1205 WARN("IDispatch cannot be constructor\n");
1206 return DISP_E_MEMBERNOTFOUND
;
1209 TRACE("using IDispatch\n");
1210 hres
= IDispatch_Invoke(disp
, id
, &IID_NULL
, ctx
->lcid
, flags
, &dp
, ret
? &retv
: NULL
, &ctx
->ei
.ei
, &err
);
1213 for(i
=0; i
<argc
; i
++)
1214 VariantClear(dp
.rgvarg
+argc
-i
-1);
1215 if(dp
.rgvarg
!= buf
)
1216 heap_free(dp
.rgvarg
);
1221 hres
= variant_to_jsval(&retv
, ret
);
1222 VariantClear(&retv
);
1228 HRESULT
disp_call_value(script_ctx_t
*ctx
, IDispatch
*disp
, IDispatch
*jsthis
, WORD flags
, unsigned argc
, jsval_t
*argv
,
1232 IDispatchEx
*dispex
;
1233 VARIANT buf
[6], retv
;
1238 assert(!(flags
& ~(DISPATCH_METHOD
|DISPATCH_CONSTRUCT
|DISPATCH_JSCRIPT_INTERNAL_MASK
)));
1240 jsdisp
= iface_to_jsdisp(disp
);
1242 if(ctx
!= jsdisp
->ctx
)
1243 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
1244 hres
= jsdisp_call_value(jsdisp
, jsthis
, flags
, argc
, argv
, r
);
1245 jsdisp_release(jsdisp
);
1249 flags
&= ~DISPATCH_JSCRIPT_INTERNAL_MASK
;
1250 if(r
&& argc
&& flags
== DISPATCH_METHOD
)
1251 flags
|= DISPATCH_PROPERTYGET
;
1253 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
1255 TRACE("using IDispatch\n");
1261 static DISPID this_id
= DISPID_THIS
;
1265 dp
.rgdispidNamedArgs
= &this_id
;
1269 dp
.rgdispidNamedArgs
= NULL
;
1272 if(dp
.cArgs
> ARRAY_SIZE(buf
)) {
1273 dp
.rgvarg
= heap_alloc(dp
.cArgs
*sizeof(VARIANT
));
1276 IDispatchEx_Release(dispex
);
1277 return E_OUTOFMEMORY
;
1283 for(i
=0; i
<argc
; i
++) {
1284 hres
= jsval_to_variant(argv
[i
], dp
.rgvarg
+dp
.cArgs
-i
-1);
1287 VariantClear(dp
.rgvarg
+dp
.cArgs
-i
-1);
1288 if(dp
.rgvarg
!= buf
)
1289 heap_free(dp
.rgvarg
);
1291 IDispatchEx_Release(dispex
);
1296 V_VT(dp
.rgvarg
) = VT_DISPATCH
;
1297 V_DISPATCH(dp
.rgvarg
) = jsthis
;
1300 V_VT(&retv
) = VT_EMPTY
;
1303 hres
= IDispatchEx_InvokeEx(dispex
, DISPID_VALUE
, ctx
->lcid
, flags
, &dp
, r
? &retv
: NULL
, &ctx
->ei
.ei
,
1304 &ctx
->jscaller
->IServiceProvider_iface
);
1305 IDispatchEx_Release(dispex
);
1309 if(flags
== DISPATCH_CONSTRUCT
) {
1310 WARN("IDispatch cannot be constructor\n");
1311 return DISP_E_MEMBERNOTFOUND
;
1314 hres
= IDispatch_Invoke(disp
, DISPID_VALUE
, &IID_NULL
, ctx
->lcid
, flags
, &dp
, r
? &retv
: NULL
, &ctx
->ei
.ei
, &err
);
1317 for(i
=0; i
<argc
; i
++)
1318 VariantClear(dp
.rgvarg
+dp
.cArgs
-i
-1);
1319 if(dp
.rgvarg
!= buf
)
1320 heap_free(dp
.rgvarg
);
1327 hres
= variant_to_jsval(&retv
, r
);
1328 VariantClear(&retv
);
1332 HRESULT
jsdisp_propput(jsdisp_t
*obj
, const WCHAR
*name
, DWORD flags
, jsval_t val
)
1334 dispex_prop_t
*prop
;
1337 hres
= ensure_prop_name(obj
, name
, flags
, &prop
);
1341 return prop_put(obj
, prop
, val
);
1344 HRESULT
jsdisp_propput_name(jsdisp_t
*obj
, const WCHAR
*name
, jsval_t val
)
1346 return jsdisp_propput(obj
, name
, PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
| PROPF_WRITABLE
, val
);
1349 HRESULT
jsdisp_propput_idx(jsdisp_t
*obj
, DWORD idx
, jsval_t val
)
1353 static const WCHAR formatW
[] = {'%','d',0};
1355 swprintf(buf
, formatW
, idx
);
1356 return jsdisp_propput_name(obj
, buf
, val
);
1359 HRESULT
disp_propput(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, jsval_t val
)
1364 jsdisp
= iface_to_jsdisp(disp
);
1366 dispex_prop_t
*prop
;
1368 prop
= get_prop(jsdisp
, id
);
1370 hres
= prop_put(jsdisp
, prop
, val
);
1372 hres
= DISP_E_MEMBERNOTFOUND
;
1374 jsdisp_release(jsdisp
);
1376 DISPID dispid
= DISPID_PROPERTYPUT
;
1377 DWORD flags
= DISPATCH_PROPERTYPUT
;
1379 DISPPARAMS dp
= {&var
, &dispid
, 1, 1};
1380 IDispatchEx
*dispex
;
1382 hres
= jsval_to_variant(val
, &var
);
1386 if(V_VT(&var
) == VT_DISPATCH
)
1387 flags
|= DISPATCH_PROPERTYPUTREF
;
1390 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
1391 if(SUCCEEDED(hres
)) {
1392 hres
= IDispatchEx_InvokeEx(dispex
, id
, ctx
->lcid
, flags
, &dp
, NULL
, &ctx
->ei
.ei
,
1393 &ctx
->jscaller
->IServiceProvider_iface
);
1394 IDispatchEx_Release(dispex
);
1398 TRACE("using IDispatch\n");
1399 hres
= IDispatch_Invoke(disp
, id
, &IID_NULL
, ctx
->lcid
, flags
, &dp
, NULL
, &ctx
->ei
.ei
, &err
);
1408 HRESULT
jsdisp_propget_name(jsdisp_t
*obj
, const WCHAR
*name
, jsval_t
*val
)
1410 dispex_prop_t
*prop
;
1413 hres
= find_prop_name_prot(obj
, string_hash(name
), name
, &prop
);
1417 if(!prop
|| prop
->type
==PROP_DELETED
) {
1418 *val
= jsval_undefined();
1422 return prop_get(obj
, prop
, val
);
1425 HRESULT
jsdisp_get_idx(jsdisp_t
*obj
, DWORD idx
, jsval_t
*r
)
1428 dispex_prop_t
*prop
;
1431 static const WCHAR formatW
[] = {'%','d',0};
1433 swprintf(name
, formatW
, idx
);
1435 hres
= find_prop_name_prot(obj
, string_hash(name
), name
, &prop
);
1439 if(!prop
|| prop
->type
==PROP_DELETED
) {
1440 *r
= jsval_undefined();
1441 return DISP_E_UNKNOWNNAME
;
1444 return prop_get(obj
, prop
, r
);
1447 HRESULT
jsdisp_propget(jsdisp_t
*jsdisp
, DISPID id
, jsval_t
*val
)
1449 dispex_prop_t
*prop
;
1451 prop
= get_prop(jsdisp
, id
);
1453 return DISP_E_MEMBERNOTFOUND
;
1455 return prop_get(jsdisp
, prop
, val
);
1458 HRESULT
disp_propget(script_ctx_t
*ctx
, IDispatch
*disp
, DISPID id
, jsval_t
*val
)
1460 DISPPARAMS dp
= {NULL
,NULL
,0,0};
1461 IDispatchEx
*dispex
;
1466 jsdisp
= iface_to_jsdisp(disp
);
1468 hres
= jsdisp_propget(jsdisp
, id
, val
);
1469 jsdisp_release(jsdisp
);
1473 V_VT(&var
) = VT_EMPTY
;
1475 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
1476 if(SUCCEEDED(hres
)) {
1477 hres
= IDispatchEx_InvokeEx(dispex
, id
, ctx
->lcid
, INVOKE_PROPERTYGET
, &dp
, &var
, &ctx
->ei
.ei
,
1478 &ctx
->jscaller
->IServiceProvider_iface
);
1479 IDispatchEx_Release(dispex
);
1483 TRACE("using IDispatch\n");
1484 hres
= IDispatch_Invoke(disp
, id
, &IID_NULL
, ctx
->lcid
, INVOKE_PROPERTYGET
, &dp
, &var
, &ctx
->ei
.ei
, &err
);
1489 hres
= variant_to_jsval(&var
, val
);
1494 HRESULT
jsdisp_delete_idx(jsdisp_t
*obj
, DWORD idx
)
1496 static const WCHAR formatW
[] = {'%','d',0};
1498 dispex_prop_t
*prop
;
1502 swprintf(buf
, formatW
, idx
);
1504 hres
= find_prop_name(obj
, string_hash(buf
), buf
, &prop
);
1505 if(FAILED(hres
) || !prop
)
1508 return delete_prop(prop
, &b
);
1511 HRESULT
disp_delete(IDispatch
*disp
, DISPID id
, BOOL
*ret
)
1513 IDispatchEx
*dispex
;
1517 jsdisp
= iface_to_jsdisp(disp
);
1519 dispex_prop_t
*prop
;
1521 prop
= get_prop(jsdisp
, id
);
1523 hres
= delete_prop(prop
, ret
);
1525 hres
= DISP_E_MEMBERNOTFOUND
;
1527 jsdisp_release(jsdisp
);
1531 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
1537 hres
= IDispatchEx_DeleteMemberByDispID(dispex
, id
);
1538 IDispatchEx_Release(dispex
);
1542 *ret
= hres
== S_OK
;
1546 HRESULT
jsdisp_next_prop(jsdisp_t
*obj
, DISPID id
, BOOL own_only
, DISPID
*ret
)
1548 dispex_prop_t
*iter
;
1551 if(id
== DISPID_STARTENUM
&& !own_only
) {
1552 hres
= fill_protrefs(obj
);
1557 if(id
+ 1 < 0 || id
+1 >= obj
->prop_cnt
)
1560 for(iter
= &obj
->props
[id
+ 1]; iter
< obj
->props
+ obj
->prop_cnt
; iter
++) {
1561 if(!iter
->name
|| iter
->type
== PROP_DELETED
)
1563 if(own_only
&& iter
->type
== PROP_PROTREF
)
1565 if(!(get_flags(obj
, iter
) & PROPF_ENUMERABLE
))
1567 *ret
= prop_to_id(obj
, iter
);
1574 HRESULT
disp_delete_name(script_ctx_t
*ctx
, IDispatch
*disp
, jsstr_t
*name
, BOOL
*ret
)
1576 IDispatchEx
*dispex
;
1581 jsdisp
= iface_to_jsdisp(disp
);
1583 dispex_prop_t
*prop
;
1586 ptr
= jsstr_flatten(name
);
1588 jsdisp_release(jsdisp
);
1589 return E_OUTOFMEMORY
;
1592 hres
= find_prop_name(jsdisp
, string_hash(ptr
), ptr
, &prop
);
1594 hres
= delete_prop(prop
, ret
);
1600 jsdisp_release(jsdisp
);
1604 bstr
= SysAllocStringLen(NULL
, jsstr_length(name
));
1606 return E_OUTOFMEMORY
;
1607 jsstr_flush(name
, bstr
);
1609 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
1610 if(SUCCEEDED(hres
)) {
1611 hres
= IDispatchEx_DeleteMemberByName(dispex
, bstr
, make_grfdex(ctx
, fdexNameCaseSensitive
));
1613 *ret
= hres
== S_OK
;
1614 IDispatchEx_Release(dispex
);
1618 hres
= IDispatch_GetIDsOfNames(disp
, &IID_NULL
, &bstr
, 1, 0, &id
);
1619 if(SUCCEEDED(hres
)) {
1620 /* Property exists and we can't delete it from pure IDispatch interface, so return false. */
1622 }else if(hres
== DISP_E_UNKNOWNNAME
) {
1623 /* Property doesn't exist, so nothing to delete */
1629 SysFreeString(bstr
);
1633 HRESULT
jsdisp_get_own_property(jsdisp_t
*obj
, const WCHAR
*name
, BOOL flags_only
,
1634 property_desc_t
*desc
)
1636 dispex_prop_t
*prop
;
1639 hres
= find_prop_name(obj
, string_hash(name
), name
, &prop
);
1644 return DISP_E_UNKNOWNNAME
;
1646 memset(desc
, 0, sizeof(*desc
));
1648 switch(prop
->type
) {
1651 desc
->mask
|= PROPF_WRITABLE
;
1652 desc
->explicit_value
= TRUE
;
1654 hres
= prop_get(obj
, prop
, &desc
->value
);
1660 desc
->explicit_getter
= desc
->explicit_setter
= TRUE
;
1662 desc
->getter
= prop
->u
.accessor
.getter
1663 ? jsdisp_addref(prop
->u
.accessor
.getter
) : NULL
;
1664 desc
->setter
= prop
->u
.accessor
.setter
1665 ? jsdisp_addref(prop
->u
.accessor
.setter
) : NULL
;
1669 return DISP_E_UNKNOWNNAME
;
1672 desc
->flags
= prop
->flags
& (PROPF_ENUMERABLE
| PROPF_WRITABLE
| PROPF_CONFIGURABLE
);
1673 desc
->mask
|= PROPF_ENUMERABLE
| PROPF_CONFIGURABLE
;
1677 HRESULT
jsdisp_define_property(jsdisp_t
*obj
, const WCHAR
*name
, property_desc_t
*desc
)
1679 dispex_prop_t
*prop
;
1682 hres
= find_prop_name(obj
, string_hash(name
), name
, &prop
);
1686 if(!prop
&& !(prop
= alloc_prop(obj
, name
, PROP_DELETED
, 0)))
1687 return E_OUTOFMEMORY
;
1689 if(prop
->type
== PROP_DELETED
|| prop
->type
== PROP_PROTREF
) {
1690 prop
->flags
= desc
->flags
;
1691 if(desc
->explicit_getter
|| desc
->explicit_setter
) {
1692 prop
->type
= PROP_ACCESSOR
;
1693 prop
->u
.accessor
.getter
= desc
->getter
? jsdisp_addref(desc
->getter
) : NULL
;
1694 prop
->u
.accessor
.setter
= desc
->setter
? jsdisp_addref(desc
->setter
) : NULL
;
1695 TRACE("%s = accessor { get: %p set: %p }\n", debugstr_w(name
),
1696 prop
->u
.accessor
.getter
, prop
->u
.accessor
.setter
);
1698 prop
->type
= PROP_JSVAL
;
1699 if(desc
->explicit_value
) {
1700 hres
= jsval_copy(desc
->value
, &prop
->u
.val
);
1704 prop
->u
.val
= jsval_undefined();
1706 TRACE("%s = %s\n", debugstr_w(name
), debugstr_jsval(prop
->u
.val
));
1711 TRACE("existing prop %s prop flags %x desc flags %x desc mask %x\n", debugstr_w(name
),
1712 prop
->flags
, desc
->flags
, desc
->mask
);
1714 if(!(prop
->flags
& PROPF_CONFIGURABLE
)) {
1715 if(((desc
->mask
& PROPF_CONFIGURABLE
) && (desc
->flags
& PROPF_CONFIGURABLE
))
1716 || ((desc
->mask
& PROPF_ENUMERABLE
)
1717 && ((desc
->flags
& PROPF_ENUMERABLE
) != (prop
->flags
& PROPF_ENUMERABLE
))))
1718 return throw_type_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
1721 if(desc
->explicit_value
|| (desc
->mask
& PROPF_WRITABLE
)) {
1722 if(prop
->type
== PROP_ACCESSOR
) {
1723 if(!(prop
->flags
& PROPF_CONFIGURABLE
))
1724 return throw_type_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
1725 if(prop
->u
.accessor
.getter
)
1726 jsdisp_release(prop
->u
.accessor
.getter
);
1727 if(prop
->u
.accessor
.setter
)
1728 jsdisp_release(prop
->u
.accessor
.setter
);
1730 prop
->type
= PROP_JSVAL
;
1731 hres
= jsval_copy(desc
->value
, &prop
->u
.val
);
1733 prop
->u
.val
= jsval_undefined();
1737 if(!(prop
->flags
& PROPF_CONFIGURABLE
) && !(prop
->flags
& PROPF_WRITABLE
)) {
1738 if((desc
->mask
& PROPF_WRITABLE
) && (desc
->flags
& PROPF_WRITABLE
))
1739 return throw_type_error(obj
->ctx
, JS_E_NONWRITABLE_MODIFIED
, name
);
1740 if(desc
->explicit_value
) {
1741 if(prop
->type
== PROP_JSVAL
) {
1743 hres
= jsval_strict_equal(desc
->value
, prop
->u
.val
, &eq
);
1747 return throw_type_error(obj
->ctx
, JS_E_NONWRITABLE_MODIFIED
, name
);
1749 FIXME("redefinition of property type %d\n", prop
->type
);
1753 if(desc
->explicit_value
) {
1754 if(prop
->type
== PROP_JSVAL
)
1755 jsval_release(prop
->u
.val
);
1757 prop
->type
= PROP_JSVAL
;
1758 hres
= jsval_copy(desc
->value
, &prop
->u
.val
);
1760 prop
->u
.val
= jsval_undefined();
1765 }else if(desc
->explicit_getter
|| desc
->explicit_setter
) {
1766 if(prop
->type
!= PROP_ACCESSOR
) {
1767 if(!(prop
->flags
& PROPF_CONFIGURABLE
))
1768 return throw_type_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
1769 if(prop
->type
== PROP_JSVAL
)
1770 jsval_release(prop
->u
.val
);
1771 prop
->type
= PROP_ACCESSOR
;
1772 prop
->u
.accessor
.getter
= prop
->u
.accessor
.setter
= NULL
;
1773 }else if(!(prop
->flags
& PROPF_CONFIGURABLE
)) {
1774 if((desc
->explicit_getter
&& desc
->getter
!= prop
->u
.accessor
.getter
)
1775 || (desc
->explicit_setter
&& desc
->setter
!= prop
->u
.accessor
.setter
))
1776 return throw_type_error(obj
->ctx
, JS_E_NONCONFIGURABLE_REDEFINED
, name
);
1779 if(desc
->explicit_getter
) {
1780 if(prop
->u
.accessor
.getter
) {
1781 jsdisp_release(prop
->u
.accessor
.getter
);
1782 prop
->u
.accessor
.getter
= NULL
;
1785 prop
->u
.accessor
.getter
= jsdisp_addref(desc
->getter
);
1787 if(desc
->explicit_setter
) {
1788 if(prop
->u
.accessor
.setter
) {
1789 jsdisp_release(prop
->u
.accessor
.setter
);
1790 prop
->u
.accessor
.setter
= NULL
;
1793 prop
->u
.accessor
.setter
= jsdisp_addref(desc
->setter
);
1797 prop
->flags
= (prop
->flags
& ~desc
->mask
) | (desc
->flags
& desc
->mask
);
1801 HRESULT
jsdisp_define_data_property(jsdisp_t
*obj
, const WCHAR
*name
, unsigned flags
, jsval_t value
)
1803 property_desc_t prop_desc
= { flags
, flags
, TRUE
};
1804 prop_desc
.value
= value
;
1805 return jsdisp_define_property(obj
, name
, &prop_desc
);