msvcp110: Add tr2_sys__File_size_wchar implementation and test.
[wine/multimedia.git] / dlls / jscript / dispex.c
blob40e17496a03c9ca30441d5c05fed48fe707ae4ff
1 /*
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
19 #include <assert.h>
21 #include "jscript.h"
23 #include "wine/unicode.h"
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
29 * This IID is used to get jsdisp_t objecto from interface.
30 * We might consider using private interface instead.
32 static const IID IID_IDispatchJS =
33 {0x719c3050,0xf9d3,0x11cf,{0xa4,0x93,0x00,0x40,0x05,0x23,0xa8,0xa6}};
35 #define FDEX_VERSION_MASK 0xf0000000
36 #define GOLDEN_RATIO 0x9E3779B9U
38 typedef enum {
39 PROP_JSVAL,
40 PROP_BUILTIN,
41 PROP_PROTREF,
42 PROP_DELETED,
43 PROP_IDX
44 } prop_type_t;
46 struct _dispex_prop_t {
47 WCHAR *name;
48 unsigned hash;
49 prop_type_t type;
50 DWORD flags;
52 union {
53 jsval_t val;
54 const builtin_prop_t *p;
55 DWORD ref;
56 unsigned idx;
57 } u;
59 int bucket_head;
60 int bucket_next;
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)
71 return NULL;
73 return This->props+id;
76 static DWORD get_flags(jsdisp_t *This, dispex_prop_t *prop)
78 if(prop->type == PROP_PROTREF) {
79 dispex_prop_t *parent = get_prop(This->prototype, prop->u.ref);
80 if(!parent) {
81 prop->type = PROP_DELETED;
82 return 0;
85 return get_flags(This->prototype, parent);
88 return prop->flags;
91 static const builtin_prop_t *find_builtin_prop(jsdisp_t *This, const WCHAR *name)
93 int min = 0, max, i, r;
95 max = This->builtin_info->props_cnt-1;
96 while(min <= max) {
97 i = (min+max)/2;
99 r = strcmpW(name, This->builtin_info->props[i].name);
100 if(!r)
101 return This->builtin_info->props + i;
103 if(r < 0)
104 max = i-1;
105 else
106 min = i+1;
109 return NULL;
112 static inline unsigned string_hash(const WCHAR *name)
114 unsigned h = 0;
115 for(; *name; name++)
116 h = (h>>(sizeof(unsigned)*8-4)) ^ (h<<4) ^ tolowerW(*name);
117 return h;
120 static inline unsigned get_props_idx(jsdisp_t *This, unsigned hash)
122 return (hash*GOLDEN_RATIO) & (This->buf_size-1);
125 static inline HRESULT resize_props(jsdisp_t *This)
127 dispex_prop_t *props;
128 int i, bucket;
130 if(This->buf_size != This->prop_cnt)
131 return S_FALSE;
133 props = heap_realloc(This->props, sizeof(dispex_prop_t)*This->buf_size*2);
134 if(!props)
135 return E_OUTOFMEMORY;
136 This->buf_size *= 2;
137 This->props = props;
139 for(i=0; i<This->buf_size; i++) {
140 This->props[i].bucket_head = 0;
141 This->props[i].bucket_next = 0;
144 for(i=1; i<This->prop_cnt; i++) {
145 props = This->props+i;
147 bucket = get_props_idx(This, props->hash);
148 props->bucket_next = This->props[bucket].bucket_head;
149 This->props[bucket].bucket_head = i;
152 return S_OK;
155 static inline dispex_prop_t* alloc_prop(jsdisp_t *This, const WCHAR *name, prop_type_t type, DWORD flags)
157 dispex_prop_t *prop;
158 unsigned bucket;
160 if(FAILED(resize_props(This)))
161 return NULL;
163 prop = &This->props[This->prop_cnt];
164 prop->name = heap_strdupW(name);
165 if(!prop->name)
166 return NULL;
167 prop->type = type;
168 prop->flags = flags;
169 prop->hash = string_hash(name);
171 bucket = get_props_idx(This, prop->hash);
172 prop->bucket_next = This->props[bucket].bucket_head;
173 This->props[bucket].bucket_head = This->prop_cnt++;
174 return prop;
177 static dispex_prop_t *alloc_protref(jsdisp_t *This, const WCHAR *name, DWORD ref)
179 dispex_prop_t *ret;
181 ret = alloc_prop(This, name, PROP_PROTREF, 0);
182 if(!ret)
183 return NULL;
185 ret->u.ref = ref;
186 return ret;
189 static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, dispex_prop_t **ret)
191 const builtin_prop_t *builtin;
192 unsigned bucket, pos, prev = 0;
193 dispex_prop_t *prop;
195 bucket = get_props_idx(This, hash);
196 pos = This->props[bucket].bucket_head;
197 while(pos != 0) {
198 if(!strcmpW(name, This->props[pos].name)) {
199 if(prev != 0) {
200 This->props[prev].bucket_next = This->props[pos].bucket_next;
201 This->props[pos].bucket_next = This->props[bucket].bucket_head;
202 This->props[bucket].bucket_head = pos;
205 *ret = &This->props[pos];
206 return S_OK;
209 prev = pos;
210 pos = This->props[pos].bucket_next;
213 builtin = find_builtin_prop(This, name);
214 if(builtin) {
215 prop = alloc_prop(This, name, PROP_BUILTIN, builtin->flags);
216 if(!prop)
217 return E_OUTOFMEMORY;
219 prop->u.p = builtin;
220 *ret = prop;
221 return S_OK;
224 if(This->builtin_info->idx_length) {
225 const WCHAR *ptr;
226 unsigned idx = 0;
228 for(ptr = name; isdigitW(*ptr) && idx < 0x10000; ptr++)
229 idx = idx*10 + (*ptr-'0');
230 if(!*ptr && idx < This->builtin_info->idx_length(This)) {
231 prop = alloc_prop(This, name, PROP_IDX, This->builtin_info->idx_put ? 0 : PROPF_CONST);
232 if(!prop)
233 return E_OUTOFMEMORY;
235 prop->u.idx = idx;
236 *ret = prop;
237 return S_OK;
241 *ret = NULL;
242 return S_OK;
245 static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *name, dispex_prop_t **ret)
247 dispex_prop_t *prop, *del=NULL;
248 HRESULT hres;
250 hres = find_prop_name(This, hash, name, &prop);
251 if(FAILED(hres))
252 return hres;
253 if(prop && prop->type==PROP_DELETED) {
254 del = prop;
255 } else if(prop) {
256 *ret = prop;
257 return S_OK;
260 if(This->prototype) {
261 hres = find_prop_name_prot(This->prototype, hash, name, &prop);
262 if(FAILED(hres))
263 return hres;
264 if(prop) {
265 if(del) {
266 del->type = PROP_PROTREF;
267 del->flags = 0;
268 del->u.ref = prop - This->prototype->props;
269 prop = del;
270 }else {
271 prop = alloc_protref(This, prop->name, prop - This->prototype->props);
272 if(!prop)
273 return E_OUTOFMEMORY;
276 *ret = prop;
277 return S_OK;
281 *ret = del;
282 return S_OK;
285 static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, BOOL search_prot, DWORD create_flags, dispex_prop_t **ret)
287 dispex_prop_t *prop;
288 HRESULT hres;
290 if(search_prot)
291 hres = find_prop_name_prot(This, string_hash(name), name, &prop);
292 else
293 hres = find_prop_name(This, string_hash(name), name, &prop);
294 if(SUCCEEDED(hres) && (!prop || prop->type == PROP_DELETED)) {
295 TRACE("creating prop %s flags %x\n", debugstr_w(name), create_flags);
297 if(prop) {
298 prop->type = PROP_JSVAL;
299 prop->flags = create_flags;
300 prop->u.val = jsval_undefined();
301 }else {
302 prop = alloc_prop(This, name, PROP_JSVAL, create_flags);
303 if(!prop)
304 return E_OUTOFMEMORY;
307 prop->u.val = jsval_undefined();
310 *ret = prop;
311 return hres;
314 static IDispatch *get_this(DISPPARAMS *dp)
316 DWORD i;
318 for(i=0; i < dp->cNamedArgs; i++) {
319 if(dp->rgdispidNamedArgs[i] == DISPID_THIS) {
320 if(V_VT(dp->rgvarg+i) == VT_DISPATCH)
321 return V_DISPATCH(dp->rgvarg+i);
323 WARN("This is not VT_DISPATCH\n");
324 return NULL;
328 TRACE("no this passed\n");
329 return NULL;
332 static HRESULT convert_params(const DISPPARAMS *dp, jsval_t *buf, unsigned *argc, jsval_t **ret)
334 jsval_t *argv;
335 unsigned cnt;
336 unsigned i;
337 HRESULT hres;
339 cnt = dp->cArgs - dp->cNamedArgs;
341 if(cnt > 6) {
342 argv = heap_alloc(cnt * sizeof(*argv));
343 if(!argv)
344 return E_OUTOFMEMORY;
345 }else {
346 argv = buf;
349 for(i = 0; i < cnt; i++) {
350 hres = variant_to_jsval(dp->rgvarg+dp->cArgs-i-1, argv+i);
351 if(FAILED(hres)) {
352 while(i--)
353 jsval_release(argv[i]);
354 if(argv != buf)
355 heap_free(argv);
356 return hres;
360 *argc = cnt;
361 *ret = argv;
362 return S_OK;
365 static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t *prop, WORD flags,
366 unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller)
368 HRESULT hres;
370 switch(prop->type) {
371 case PROP_BUILTIN: {
372 if(flags == DISPATCH_CONSTRUCT && (prop->flags & PROPF_METHOD)) {
373 WARN("%s is not a constructor\n", debugstr_w(prop->name));
374 return E_INVALIDARG;
377 if(prop->name || This->builtin_info->class != JSCLASS_FUNCTION) {
378 vdisp_t vthis;
380 if(jsthis)
381 set_disp(&vthis, jsthis);
382 else
383 set_jsdisp(&vthis, This);
384 hres = prop->u.p->invoke(This->ctx, &vthis, flags, argc, argv, r);
385 vdisp_release(&vthis);
386 }else {
387 /* Function object calls are special case */
388 hres = Function_invoke(This, jsthis, flags, argc, argv, r);
390 return hres;
392 case PROP_PROTREF:
393 return invoke_prop_func(This->prototype, jsthis, This->prototype->props+prop->u.ref,
394 flags, argc, argv, r, caller);
395 case PROP_JSVAL: {
396 if(!is_object_instance(prop->u.val)) {
397 FIXME("invoke %s\n", debugstr_jsval(prop->u.val));
398 return E_FAIL;
401 TRACE("call %s %p\n", debugstr_w(prop->name), get_object(prop->u.val));
403 return disp_call_value(This->ctx, get_object(prop->u.val), jsthis, flags, argc, argv, r);
405 case PROP_IDX:
406 FIXME("Invoking PROP_IDX not yet supported\n");
407 return E_NOTIMPL;
408 case PROP_DELETED:
409 assert(0);
412 assert(0);
413 return E_FAIL;
416 static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, DISPPARAMS *dp,
417 jsval_t *r, IServiceProvider *caller)
419 HRESULT hres;
421 switch(prop->type) {
422 case PROP_BUILTIN:
423 if(prop->u.p->getter) {
424 hres = prop->u.p->getter(This->ctx, This, r);
425 }else {
426 jsdisp_t *obj;
428 assert(prop->u.p->invoke != NULL);
429 hres = create_builtin_function(This->ctx, prop->u.p->invoke, prop->u.p->name, NULL,
430 prop->u.p->flags, NULL, &obj);
431 if(FAILED(hres))
432 break;
434 prop->type = PROP_JSVAL;
435 prop->u.val = jsval_obj(obj);
437 jsdisp_addref(obj);
438 *r = jsval_obj(obj);
440 break;
441 case PROP_PROTREF:
442 hres = prop_get(This->prototype, This->prototype->props+prop->u.ref, dp, r, caller);
443 break;
444 case PROP_JSVAL:
445 hres = jsval_copy(prop->u.val, r);
446 break;
447 case PROP_IDX:
448 hres = This->builtin_info->idx_get(This, prop->u.idx, r);
449 break;
450 default:
451 ERR("type %d\n", prop->type);
452 return E_FAIL;
455 if(FAILED(hres)) {
456 TRACE("fail %08x\n", hres);
457 return hres;
460 TRACE("%s ret %s\n", debugstr_w(prop->name), debugstr_jsval(*r));
461 return hres;
464 static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val, IServiceProvider *caller)
466 HRESULT hres;
468 if(prop->flags & PROPF_CONST)
469 return S_OK;
471 switch(prop->type) {
472 case PROP_BUILTIN:
473 if(prop->u.p->setter)
474 return prop->u.p->setter(This->ctx, This, val);
476 if(prop->u.p->setter) {
477 FIXME("getter with no setter\n");
478 return E_FAIL;
480 /* fall through */
481 case PROP_PROTREF:
482 prop->type = PROP_JSVAL;
483 prop->flags = PROPF_ENUM;
484 prop->u.val = jsval_undefined();
485 break;
486 case PROP_JSVAL:
487 jsval_release(prop->u.val);
488 break;
489 case PROP_IDX:
490 return This->builtin_info->idx_put(This, prop->u.idx, val);
491 default:
492 ERR("type %d\n", prop->type);
493 return E_FAIL;
496 TRACE("%s = %s\n", debugstr_w(prop->name), debugstr_jsval(val));
498 hres = jsval_copy(val, &prop->u.val);
499 if(FAILED(hres)) {
500 prop->u.val = jsval_undefined();
501 return hres;
504 if(This->builtin_info->on_put)
505 This->builtin_info->on_put(This, prop->name);
507 return S_OK;
510 HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
512 TRACE("%p %s\n", jsthis, debugstr_jsval(value));
513 return S_OK;
516 static HRESULT fill_protrefs(jsdisp_t *This)
518 dispex_prop_t *iter, *prop;
519 HRESULT hres;
521 if(!This->prototype)
522 return S_OK;
524 fill_protrefs(This->prototype);
526 for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) {
527 if(!iter->name)
528 continue;
529 hres = find_prop_name(This, iter->hash, iter->name, &prop);
530 if(FAILED(hres))
531 return hres;
532 if(!prop || prop->type==PROP_DELETED) {
533 if(prop) {
534 prop->type = PROP_PROTREF;
535 prop->flags = 0;
536 prop->u.ref = iter - This->prototype->props;
537 }else {
538 prop = alloc_protref(This, iter->name, iter - This->prototype->props);
539 if(!prop)
540 return E_OUTOFMEMORY;
545 return S_OK;
548 static inline jsdisp_t *impl_from_IDispatchEx(IDispatchEx *iface)
550 return CONTAINING_RECORD(iface, jsdisp_t, IDispatchEx_iface);
553 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
555 jsdisp_t *This = impl_from_IDispatchEx(iface);
557 if(IsEqualGUID(&IID_IUnknown, riid)) {
558 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
559 *ppv = &This->IDispatchEx_iface;
560 }else if(IsEqualGUID(&IID_IDispatch, riid)) {
561 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
562 *ppv = &This->IDispatchEx_iface;
563 }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
564 TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
565 *ppv = &This->IDispatchEx_iface;
566 }else if(IsEqualGUID(&IID_IDispatchJS, riid)) {
567 TRACE("(%p)->(IID_IDispatchJS %p)\n", This, ppv);
568 jsdisp_addref(This);
569 *ppv = This;
570 return S_OK;
571 }else {
572 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
573 *ppv = NULL;
574 return E_NOINTERFACE;
577 jsdisp_addref(This);
578 return S_OK;
581 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
583 jsdisp_t *This = impl_from_IDispatchEx(iface);
584 jsdisp_addref(This);
585 return This->ref;
588 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
590 jsdisp_t *This = impl_from_IDispatchEx(iface);
591 ULONG ref = --This->ref;
592 if(!ref)
593 jsdisp_free(This);
594 return ref;
597 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
599 jsdisp_t *This = impl_from_IDispatchEx(iface);
601 TRACE("(%p)->(%p)\n", This, pctinfo);
603 *pctinfo = 1;
604 return S_OK;
607 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid,
608 ITypeInfo **ppTInfo)
610 jsdisp_t *This = impl_from_IDispatchEx(iface);
611 FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
612 return E_NOTIMPL;
615 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
616 LPOLESTR *rgszNames, UINT cNames, LCID lcid,
617 DISPID *rgDispId)
619 jsdisp_t *This = impl_from_IDispatchEx(iface);
620 UINT i;
621 HRESULT hres;
623 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
624 lcid, rgDispId);
626 for(i=0; i < cNames; i++) {
627 hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[i], 0, rgDispId+i);
628 if(FAILED(hres))
629 return hres;
632 return S_OK;
635 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
636 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
637 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
639 jsdisp_t *This = impl_from_IDispatchEx(iface);
641 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
642 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
644 return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags,
645 pDispParams, pVarResult, pExcepInfo, NULL);
648 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
650 jsdisp_t *This = impl_from_IDispatchEx(iface);
652 TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
654 if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) {
655 FIXME("Unsupported grfdex %x\n", grfdex);
656 return E_NOTIMPL;
659 return jsdisp_get_id(This, bstrName, grfdex, pid);
662 static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
663 VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
665 jsdisp_t *This = impl_from_IDispatchEx(iface);
666 dispex_prop_t *prop;
667 HRESULT hres;
669 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
671 if(pvarRes)
672 V_VT(pvarRes) = VT_EMPTY;
674 prop = get_prop(This, id);
675 if(!prop || prop->type == PROP_DELETED) {
676 TRACE("invalid id\n");
677 return DISP_E_MEMBERNOTFOUND;
680 clear_ei(This->ctx);
682 switch(wFlags) {
683 case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
684 wFlags = DISPATCH_METHOD;
685 /* fall through */
686 case DISPATCH_METHOD:
687 case DISPATCH_CONSTRUCT: {
688 jsval_t *argv, buf[6], r;
689 unsigned argc;
691 hres = convert_params(pdp, buf, &argc, &argv);
692 if(FAILED(hres))
693 return hres;
695 hres = invoke_prop_func(This, get_this(pdp), prop, wFlags, argc, argv, pvarRes ? &r : NULL, pspCaller);
696 if(argv != buf)
697 heap_free(argv);
698 if(SUCCEEDED(hres) && pvarRes) {
699 hres = jsval_to_variant(r, pvarRes);
700 jsval_release(r);
702 break;
704 case DISPATCH_PROPERTYGET: {
705 jsval_t r;
707 hres = prop_get(This, prop, pdp, &r, pspCaller);
708 if(SUCCEEDED(hres)) {
709 hres = jsval_to_variant(r, pvarRes);
710 jsval_release(r);
712 break;
714 case DISPATCH_PROPERTYPUT: {
715 jsval_t val;
716 DWORD i;
718 for(i=0; i < pdp->cNamedArgs; i++) {
719 if(pdp->rgdispidNamedArgs[i] == DISPID_PROPERTYPUT)
720 break;
723 if(i == pdp->cNamedArgs) {
724 TRACE("no value to set\n");
725 return DISP_E_PARAMNOTOPTIONAL;
728 hres = variant_to_jsval(pdp->rgvarg+i, &val);
729 if(FAILED(hres))
730 return hres;
732 hres = prop_put(This, prop, val, pspCaller);
733 jsval_release(val);
734 break;
736 default:
737 FIXME("Unimplemented flags %x\n", wFlags);
738 return E_INVALIDARG;
741 if(pei)
742 *pei = This->ctx->ei.ei;
743 return hres;
746 static HRESULT delete_prop(dispex_prop_t *prop, BOOL *ret)
748 if(prop->flags & PROPF_DONTDELETE) {
749 *ret = FALSE;
750 return S_OK;
753 *ret = TRUE; /* FIXME: not exactly right */
755 if(prop->type == PROP_JSVAL) {
756 jsval_release(prop->u.val);
757 prop->type = PROP_DELETED;
759 return S_OK;
762 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
764 jsdisp_t *This = impl_from_IDispatchEx(iface);
765 dispex_prop_t *prop;
766 BOOL b;
767 HRESULT hres;
769 TRACE("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex);
771 if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK))
772 FIXME("Unsupported grfdex %x\n", grfdex);
774 hres = find_prop_name(This, string_hash(bstrName), bstrName, &prop);
775 if(FAILED(hres))
776 return hres;
777 if(!prop) {
778 TRACE("not found\n");
779 return S_OK;
782 return delete_prop(prop, &b);
785 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
787 jsdisp_t *This = impl_from_IDispatchEx(iface);
788 dispex_prop_t *prop;
789 BOOL b;
791 TRACE("(%p)->(%x)\n", This, id);
793 prop = get_prop(This, id);
794 if(!prop) {
795 WARN("invalid id\n");
796 return DISP_E_MEMBERNOTFOUND;
799 return delete_prop(prop, &b);
802 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
804 jsdisp_t *This = impl_from_IDispatchEx(iface);
805 FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex);
806 return E_NOTIMPL;
809 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
811 jsdisp_t *This = impl_from_IDispatchEx(iface);
812 dispex_prop_t *prop;
814 TRACE("(%p)->(%x %p)\n", This, id, pbstrName);
816 prop = get_prop(This, id);
817 if(!prop || !prop->name || prop->type == PROP_DELETED)
818 return DISP_E_MEMBERNOTFOUND;
820 *pbstrName = SysAllocString(prop->name);
821 if(!*pbstrName)
822 return E_OUTOFMEMORY;
824 return S_OK;
827 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
829 jsdisp_t *This = impl_from_IDispatchEx(iface);
830 dispex_prop_t *iter;
831 HRESULT hres;
833 TRACE("(%p)->(%x %x %p)\n", This, grfdex, id, pid);
835 if(id == DISPID_STARTENUM) {
836 hres = fill_protrefs(This);
837 if(FAILED(hres))
838 return hres;
841 if(id+1>=0 && id+1<This->prop_cnt) {
842 iter = &This->props[id+1];
843 }else {
844 *pid = DISPID_STARTENUM;
845 return S_FALSE;
848 while(iter < This->props + This->prop_cnt) {
849 if(iter->name && (get_flags(This, iter) & PROPF_ENUM) && iter->type!=PROP_DELETED) {
850 *pid = prop_to_id(This, iter);
851 return S_OK;
853 iter++;
856 *pid = DISPID_STARTENUM;
857 return S_FALSE;
860 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
862 jsdisp_t *This = impl_from_IDispatchEx(iface);
863 FIXME("(%p)->(%p)\n", This, ppunk);
864 return E_NOTIMPL;
867 static IDispatchExVtbl DispatchExVtbl = {
868 DispatchEx_QueryInterface,
869 DispatchEx_AddRef,
870 DispatchEx_Release,
871 DispatchEx_GetTypeInfoCount,
872 DispatchEx_GetTypeInfo,
873 DispatchEx_GetIDsOfNames,
874 DispatchEx_Invoke,
875 DispatchEx_GetDispID,
876 DispatchEx_InvokeEx,
877 DispatchEx_DeleteMemberByName,
878 DispatchEx_DeleteMemberByDispID,
879 DispatchEx_GetMemberProperties,
880 DispatchEx_GetMemberName,
881 DispatchEx_GetNextDispID,
882 DispatchEx_GetNameSpaceParent
885 jsdisp_t *as_jsdisp(IDispatch *disp)
887 assert(disp->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl);
888 return impl_from_IDispatchEx((IDispatchEx*)disp);
891 jsdisp_t *to_jsdisp(IDispatch *disp)
893 return disp->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl ? impl_from_IDispatchEx((IDispatchEx*)disp) : NULL;
896 HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype)
898 TRACE("%p (%p)\n", dispex, prototype);
900 dispex->IDispatchEx_iface.lpVtbl = &DispatchExVtbl;
901 dispex->ref = 1;
902 dispex->builtin_info = builtin_info;
904 dispex->props = heap_alloc_zero(sizeof(dispex_prop_t)*(dispex->buf_size=4));
905 if(!dispex->props)
906 return E_OUTOFMEMORY;
908 dispex->prototype = prototype;
909 if(prototype)
910 jsdisp_addref(prototype);
912 dispex->prop_cnt = 1;
913 if(builtin_info->value_prop.invoke || builtin_info->value_prop.getter) {
914 dispex->props[0].type = PROP_BUILTIN;
915 dispex->props[0].u.p = &builtin_info->value_prop;
916 }else {
917 dispex->props[0].type = PROP_DELETED;
920 script_addref(ctx);
921 dispex->ctx = ctx;
923 return S_OK;
926 static const builtin_info_t dispex_info = {
927 JSCLASS_NONE,
928 {NULL, NULL, 0},
929 0, NULL,
930 NULL,
931 NULL
934 HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype, jsdisp_t **dispex)
936 jsdisp_t *ret;
937 HRESULT hres;
939 ret = heap_alloc_zero(sizeof(jsdisp_t));
940 if(!ret)
941 return E_OUTOFMEMORY;
943 hres = init_dispex(ret, ctx, builtin_info ? builtin_info : &dispex_info, prototype);
944 if(FAILED(hres)) {
945 heap_free(ret);
946 return hres;
949 *dispex = ret;
950 return S_OK;
953 void jsdisp_free(jsdisp_t *obj)
955 dispex_prop_t *prop;
957 TRACE("(%p)\n", obj);
959 for(prop = obj->props; prop < obj->props+obj->prop_cnt; prop++) {
960 if(prop->type == PROP_JSVAL)
961 jsval_release(prop->u.val);
962 heap_free(prop->name);
964 heap_free(obj->props);
965 script_release(obj->ctx);
966 if(obj->prototype)
967 jsdisp_release(obj->prototype);
969 if(obj->builtin_info->destructor)
970 obj->builtin_info->destructor(obj);
971 else
972 heap_free(obj);
975 #ifdef TRACE_REFCNT
977 jsdisp_t *jsdisp_addref(jsdisp_t *jsdisp)
979 ULONG ref = ++jsdisp->ref;
980 TRACE("(%p) ref=%d\n", jsdisp, ref);
981 return jsdisp;
984 void jsdisp_release(jsdisp_t *jsdisp)
986 ULONG ref = --jsdisp->ref;
988 TRACE("(%p) ref=%d\n", jsdisp, ref);
990 if(!ref)
991 jsdisp_free(jsdisp);
994 #endif
996 HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *constr)
998 jsdisp_t *prot = NULL;
999 dispex_prop_t *prop;
1000 HRESULT hres;
1002 static const WCHAR prototypeW[] = {'p','r','o','t','o','t','y','p','e',0};
1004 hres = find_prop_name_prot(constr, string_hash(prototypeW), prototypeW, &prop);
1005 if(SUCCEEDED(hres) && prop && prop->type!=PROP_DELETED) {
1006 jsval_t val;
1008 hres = prop_get(constr, prop, NULL, &val, NULL);
1009 if(FAILED(hres)) {
1010 ERR("Could not get prototype\n");
1011 return hres;
1014 if(is_object_instance(val))
1015 prot = iface_to_jsdisp((IUnknown*)get_object(val));
1016 jsval_release(val);
1019 hres = init_dispex(dispex, ctx, builtin_info, prot);
1021 if(prot)
1022 jsdisp_release(prot);
1023 return hres;
1026 jsdisp_t *iface_to_jsdisp(IUnknown *iface)
1028 jsdisp_t *ret;
1029 HRESULT hres;
1031 hres = IUnknown_QueryInterface(iface, &IID_IDispatchJS, (void**)&ret);
1032 if(FAILED(hres))
1033 return NULL;
1035 return ret;
1038 HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID *id)
1040 dispex_prop_t *prop;
1041 HRESULT hres;
1043 if(flags & fdexNameEnsure)
1044 hres = ensure_prop_name(jsdisp, name, TRUE, PROPF_ENUM, &prop);
1045 else
1046 hres = find_prop_name_prot(jsdisp, string_hash(name), name, &prop);
1047 if(FAILED(hres))
1048 return hres;
1050 if(prop && prop->type!=PROP_DELETED) {
1051 *id = prop_to_id(jsdisp, prop);
1052 return S_OK;
1055 TRACE("not found %s\n", debugstr_w(name));
1056 return DISP_E_UNKNOWNNAME;
1059 HRESULT jsdisp_call_value(jsdisp_t *jsfunc, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1061 HRESULT hres;
1063 assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT)));
1065 if(is_class(jsfunc, JSCLASS_FUNCTION)) {
1066 hres = Function_invoke(jsfunc, jsthis, flags, argc, argv, r);
1067 }else {
1068 vdisp_t vdisp;
1070 if(!jsfunc->builtin_info->value_prop.invoke) {
1071 WARN("Not a function\n");
1072 return throw_type_error(jsfunc->ctx, JS_E_FUNCTION_EXPECTED, NULL);
1075 set_disp(&vdisp, jsthis);
1076 hres = jsfunc->builtin_info->value_prop.invoke(jsfunc->ctx, &vdisp, flags, argc, argv, r);
1077 vdisp_release(&vdisp);
1079 return hres;
1082 HRESULT jsdisp_call(jsdisp_t *disp, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1084 dispex_prop_t *prop;
1086 prop = get_prop(disp, id);
1087 if(!prop)
1088 return DISP_E_MEMBERNOTFOUND;
1090 return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, NULL);
1093 HRESULT jsdisp_call_name(jsdisp_t *disp, const WCHAR *name, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1095 dispex_prop_t *prop;
1096 HRESULT hres;
1098 hres = find_prop_name_prot(disp, string_hash(name), name, &prop);
1099 if(FAILED(hres))
1100 return hres;
1102 return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, NULL);
1105 HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *ret)
1107 IDispatchEx *dispex;
1108 jsdisp_t *jsdisp;
1109 VARIANT buf[6], retv;
1110 DISPPARAMS dp;
1111 unsigned i;
1112 HRESULT hres;
1114 jsdisp = iface_to_jsdisp((IUnknown*)disp);
1115 if(jsdisp) {
1116 if(flags & DISPATCH_PROPERTYPUT) {
1117 FIXME("disp_call(propput) on builtin object\n");
1118 return E_FAIL;
1121 hres = jsdisp_call(jsdisp, id, flags, argc, argv, ret);
1122 jsdisp_release(jsdisp);
1123 return hres;
1126 if(ret && argc)
1127 flags |= DISPATCH_PROPERTYGET;
1129 dp.cArgs = argc;
1131 if(flags & DISPATCH_PROPERTYPUT) {
1132 static DISPID propput_dispid = DISPID_PROPERTYPUT;
1134 dp.cNamedArgs = 1;
1135 dp.rgdispidNamedArgs = &propput_dispid;
1136 }else {
1137 dp.cNamedArgs = 0;
1138 dp.rgdispidNamedArgs = NULL;
1141 if(argc > 6) {
1142 dp.rgvarg = heap_alloc(argc*sizeof(VARIANT));
1143 if(!dp.rgvarg)
1144 return E_OUTOFMEMORY;
1145 }else {
1146 dp.rgvarg = buf;
1149 for(i=0; i<argc; i++) {
1150 hres = jsval_to_variant(argv[i], dp.rgvarg+argc-i-1);
1151 if(FAILED(hres)) {
1152 while(i--)
1153 VariantClear(dp.rgvarg+argc-i-1);
1154 if(dp.rgvarg != buf)
1155 heap_free(dp.rgvarg);
1156 return hres;
1160 V_VT(&retv) = VT_EMPTY;
1161 clear_ei(ctx);
1162 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1163 if(SUCCEEDED(hres)) {
1164 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, &dp, ret ? &retv : NULL, &ctx->ei.ei,
1165 &ctx->jscaller->IServiceProvider_iface);
1166 IDispatchEx_Release(dispex);
1167 }else {
1168 UINT err = 0;
1170 if(flags == DISPATCH_CONSTRUCT) {
1171 WARN("IDispatch cannot be constructor\n");
1172 return DISP_E_MEMBERNOTFOUND;
1175 TRACE("using IDispatch\n");
1176 hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, &dp, ret ? &retv : NULL, &ctx->ei.ei, &err);
1179 for(i=0; i<argc; i++)
1180 VariantClear(dp.rgvarg+argc-i-1);
1181 if(dp.rgvarg != buf)
1182 heap_free(dp.rgvarg);
1183 if(FAILED(hres))
1184 return hres;
1186 if(ret) {
1187 hres = variant_to_jsval(&retv, ret);
1188 VariantClear(&retv);
1190 return hres;
1193 HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1194 jsval_t *r)
1196 jsdisp_t *jsdisp;
1197 IDispatchEx *dispex;
1198 VARIANT buf[6], retv;
1199 DISPPARAMS dp;
1200 unsigned i;
1201 HRESULT hres;
1203 assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT)));
1205 jsdisp = iface_to_jsdisp((IUnknown*)disp);
1206 if(jsdisp) {
1207 hres = jsdisp_call_value(jsdisp, jsthis, flags, argc, argv, r);
1208 jsdisp_release(jsdisp);
1209 return hres;
1212 if(r && argc && flags == DISPATCH_METHOD)
1213 flags |= DISPATCH_PROPERTYGET;
1215 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1216 if(FAILED(hres)) {
1217 TRACE("using IDispatch\n");
1218 dispex = NULL;
1219 jsthis = NULL;
1222 if(jsthis) {
1223 static DISPID this_id = DISPID_THIS;
1225 dp.cArgs = argc+1;
1226 dp.cNamedArgs = 1;
1227 dp.rgdispidNamedArgs = &this_id;
1228 }else {
1229 dp.cArgs = argc;
1230 dp.cNamedArgs = 0;
1231 dp.rgdispidNamedArgs = NULL;
1234 if(dp.cArgs > sizeof(buf)/sizeof(*buf)) {
1235 dp.rgvarg = heap_alloc(dp.cArgs*sizeof(VARIANT));
1236 if(!dp.rgvarg) {
1237 if(dispex)
1238 IDispatchEx_Release(dispex);
1239 return E_OUTOFMEMORY;
1241 }else {
1242 dp.rgvarg = buf;
1245 for(i=0; i<argc; i++) {
1246 hres = jsval_to_variant(argv[i], dp.rgvarg+dp.cArgs-i-1);
1247 if(FAILED(hres)) {
1248 while(i--)
1249 VariantClear(dp.rgvarg+dp.cArgs-i-1);
1250 if(dp.rgvarg != buf)
1251 heap_free(dp.rgvarg);
1252 if(dispex)
1253 IDispatchEx_Release(dispex);
1254 return hres;
1257 if(jsthis) {
1258 V_VT(dp.rgvarg) = VT_DISPATCH;
1259 V_DISPATCH(dp.rgvarg) = jsthis;
1262 V_VT(&retv) = VT_EMPTY;
1263 clear_ei(ctx);
1264 if(dispex) {
1265 hres = IDispatchEx_InvokeEx(dispex, DISPID_VALUE, ctx->lcid, flags, &dp, r ? &retv : NULL, &ctx->ei.ei,
1266 &ctx->jscaller->IServiceProvider_iface);
1267 IDispatchEx_Release(dispex);
1268 }else {
1269 UINT err = 0;
1271 if(flags == DISPATCH_CONSTRUCT) {
1272 WARN("IDispatch cannot be constructor\n");
1273 return DISP_E_MEMBERNOTFOUND;
1276 hres = IDispatch_Invoke(disp, DISPID_VALUE, &IID_NULL, ctx->lcid, flags, &dp, r ? &retv : NULL, &ctx->ei.ei, &err);
1279 for(i=0; i<argc; i++)
1280 VariantClear(dp.rgvarg+dp.cArgs-i-1);
1281 if(dp.rgvarg != buf)
1282 heap_free(dp.rgvarg);
1283 if(FAILED(hres))
1284 return hres;
1286 if(!r)
1287 return S_OK;
1289 hres = variant_to_jsval(&retv, r);
1290 VariantClear(&retv);
1291 return hres;
1294 HRESULT jsdisp_propput(jsdisp_t *obj, const WCHAR *name, DWORD flags, jsval_t val)
1296 dispex_prop_t *prop;
1297 HRESULT hres;
1299 hres = ensure_prop_name(obj, name, FALSE, flags, &prop);
1300 if(FAILED(hres))
1301 return hres;
1303 return prop_put(obj, prop, val, NULL);
1306 HRESULT jsdisp_propput_name(jsdisp_t *obj, const WCHAR *name, jsval_t val)
1308 return jsdisp_propput(obj, name, PROPF_ENUM, val);
1311 HRESULT jsdisp_propput_const(jsdisp_t *obj, const WCHAR *name, jsval_t val)
1313 dispex_prop_t *prop;
1314 HRESULT hres;
1316 hres = ensure_prop_name(obj, name, FALSE, PROPF_CONST, &prop);
1317 if(FAILED(hres))
1318 return hres;
1320 return jsval_copy(val, &prop->u.val);
1323 HRESULT jsdisp_propput_dontenum(jsdisp_t *obj, const WCHAR *name, jsval_t val)
1325 return jsdisp_propput(obj, name, 0, val);
1328 HRESULT jsdisp_propput_idx(jsdisp_t *obj, DWORD idx, jsval_t val)
1330 WCHAR buf[12];
1332 static const WCHAR formatW[] = {'%','d',0};
1334 sprintfW(buf, formatW, idx);
1335 return jsdisp_propput_name(obj, buf, val);
1338 HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val)
1340 jsdisp_t *jsdisp;
1341 HRESULT hres;
1343 jsdisp = iface_to_jsdisp((IUnknown*)disp);
1344 if(jsdisp) {
1345 dispex_prop_t *prop;
1347 prop = get_prop(jsdisp, id);
1348 if(prop)
1349 hres = prop_put(jsdisp, prop, val, NULL);
1350 else
1351 hres = DISP_E_MEMBERNOTFOUND;
1353 jsdisp_release(jsdisp);
1354 }else {
1355 DISPID dispid = DISPID_PROPERTYPUT;
1356 DWORD flags = DISPATCH_PROPERTYPUT;
1357 VARIANT var;
1358 DISPPARAMS dp = {&var, &dispid, 1, 1};
1359 IDispatchEx *dispex;
1361 hres = jsval_to_variant(val, &var);
1362 if(FAILED(hres))
1363 return hres;
1365 if(V_VT(&var) == VT_DISPATCH)
1366 flags |= DISPATCH_PROPERTYPUTREF;
1368 clear_ei(ctx);
1369 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1370 if(SUCCEEDED(hres)) {
1371 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, &dp, NULL, &ctx->ei.ei,
1372 &ctx->jscaller->IServiceProvider_iface);
1373 IDispatchEx_Release(dispex);
1374 }else {
1375 ULONG err = 0;
1377 TRACE("using IDispatch\n");
1378 hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, &dp, NULL, &ctx->ei.ei, &err);
1381 VariantClear(&var);
1384 return hres;
1387 HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val)
1389 DISPPARAMS dp = {NULL, NULL, 0, 0};
1390 dispex_prop_t *prop;
1391 HRESULT hres;
1393 hres = find_prop_name_prot(obj, string_hash(name), name, &prop);
1394 if(FAILED(hres))
1395 return hres;
1397 if(!prop || prop->type==PROP_DELETED) {
1398 *val = jsval_undefined();
1399 return S_OK;
1402 return prop_get(obj, prop, &dp, val, NULL);
1405 HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r)
1407 WCHAR name[12];
1408 DISPPARAMS dp = {NULL, NULL, 0, 0};
1409 dispex_prop_t *prop;
1410 HRESULT hres;
1412 static const WCHAR formatW[] = {'%','d',0};
1414 sprintfW(name, formatW, idx);
1416 hres = find_prop_name_prot(obj, string_hash(name), name, &prop);
1417 if(FAILED(hres))
1418 return hres;
1420 if(!prop || prop->type==PROP_DELETED) {
1421 *r = jsval_undefined();
1422 return DISP_E_UNKNOWNNAME;
1425 return prop_get(obj, prop, &dp, r, NULL);
1428 HRESULT jsdisp_propget(jsdisp_t *jsdisp, DISPID id, jsval_t *val)
1430 DISPPARAMS dp = {NULL,NULL,0,0};
1431 dispex_prop_t *prop;
1433 prop = get_prop(jsdisp, id);
1434 if(!prop)
1435 return DISP_E_MEMBERNOTFOUND;
1437 return prop_get(jsdisp, prop, &dp, val, NULL);
1440 HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t *val)
1442 DISPPARAMS dp = {NULL,NULL,0,0};
1443 IDispatchEx *dispex;
1444 jsdisp_t *jsdisp;
1445 VARIANT var;
1446 HRESULT hres;
1448 jsdisp = iface_to_jsdisp((IUnknown*)disp);
1449 if(jsdisp) {
1450 hres = jsdisp_propget(jsdisp, id, val);
1451 jsdisp_release(jsdisp);
1452 return hres;
1455 V_VT(&var) = VT_EMPTY;
1456 clear_ei(ctx);
1457 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1458 if(SUCCEEDED(hres)) {
1459 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, INVOKE_PROPERTYGET, &dp, &var, &ctx->ei.ei,
1460 &ctx->jscaller->IServiceProvider_iface);
1461 IDispatchEx_Release(dispex);
1462 }else {
1463 ULONG err = 0;
1465 TRACE("using IDispatch\n");
1466 hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, INVOKE_PROPERTYGET, &dp, &var, &ctx->ei.ei, &err);
1468 if(FAILED(hres))
1469 return hres;
1471 hres = variant_to_jsval(&var, val);
1472 VariantClear(&var);
1473 return hres;
1476 HRESULT jsdisp_delete_idx(jsdisp_t *obj, DWORD idx)
1478 static const WCHAR formatW[] = {'%','d',0};
1479 WCHAR buf[12];
1480 dispex_prop_t *prop;
1481 BOOL b;
1482 HRESULT hres;
1484 sprintfW(buf, formatW, idx);
1486 hres = find_prop_name(obj, string_hash(buf), buf, &prop);
1487 if(FAILED(hres) || !prop)
1488 return hres;
1490 return delete_prop(prop, &b);
1493 HRESULT disp_delete(IDispatch *disp, DISPID id, BOOL *ret)
1495 IDispatchEx *dispex;
1496 jsdisp_t *jsdisp;
1497 HRESULT hres;
1499 jsdisp = iface_to_jsdisp((IUnknown*)disp);
1500 if(jsdisp) {
1501 dispex_prop_t *prop;
1503 prop = get_prop(jsdisp, id);
1504 if(prop)
1505 hres = delete_prop(prop, ret);
1506 else
1507 hres = DISP_E_MEMBERNOTFOUND;
1509 jsdisp_release(jsdisp);
1510 return hres;
1513 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1514 if(FAILED(hres)) {
1515 *ret = FALSE;
1516 return S_OK;
1519 hres = IDispatchEx_DeleteMemberByDispID(dispex, id);
1520 IDispatchEx_Release(dispex);
1521 if(FAILED(hres))
1522 return hres;
1524 *ret = hres == S_OK;
1525 return S_OK;
1528 HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL *ret)
1530 IDispatchEx *dispex;
1531 jsdisp_t *jsdisp;
1532 BSTR bstr;
1533 HRESULT hres;
1535 jsdisp = iface_to_jsdisp((IUnknown*)disp);
1536 if(jsdisp) {
1537 dispex_prop_t *prop;
1538 const WCHAR *ptr;
1540 ptr = jsstr_flatten(name);
1541 if(!ptr) {
1542 jsdisp_release(jsdisp);
1543 return E_OUTOFMEMORY;
1546 hres = find_prop_name(jsdisp, string_hash(ptr), ptr, &prop);
1547 if(prop) {
1548 hres = delete_prop(prop, ret);
1549 }else {
1550 *ret = TRUE;
1551 hres = S_OK;
1554 jsdisp_release(jsdisp);
1555 return hres;
1558 bstr = SysAllocStringLen(NULL, jsstr_length(name));
1559 if(!bstr)
1560 return E_OUTOFMEMORY;
1561 jsstr_flush(name, bstr);
1563 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1564 if(SUCCEEDED(hres)) {
1565 hres = IDispatchEx_DeleteMemberByName(dispex, bstr, make_grfdex(ctx, fdexNameCaseSensitive));
1566 if(SUCCEEDED(hres))
1567 *ret = hres == S_OK;
1568 IDispatchEx_Release(dispex);
1569 }else {
1570 DISPID id;
1572 hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, &id);
1573 if(SUCCEEDED(hres)) {
1574 /* Property exists and we can't delete it from pure IDispatch interface, so return false. */
1575 *ret = FALSE;
1576 }else if(hres == DISP_E_UNKNOWNNAME) {
1577 /* Property doesn't exist, so nothing to delete */
1578 *ret = TRUE;
1579 hres = S_OK;
1583 SysFreeString(bstr);
1584 return hres;
1587 HRESULT jsdisp_is_own_prop(jsdisp_t *obj, const WCHAR *name, BOOL *ret)
1589 dispex_prop_t *prop;
1590 HRESULT hres;
1592 hres = find_prop_name(obj, string_hash(name), name, &prop);
1593 if(FAILED(hres))
1594 return hres;
1596 *ret = prop && (prop->type == PROP_JSVAL || prop->type == PROP_BUILTIN);
1597 return S_OK;
1600 HRESULT jsdisp_is_enumerable(jsdisp_t *obj, const WCHAR *name, BOOL *ret)
1602 dispex_prop_t *prop;
1603 HRESULT hres;
1605 hres = find_prop_name(obj, string_hash(name), name, &prop);
1606 if(FAILED(hres))
1607 return hres;
1609 *ret = prop && (prop->flags & PROPF_ENUM) && prop->type != PROP_PROTREF;
1610 return S_OK;