oleaut32/tests: Test more return values.
[wine.git] / dlls / jscript / dispex.c
blob40c02a064e206e71ced54528d40cfdec16d81631
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);
28 #define FDEX_VERSION_MASK 0xf0000000
29 #define GOLDEN_RATIO 0x9E3779B9U
31 typedef enum {
32 PROP_JSVAL,
33 PROP_BUILTIN,
34 PROP_PROTREF,
35 PROP_DELETED,
36 PROP_IDX
37 } prop_type_t;
39 struct _dispex_prop_t {
40 WCHAR *name;
41 unsigned hash;
42 prop_type_t type;
43 DWORD flags;
45 union {
46 jsval_t val;
47 const builtin_prop_t *p;
48 DWORD ref;
49 unsigned idx;
50 } u;
52 int bucket_head;
53 int bucket_next;
56 static inline DISPID prop_to_id(jsdisp_t *This, dispex_prop_t *prop)
58 return prop - This->props;
61 static inline dispex_prop_t *get_prop(jsdisp_t *This, DISPID id)
63 if(id < 0 || id >= This->prop_cnt || This->props[id].type == PROP_DELETED)
64 return NULL;
66 return This->props+id;
69 static DWORD get_flags(jsdisp_t *This, dispex_prop_t *prop)
71 if(prop->type == PROP_PROTREF) {
72 dispex_prop_t *parent = get_prop(This->prototype, prop->u.ref);
73 if(!parent) {
74 prop->type = PROP_DELETED;
75 return 0;
78 return get_flags(This->prototype, parent);
81 return prop->flags;
84 static const builtin_prop_t *find_builtin_prop(jsdisp_t *This, const WCHAR *name)
86 int min = 0, max, i, r;
88 max = This->builtin_info->props_cnt-1;
89 while(min <= max) {
90 i = (min+max)/2;
92 r = strcmpW(name, This->builtin_info->props[i].name);
93 if(!r)
94 return This->builtin_info->props + i;
96 if(r < 0)
97 max = i-1;
98 else
99 min = i+1;
102 return NULL;
105 static inline unsigned string_hash(const WCHAR *name)
107 unsigned h = 0;
108 for(; *name; name++)
109 h = (h>>(sizeof(unsigned)*8-4)) ^ (h<<4) ^ tolowerW(*name);
110 return h;
113 static inline unsigned get_props_idx(jsdisp_t *This, unsigned hash)
115 return (hash*GOLDEN_RATIO) & (This->buf_size-1);
118 static inline HRESULT resize_props(jsdisp_t *This)
120 dispex_prop_t *props;
121 int i, bucket;
123 if(This->buf_size != This->prop_cnt)
124 return S_FALSE;
126 props = heap_realloc(This->props, sizeof(dispex_prop_t)*This->buf_size*2);
127 if(!props)
128 return E_OUTOFMEMORY;
129 This->buf_size *= 2;
130 This->props = props;
132 for(i=0; i<This->buf_size; i++) {
133 This->props[i].bucket_head = 0;
134 This->props[i].bucket_next = 0;
137 for(i=1; i<This->prop_cnt; i++) {
138 props = This->props+i;
140 bucket = get_props_idx(This, props->hash);
141 props->bucket_next = This->props[bucket].bucket_head;
142 This->props[bucket].bucket_head = i;
145 return S_OK;
148 static inline dispex_prop_t* alloc_prop(jsdisp_t *This, const WCHAR *name, prop_type_t type, DWORD flags)
150 dispex_prop_t *prop;
151 unsigned bucket;
153 if(FAILED(resize_props(This)))
154 return NULL;
156 prop = &This->props[This->prop_cnt];
157 prop->name = heap_strdupW(name);
158 if(!prop->name)
159 return NULL;
160 prop->type = type;
161 prop->flags = flags;
162 prop->hash = string_hash(name);
164 bucket = get_props_idx(This, prop->hash);
165 prop->bucket_next = This->props[bucket].bucket_head;
166 This->props[bucket].bucket_head = This->prop_cnt++;
167 return prop;
170 static dispex_prop_t *alloc_protref(jsdisp_t *This, const WCHAR *name, DWORD ref)
172 dispex_prop_t *ret;
174 ret = alloc_prop(This, name, PROP_PROTREF, 0);
175 if(!ret)
176 return NULL;
178 ret->u.ref = ref;
179 return ret;
182 static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, dispex_prop_t **ret)
184 const builtin_prop_t *builtin;
185 unsigned bucket, pos, prev = 0;
186 dispex_prop_t *prop;
188 bucket = get_props_idx(This, hash);
189 pos = This->props[bucket].bucket_head;
190 while(pos != 0) {
191 if(!strcmpW(name, This->props[pos].name)) {
192 if(prev != 0) {
193 This->props[prev].bucket_next = This->props[pos].bucket_next;
194 This->props[pos].bucket_next = This->props[bucket].bucket_head;
195 This->props[bucket].bucket_head = pos;
198 *ret = &This->props[pos];
199 return S_OK;
202 prev = pos;
203 pos = This->props[pos].bucket_next;
206 builtin = find_builtin_prop(This, name);
207 if(builtin) {
208 prop = alloc_prop(This, name, PROP_BUILTIN, builtin->flags);
209 if(!prop)
210 return E_OUTOFMEMORY;
212 prop->u.p = builtin;
213 *ret = prop;
214 return S_OK;
217 if(This->builtin_info->idx_length) {
218 const WCHAR *ptr;
219 unsigned idx = 0;
221 for(ptr = name; isdigitW(*ptr) && idx < 0x10000; ptr++)
222 idx = idx*10 + (*ptr-'0');
223 if(!*ptr && idx < This->builtin_info->idx_length(This)) {
224 prop = alloc_prop(This, name, PROP_IDX, This->builtin_info->idx_put ? 0 : PROPF_CONST);
225 if(!prop)
226 return E_OUTOFMEMORY;
228 prop->u.idx = idx;
229 *ret = prop;
230 return S_OK;
234 *ret = NULL;
235 return S_OK;
238 static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *name, dispex_prop_t **ret)
240 dispex_prop_t *prop, *del=NULL;
241 HRESULT hres;
243 hres = find_prop_name(This, hash, name, &prop);
244 if(FAILED(hres))
245 return hres;
246 if(prop && prop->type==PROP_DELETED) {
247 del = prop;
248 } else if(prop) {
249 *ret = prop;
250 return S_OK;
253 if(This->prototype) {
254 hres = find_prop_name_prot(This->prototype, hash, name, &prop);
255 if(FAILED(hres))
256 return hres;
257 if(prop) {
258 if(del) {
259 del->type = PROP_PROTREF;
260 del->flags = 0;
261 del->u.ref = prop - This->prototype->props;
262 prop = del;
263 }else {
264 prop = alloc_protref(This, prop->name, prop - This->prototype->props);
265 if(!prop)
266 return E_OUTOFMEMORY;
269 *ret = prop;
270 return S_OK;
274 *ret = del;
275 return S_OK;
278 static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, BOOL search_prot, DWORD create_flags, dispex_prop_t **ret)
280 dispex_prop_t *prop;
281 HRESULT hres;
283 if(search_prot)
284 hres = find_prop_name_prot(This, string_hash(name), name, &prop);
285 else
286 hres = find_prop_name(This, string_hash(name), name, &prop);
287 if(SUCCEEDED(hres) && (!prop || prop->type == PROP_DELETED)) {
288 TRACE("creating prop %s flags %x\n", debugstr_w(name), create_flags);
290 if(prop) {
291 prop->type = PROP_JSVAL;
292 prop->flags = create_flags;
293 prop->u.val = jsval_undefined();
294 }else {
295 prop = alloc_prop(This, name, PROP_JSVAL, create_flags);
296 if(!prop)
297 return E_OUTOFMEMORY;
300 prop->u.val = jsval_undefined();
303 *ret = prop;
304 return hres;
307 static IDispatch *get_this(DISPPARAMS *dp)
309 DWORD i;
311 for(i=0; i < dp->cNamedArgs; i++) {
312 if(dp->rgdispidNamedArgs[i] == DISPID_THIS) {
313 if(V_VT(dp->rgvarg+i) == VT_DISPATCH)
314 return V_DISPATCH(dp->rgvarg+i);
316 WARN("This is not VT_DISPATCH\n");
317 return NULL;
321 TRACE("no this passed\n");
322 return NULL;
325 static HRESULT convert_params(const DISPPARAMS *dp, jsval_t *buf, unsigned *argc, jsval_t **ret)
327 jsval_t *argv;
328 unsigned cnt;
329 unsigned i;
330 HRESULT hres;
332 cnt = dp->cArgs - dp->cNamedArgs;
334 if(cnt > 6) {
335 argv = heap_alloc(cnt * sizeof(*argv));
336 if(!argv)
337 return E_OUTOFMEMORY;
338 }else {
339 argv = buf;
342 for(i = 0; i < cnt; i++) {
343 hres = variant_to_jsval(dp->rgvarg+dp->cArgs-i-1, argv+i);
344 if(FAILED(hres)) {
345 while(i--)
346 jsval_release(argv[i]);
347 if(argv != buf)
348 heap_free(argv);
349 return hres;
353 *argc = cnt;
354 *ret = argv;
355 return S_OK;
358 static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t *prop, WORD flags,
359 unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller)
361 HRESULT hres;
363 switch(prop->type) {
364 case PROP_BUILTIN: {
365 if(flags == DISPATCH_CONSTRUCT && (prop->flags & PROPF_METHOD)) {
366 WARN("%s is not a constructor\n", debugstr_w(prop->name));
367 return E_INVALIDARG;
370 if(prop->name || This->builtin_info->class != JSCLASS_FUNCTION) {
371 vdisp_t vthis;
373 if(This->builtin_info->class != JSCLASS_FUNCTION && prop->u.p->invoke != JSGlobal_eval)
374 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
375 if(jsthis)
376 set_disp(&vthis, jsthis);
377 else
378 set_jsdisp(&vthis, This);
379 hres = prop->u.p->invoke(This->ctx, &vthis, flags, argc, argv, r);
380 vdisp_release(&vthis);
381 }else {
382 /* Function object calls are special case */
383 hres = Function_invoke(This, jsthis, flags, argc, argv, r);
385 return hres;
387 case PROP_PROTREF:
388 return invoke_prop_func(This->prototype, jsthis, This->prototype->props+prop->u.ref,
389 flags, argc, argv, r, caller);
390 case PROP_JSVAL: {
391 if(!is_object_instance(prop->u.val)) {
392 FIXME("invoke %s\n", debugstr_jsval(prop->u.val));
393 return E_FAIL;
396 TRACE("call %s %p\n", debugstr_w(prop->name), get_object(prop->u.val));
398 return disp_call_value(This->ctx, get_object(prop->u.val), jsthis, flags, argc, argv, r);
400 case PROP_IDX:
401 FIXME("Invoking PROP_IDX not yet supported\n");
402 return E_NOTIMPL;
403 case PROP_DELETED:
404 assert(0);
407 assert(0);
408 return E_FAIL;
411 static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, DISPPARAMS *dp,
412 jsval_t *r, IServiceProvider *caller)
414 HRESULT hres;
416 switch(prop->type) {
417 case PROP_BUILTIN:
418 if(prop->u.p->getter) {
419 hres = prop->u.p->getter(This->ctx, This, r);
420 }else {
421 jsdisp_t *obj;
423 assert(prop->u.p->invoke != NULL);
424 hres = create_builtin_function(This->ctx, prop->u.p->invoke, prop->u.p->name, NULL,
425 prop->u.p->flags, NULL, &obj);
426 if(FAILED(hres))
427 break;
429 prop->type = PROP_JSVAL;
430 prop->u.val = jsval_obj(obj);
432 jsdisp_addref(obj);
433 *r = jsval_obj(obj);
435 break;
436 case PROP_PROTREF:
437 hres = prop_get(This->prototype, This->prototype->props+prop->u.ref, dp, r, caller);
438 break;
439 case PROP_JSVAL:
440 hres = jsval_copy(prop->u.val, r);
441 break;
442 case PROP_IDX:
443 hres = This->builtin_info->idx_get(This, prop->u.idx, r);
444 break;
445 default:
446 ERR("type %d\n", prop->type);
447 return E_FAIL;
450 if(FAILED(hres)) {
451 TRACE("fail %08x\n", hres);
452 return hres;
455 TRACE("%s ret %s\n", debugstr_w(prop->name), debugstr_jsval(*r));
456 return hres;
459 static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val, IServiceProvider *caller)
461 HRESULT hres;
463 if(prop->flags & PROPF_CONST)
464 return S_OK;
466 switch(prop->type) {
467 case PROP_BUILTIN:
468 if(prop->u.p->setter)
469 return prop->u.p->setter(This->ctx, This, val);
471 if(prop->u.p->setter) {
472 FIXME("getter with no setter\n");
473 return E_FAIL;
475 /* fall through */
476 case PROP_PROTREF:
477 prop->type = PROP_JSVAL;
478 prop->flags = PROPF_ENUM;
479 prop->u.val = jsval_undefined();
480 break;
481 case PROP_JSVAL:
482 jsval_release(prop->u.val);
483 break;
484 case PROP_IDX:
485 return This->builtin_info->idx_put(This, prop->u.idx, val);
486 default:
487 ERR("type %d\n", prop->type);
488 return E_FAIL;
491 TRACE("%s = %s\n", debugstr_w(prop->name), debugstr_jsval(val));
493 hres = jsval_copy(val, &prop->u.val);
494 if(FAILED(hres))
495 return hres;
497 if(This->builtin_info->on_put)
498 This->builtin_info->on_put(This, prop->name);
500 return S_OK;
503 HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
505 TRACE("%p %s\n", jsthis, debugstr_jsval(value));
506 return S_OK;
509 static HRESULT fill_protrefs(jsdisp_t *This)
511 dispex_prop_t *iter, *prop;
512 HRESULT hres;
514 if(!This->prototype)
515 return S_OK;
517 fill_protrefs(This->prototype);
519 for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) {
520 if(!iter->name)
521 continue;
522 hres = find_prop_name(This, iter->hash, iter->name, &prop);
523 if(FAILED(hres))
524 return hres;
525 if(!prop || prop->type==PROP_DELETED) {
526 if(prop) {
527 prop->type = PROP_PROTREF;
528 prop->flags = 0;
529 prop->u.ref = iter - This->prototype->props;
530 }else {
531 prop = alloc_protref(This, iter->name, iter - This->prototype->props);
532 if(!prop)
533 return E_OUTOFMEMORY;
538 return S_OK;
541 static inline jsdisp_t *impl_from_IDispatchEx(IDispatchEx *iface)
543 return CONTAINING_RECORD(iface, jsdisp_t, IDispatchEx_iface);
546 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
548 jsdisp_t *This = impl_from_IDispatchEx(iface);
550 if(IsEqualGUID(&IID_IUnknown, riid)) {
551 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
552 *ppv = &This->IDispatchEx_iface;
553 }else if(IsEqualGUID(&IID_IDispatch, riid)) {
554 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
555 *ppv = &This->IDispatchEx_iface;
556 }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
557 TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
558 *ppv = &This->IDispatchEx_iface;
559 }else {
560 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
561 *ppv = NULL;
562 return E_NOINTERFACE;
565 jsdisp_addref(This);
566 return S_OK;
569 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
571 jsdisp_t *This = impl_from_IDispatchEx(iface);
572 jsdisp_addref(This);
573 return This->ref;
576 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
578 jsdisp_t *This = impl_from_IDispatchEx(iface);
579 ULONG ref = --This->ref;
580 TRACE("(%p) ref=%d\n", This, ref);
581 if(!ref)
582 jsdisp_free(This);
583 return ref;
586 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
588 jsdisp_t *This = impl_from_IDispatchEx(iface);
590 TRACE("(%p)->(%p)\n", This, pctinfo);
592 *pctinfo = 1;
593 return S_OK;
596 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid,
597 ITypeInfo **ppTInfo)
599 jsdisp_t *This = impl_from_IDispatchEx(iface);
600 FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
601 return E_NOTIMPL;
604 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
605 LPOLESTR *rgszNames, UINT cNames, LCID lcid,
606 DISPID *rgDispId)
608 jsdisp_t *This = impl_from_IDispatchEx(iface);
609 UINT i;
610 HRESULT hres;
612 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
613 lcid, rgDispId);
615 for(i=0; i < cNames; i++) {
616 hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[i], 0, rgDispId+i);
617 if(FAILED(hres))
618 return hres;
621 return S_OK;
624 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
625 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
626 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
628 jsdisp_t *This = impl_from_IDispatchEx(iface);
630 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
631 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
633 return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags,
634 pDispParams, pVarResult, pExcepInfo, NULL);
637 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
639 jsdisp_t *This = impl_from_IDispatchEx(iface);
641 TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
643 if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) {
644 FIXME("Unsupported grfdex %x\n", grfdex);
645 return E_NOTIMPL;
648 return jsdisp_get_id(This, bstrName, grfdex, pid);
651 static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
652 VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
654 jsdisp_t *This = impl_from_IDispatchEx(iface);
655 dispex_prop_t *prop;
656 HRESULT hres;
658 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
660 if(pvarRes)
661 V_VT(pvarRes) = VT_EMPTY;
663 prop = get_prop(This, id);
664 if(!prop || prop->type == PROP_DELETED) {
665 TRACE("invalid id\n");
666 return DISP_E_MEMBERNOTFOUND;
669 clear_ei(This->ctx);
671 switch(wFlags) {
672 case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
673 wFlags = DISPATCH_METHOD;
674 /* fall through */
675 case DISPATCH_METHOD:
676 case DISPATCH_CONSTRUCT: {
677 jsval_t *argv, buf[6], r;
678 unsigned argc;
680 hres = convert_params(pdp, buf, &argc, &argv);
681 if(FAILED(hres))
682 return hres;
684 hres = invoke_prop_func(This, get_this(pdp), prop, wFlags, argc, argv, pvarRes ? &r : NULL, pspCaller);
685 if(argv != buf)
686 heap_free(argv);
687 if(SUCCEEDED(hres) && pvarRes) {
688 hres = jsval_to_variant(r, pvarRes);
689 jsval_release(r);
691 break;
693 case DISPATCH_PROPERTYGET: {
694 jsval_t r;
696 hres = prop_get(This, prop, pdp, &r, pspCaller);
697 if(SUCCEEDED(hres)) {
698 hres = jsval_to_variant(r, pvarRes);
699 jsval_release(r);
701 break;
703 case DISPATCH_PROPERTYPUT: {
704 jsval_t val;
705 DWORD i;
707 for(i=0; i < pdp->cNamedArgs; i++) {
708 if(pdp->rgdispidNamedArgs[i] == DISPID_PROPERTYPUT)
709 break;
712 if(i == pdp->cNamedArgs) {
713 TRACE("no value to set\n");
714 return DISP_E_PARAMNOTOPTIONAL;
717 hres = variant_to_jsval(pdp->rgvarg+i, &val);
718 if(FAILED(hres))
719 return hres;
721 hres = prop_put(This, prop, val, pspCaller);
722 jsval_release(val);
723 break;
725 default:
726 FIXME("Unimplemented flags %x\n", wFlags);
727 return E_INVALIDARG;
730 if(pei)
731 *pei = This->ctx->ei.ei;
732 return hres;
735 static HRESULT delete_prop(dispex_prop_t *prop, BOOL *ret)
737 if(prop->flags & PROPF_DONTDELETE) {
738 *ret = FALSE;
739 return S_OK;
742 *ret = TRUE; /* FIXME: not exactly right */
744 if(prop->type == PROP_JSVAL) {
745 jsval_release(prop->u.val);
746 prop->type = PROP_DELETED;
748 return S_OK;
751 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
753 jsdisp_t *This = impl_from_IDispatchEx(iface);
754 dispex_prop_t *prop;
755 BOOL b;
756 HRESULT hres;
758 TRACE("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex);
760 if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK))
761 FIXME("Unsupported grfdex %x\n", grfdex);
763 hres = find_prop_name(This, string_hash(bstrName), bstrName, &prop);
764 if(FAILED(hres))
765 return hres;
766 if(!prop) {
767 TRACE("not found\n");
768 return S_OK;
771 return delete_prop(prop, &b);
774 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
776 jsdisp_t *This = impl_from_IDispatchEx(iface);
777 dispex_prop_t *prop;
778 BOOL b;
780 TRACE("(%p)->(%x)\n", This, id);
782 prop = get_prop(This, id);
783 if(!prop) {
784 WARN("invalid id\n");
785 return DISP_E_MEMBERNOTFOUND;
788 return delete_prop(prop, &b);
791 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
793 jsdisp_t *This = impl_from_IDispatchEx(iface);
794 FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex);
795 return E_NOTIMPL;
798 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
800 jsdisp_t *This = impl_from_IDispatchEx(iface);
801 dispex_prop_t *prop;
803 TRACE("(%p)->(%x %p)\n", This, id, pbstrName);
805 prop = get_prop(This, id);
806 if(!prop || !prop->name || prop->type == PROP_DELETED)
807 return DISP_E_MEMBERNOTFOUND;
809 *pbstrName = SysAllocString(prop->name);
810 if(!*pbstrName)
811 return E_OUTOFMEMORY;
813 return S_OK;
816 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
818 jsdisp_t *This = impl_from_IDispatchEx(iface);
819 dispex_prop_t *iter;
820 HRESULT hres;
822 TRACE("(%p)->(%x %x %p)\n", This, grfdex, id, pid);
824 if(id == DISPID_STARTENUM) {
825 hres = fill_protrefs(This);
826 if(FAILED(hres))
827 return hres;
830 if(id+1>=0 && id+1<This->prop_cnt) {
831 iter = &This->props[id+1];
832 }else {
833 *pid = DISPID_STARTENUM;
834 return S_FALSE;
837 while(iter < This->props + This->prop_cnt) {
838 if(iter->name && (get_flags(This, iter) & PROPF_ENUM) && iter->type!=PROP_DELETED) {
839 *pid = prop_to_id(This, iter);
840 return S_OK;
842 iter++;
845 *pid = DISPID_STARTENUM;
846 return S_FALSE;
849 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
851 jsdisp_t *This = impl_from_IDispatchEx(iface);
852 FIXME("(%p)->(%p)\n", This, ppunk);
853 return E_NOTIMPL;
856 static IDispatchExVtbl DispatchExVtbl = {
857 DispatchEx_QueryInterface,
858 DispatchEx_AddRef,
859 DispatchEx_Release,
860 DispatchEx_GetTypeInfoCount,
861 DispatchEx_GetTypeInfo,
862 DispatchEx_GetIDsOfNames,
863 DispatchEx_Invoke,
864 DispatchEx_GetDispID,
865 DispatchEx_InvokeEx,
866 DispatchEx_DeleteMemberByName,
867 DispatchEx_DeleteMemberByDispID,
868 DispatchEx_GetMemberProperties,
869 DispatchEx_GetMemberName,
870 DispatchEx_GetNextDispID,
871 DispatchEx_GetNameSpaceParent
874 jsdisp_t *as_jsdisp(IDispatch *disp)
876 assert(disp->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl);
877 return impl_from_IDispatchEx((IDispatchEx*)disp);
880 jsdisp_t *to_jsdisp(IDispatch *disp)
882 return disp->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl ? impl_from_IDispatchEx((IDispatchEx*)disp) : NULL;
885 HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype)
887 TRACE("%p (%p)\n", dispex, prototype);
889 dispex->IDispatchEx_iface.lpVtbl = &DispatchExVtbl;
890 dispex->ref = 1;
891 dispex->builtin_info = builtin_info;
893 dispex->props = heap_alloc_zero(sizeof(dispex_prop_t)*(dispex->buf_size=4));
894 if(!dispex->props)
895 return E_OUTOFMEMORY;
897 dispex->prototype = prototype;
898 if(prototype)
899 jsdisp_addref(prototype);
901 dispex->prop_cnt = 1;
902 if(builtin_info->value_prop.invoke || builtin_info->value_prop.getter) {
903 dispex->props[0].type = PROP_BUILTIN;
904 dispex->props[0].u.p = &builtin_info->value_prop;
905 }else {
906 dispex->props[0].type = PROP_DELETED;
909 script_addref(ctx);
910 dispex->ctx = ctx;
912 return S_OK;
915 static const builtin_info_t dispex_info = {
916 JSCLASS_NONE,
917 {NULL, NULL, 0},
918 0, NULL,
919 NULL,
920 NULL
923 HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype, jsdisp_t **dispex)
925 jsdisp_t *ret;
926 HRESULT hres;
928 ret = heap_alloc_zero(sizeof(jsdisp_t));
929 if(!ret)
930 return E_OUTOFMEMORY;
932 hres = init_dispex(ret, ctx, builtin_info ? builtin_info : &dispex_info, prototype);
933 if(FAILED(hres)) {
934 heap_free(ret);
935 return hres;
938 *dispex = ret;
939 return S_OK;
942 void jsdisp_free(jsdisp_t *obj)
944 dispex_prop_t *prop;
946 TRACE("(%p)\n", obj);
948 for(prop = obj->props; prop < obj->props+obj->prop_cnt; prop++) {
949 if(prop->type == PROP_JSVAL)
950 jsval_release(prop->u.val);
951 heap_free(prop->name);
953 heap_free(obj->props);
954 script_release(obj->ctx);
955 if(obj->prototype)
956 jsdisp_release(obj->prototype);
958 if(obj->builtin_info->destructor)
959 obj->builtin_info->destructor(obj);
960 else
961 heap_free(obj);
964 #ifdef TRACE_REFCNT
966 jsdisp_t *jsdisp_addref(jsdisp_t *jsdisp)
968 ULONG ref = ++jsdisp->ref;
969 TRACE("(%p) ref=%d\n", jsdisp, ref);
970 return jsdisp;
973 void jsdisp_release(jsdisp_t *jsdisp)
975 ULONG ref = --jsdisp->ref;
977 TRACE("(%p) ref=%d\n", jsdisp, ref);
979 if(!ref)
980 jsdisp_free(jsdisp);
983 #endif
985 HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *constr)
987 jsdisp_t *prot = NULL;
988 dispex_prop_t *prop;
989 HRESULT hres;
991 static const WCHAR prototypeW[] = {'p','r','o','t','o','t','y','p','e',0};
993 hres = find_prop_name_prot(constr, string_hash(prototypeW), prototypeW, &prop);
994 if(SUCCEEDED(hres) && prop && prop->type!=PROP_DELETED) {
995 jsval_t val;
997 hres = prop_get(constr, prop, NULL, &val, NULL);
998 if(FAILED(hres)) {
999 ERR("Could not get prototype\n");
1000 return hres;
1003 if(is_object_instance(val))
1004 prot = iface_to_jsdisp(get_object(val));
1005 jsval_release(val);
1008 hres = init_dispex(dispex, ctx, builtin_info, prot);
1010 if(prot)
1011 jsdisp_release(prot);
1012 return hres;
1015 jsdisp_t *iface_to_jsdisp(IDispatch *iface)
1017 return iface->lpVtbl == (const IDispatchVtbl*)&DispatchExVtbl
1018 ? jsdisp_addref( impl_from_IDispatchEx((IDispatchEx*)iface))
1019 : NULL;
1022 HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID *id)
1024 dispex_prop_t *prop;
1025 HRESULT hres;
1027 if(flags & fdexNameEnsure)
1028 hres = ensure_prop_name(jsdisp, name, TRUE, PROPF_ENUM, &prop);
1029 else
1030 hres = find_prop_name_prot(jsdisp, string_hash(name), name, &prop);
1031 if(FAILED(hres))
1032 return hres;
1034 if(prop && prop->type!=PROP_DELETED) {
1035 *id = prop_to_id(jsdisp, prop);
1036 return S_OK;
1039 TRACE("not found %s\n", debugstr_w(name));
1040 return DISP_E_UNKNOWNNAME;
1043 HRESULT jsdisp_call_value(jsdisp_t *jsfunc, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1045 HRESULT hres;
1047 assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT|DISPATCH_JSCRIPT_INTERNAL_MASK)));
1049 if(is_class(jsfunc, JSCLASS_FUNCTION)) {
1050 hres = Function_invoke(jsfunc, jsthis, flags, argc, argv, r);
1051 }else {
1052 vdisp_t vdisp;
1054 if(!jsfunc->builtin_info->value_prop.invoke) {
1055 WARN("Not a function\n");
1056 return throw_type_error(jsfunc->ctx, JS_E_FUNCTION_EXPECTED, NULL);
1059 set_disp(&vdisp, jsthis);
1060 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
1061 hres = jsfunc->builtin_info->value_prop.invoke(jsfunc->ctx, &vdisp, flags, argc, argv, r);
1062 vdisp_release(&vdisp);
1064 return hres;
1067 HRESULT jsdisp_call(jsdisp_t *disp, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1069 dispex_prop_t *prop;
1071 prop = get_prop(disp, id);
1072 if(!prop)
1073 return DISP_E_MEMBERNOTFOUND;
1075 return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, NULL);
1078 HRESULT jsdisp_call_name(jsdisp_t *disp, const WCHAR *name, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1080 dispex_prop_t *prop;
1081 HRESULT hres;
1083 hres = find_prop_name_prot(disp, string_hash(name), name, &prop);
1084 if(FAILED(hres))
1085 return hres;
1087 return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, NULL);
1090 HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *ret)
1092 IDispatchEx *dispex;
1093 jsdisp_t *jsdisp;
1094 VARIANT buf[6], retv;
1095 DISPPARAMS dp;
1096 unsigned i;
1097 HRESULT hres;
1099 jsdisp = iface_to_jsdisp(disp);
1100 if(jsdisp) {
1101 if(flags & DISPATCH_PROPERTYPUT) {
1102 FIXME("disp_call(propput) on builtin object\n");
1103 return E_FAIL;
1106 if(ctx != jsdisp->ctx)
1107 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
1108 hres = jsdisp_call(jsdisp, id, flags, argc, argv, ret);
1109 jsdisp_release(jsdisp);
1110 return hres;
1113 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
1114 if(ret && argc)
1115 flags |= DISPATCH_PROPERTYGET;
1117 dp.cArgs = argc;
1119 if(flags & DISPATCH_PROPERTYPUT) {
1120 static DISPID propput_dispid = DISPID_PROPERTYPUT;
1122 dp.cNamedArgs = 1;
1123 dp.rgdispidNamedArgs = &propput_dispid;
1124 }else {
1125 dp.cNamedArgs = 0;
1126 dp.rgdispidNamedArgs = NULL;
1129 if(argc > 6) {
1130 dp.rgvarg = heap_alloc(argc*sizeof(VARIANT));
1131 if(!dp.rgvarg)
1132 return E_OUTOFMEMORY;
1133 }else {
1134 dp.rgvarg = buf;
1137 for(i=0; i<argc; i++) {
1138 hres = jsval_to_variant(argv[i], dp.rgvarg+argc-i-1);
1139 if(FAILED(hres)) {
1140 while(i--)
1141 VariantClear(dp.rgvarg+argc-i-1);
1142 if(dp.rgvarg != buf)
1143 heap_free(dp.rgvarg);
1144 return hres;
1148 V_VT(&retv) = VT_EMPTY;
1149 clear_ei(ctx);
1150 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1151 if(SUCCEEDED(hres)) {
1152 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, &dp, ret ? &retv : NULL, &ctx->ei.ei,
1153 &ctx->jscaller->IServiceProvider_iface);
1154 IDispatchEx_Release(dispex);
1155 }else {
1156 UINT err = 0;
1158 if(flags == DISPATCH_CONSTRUCT) {
1159 WARN("IDispatch cannot be constructor\n");
1160 return DISP_E_MEMBERNOTFOUND;
1163 TRACE("using IDispatch\n");
1164 hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, &dp, ret ? &retv : NULL, &ctx->ei.ei, &err);
1167 for(i=0; i<argc; i++)
1168 VariantClear(dp.rgvarg+argc-i-1);
1169 if(dp.rgvarg != buf)
1170 heap_free(dp.rgvarg);
1171 if(FAILED(hres))
1172 return hres;
1174 if(ret) {
1175 hres = variant_to_jsval(&retv, ret);
1176 VariantClear(&retv);
1179 return hres;
1182 HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1183 jsval_t *r)
1185 jsdisp_t *jsdisp;
1186 IDispatchEx *dispex;
1187 VARIANT buf[6], retv;
1188 DISPPARAMS dp;
1189 unsigned i;
1190 HRESULT hres;
1192 assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT|DISPATCH_JSCRIPT_INTERNAL_MASK)));
1194 jsdisp = iface_to_jsdisp(disp);
1195 if(jsdisp) {
1196 if(ctx != jsdisp->ctx)
1197 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
1198 hres = jsdisp_call_value(jsdisp, jsthis, flags, argc, argv, r);
1199 jsdisp_release(jsdisp);
1200 return hres;
1203 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
1204 if(r && argc && flags == DISPATCH_METHOD)
1205 flags |= DISPATCH_PROPERTYGET;
1207 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1208 if(FAILED(hres)) {
1209 TRACE("using IDispatch\n");
1210 dispex = NULL;
1211 jsthis = NULL;
1214 if(jsthis) {
1215 static DISPID this_id = DISPID_THIS;
1217 dp.cArgs = argc+1;
1218 dp.cNamedArgs = 1;
1219 dp.rgdispidNamedArgs = &this_id;
1220 }else {
1221 dp.cArgs = argc;
1222 dp.cNamedArgs = 0;
1223 dp.rgdispidNamedArgs = NULL;
1226 if(dp.cArgs > sizeof(buf)/sizeof(*buf)) {
1227 dp.rgvarg = heap_alloc(dp.cArgs*sizeof(VARIANT));
1228 if(!dp.rgvarg) {
1229 if(dispex)
1230 IDispatchEx_Release(dispex);
1231 return E_OUTOFMEMORY;
1233 }else {
1234 dp.rgvarg = buf;
1237 for(i=0; i<argc; i++) {
1238 hres = jsval_to_variant(argv[i], dp.rgvarg+dp.cArgs-i-1);
1239 if(FAILED(hres)) {
1240 while(i--)
1241 VariantClear(dp.rgvarg+dp.cArgs-i-1);
1242 if(dp.rgvarg != buf)
1243 heap_free(dp.rgvarg);
1244 if(dispex)
1245 IDispatchEx_Release(dispex);
1246 return hres;
1249 if(jsthis) {
1250 V_VT(dp.rgvarg) = VT_DISPATCH;
1251 V_DISPATCH(dp.rgvarg) = jsthis;
1254 V_VT(&retv) = VT_EMPTY;
1255 clear_ei(ctx);
1256 if(dispex) {
1257 hres = IDispatchEx_InvokeEx(dispex, DISPID_VALUE, ctx->lcid, flags, &dp, r ? &retv : NULL, &ctx->ei.ei,
1258 &ctx->jscaller->IServiceProvider_iface);
1259 IDispatchEx_Release(dispex);
1260 }else {
1261 UINT err = 0;
1263 if(flags == DISPATCH_CONSTRUCT) {
1264 WARN("IDispatch cannot be constructor\n");
1265 return DISP_E_MEMBERNOTFOUND;
1268 hres = IDispatch_Invoke(disp, DISPID_VALUE, &IID_NULL, ctx->lcid, flags, &dp, r ? &retv : NULL, &ctx->ei.ei, &err);
1271 for(i=0; i<argc; i++)
1272 VariantClear(dp.rgvarg+dp.cArgs-i-1);
1273 if(dp.rgvarg != buf)
1274 heap_free(dp.rgvarg);
1275 if(FAILED(hres))
1276 return hres;
1278 if(!r)
1279 return S_OK;
1281 hres = variant_to_jsval(&retv, r);
1282 VariantClear(&retv);
1283 return hres;
1286 HRESULT jsdisp_propput(jsdisp_t *obj, const WCHAR *name, DWORD flags, jsval_t val)
1288 dispex_prop_t *prop;
1289 HRESULT hres;
1291 hres = ensure_prop_name(obj, name, FALSE, flags, &prop);
1292 if(FAILED(hres))
1293 return hres;
1295 return prop_put(obj, prop, val, NULL);
1298 HRESULT jsdisp_propput_name(jsdisp_t *obj, const WCHAR *name, jsval_t val)
1300 return jsdisp_propput(obj, name, PROPF_ENUM, val);
1303 HRESULT jsdisp_propput_const(jsdisp_t *obj, const WCHAR *name, jsval_t val)
1305 dispex_prop_t *prop;
1306 HRESULT hres;
1308 hres = ensure_prop_name(obj, name, FALSE, PROPF_CONST, &prop);
1309 if(FAILED(hres))
1310 return hres;
1312 return jsval_copy(val, &prop->u.val);
1315 HRESULT jsdisp_propput_dontenum(jsdisp_t *obj, const WCHAR *name, jsval_t val)
1317 return jsdisp_propput(obj, name, 0, val);
1320 HRESULT jsdisp_propput_idx(jsdisp_t *obj, DWORD idx, jsval_t val)
1322 WCHAR buf[12];
1324 static const WCHAR formatW[] = {'%','d',0};
1326 sprintfW(buf, formatW, idx);
1327 return jsdisp_propput_name(obj, buf, val);
1330 HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val)
1332 jsdisp_t *jsdisp;
1333 HRESULT hres;
1335 jsdisp = iface_to_jsdisp(disp);
1336 if(jsdisp) {
1337 dispex_prop_t *prop;
1339 prop = get_prop(jsdisp, id);
1340 if(prop)
1341 hres = prop_put(jsdisp, prop, val, NULL);
1342 else
1343 hres = DISP_E_MEMBERNOTFOUND;
1345 jsdisp_release(jsdisp);
1346 }else {
1347 DISPID dispid = DISPID_PROPERTYPUT;
1348 DWORD flags = DISPATCH_PROPERTYPUT;
1349 VARIANT var;
1350 DISPPARAMS dp = {&var, &dispid, 1, 1};
1351 IDispatchEx *dispex;
1353 hres = jsval_to_variant(val, &var);
1354 if(FAILED(hres))
1355 return hres;
1357 if(V_VT(&var) == VT_DISPATCH)
1358 flags |= DISPATCH_PROPERTYPUTREF;
1360 clear_ei(ctx);
1361 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1362 if(SUCCEEDED(hres)) {
1363 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, &dp, NULL, &ctx->ei.ei,
1364 &ctx->jscaller->IServiceProvider_iface);
1365 IDispatchEx_Release(dispex);
1366 }else {
1367 ULONG err = 0;
1369 TRACE("using IDispatch\n");
1370 hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, &dp, NULL, &ctx->ei.ei, &err);
1373 VariantClear(&var);
1376 return hres;
1379 HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val)
1381 DISPPARAMS dp = {NULL, NULL, 0, 0};
1382 dispex_prop_t *prop;
1383 HRESULT hres;
1385 hres = find_prop_name_prot(obj, string_hash(name), name, &prop);
1386 if(FAILED(hres))
1387 return hres;
1389 if(!prop || prop->type==PROP_DELETED) {
1390 *val = jsval_undefined();
1391 return S_OK;
1394 return prop_get(obj, prop, &dp, val, NULL);
1397 HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r)
1399 WCHAR name[12];
1400 DISPPARAMS dp = {NULL, NULL, 0, 0};
1401 dispex_prop_t *prop;
1402 HRESULT hres;
1404 static const WCHAR formatW[] = {'%','d',0};
1406 sprintfW(name, formatW, idx);
1408 hres = find_prop_name_prot(obj, string_hash(name), name, &prop);
1409 if(FAILED(hres))
1410 return hres;
1412 if(!prop || prop->type==PROP_DELETED) {
1413 *r = jsval_undefined();
1414 return DISP_E_UNKNOWNNAME;
1417 return prop_get(obj, prop, &dp, r, NULL);
1420 HRESULT jsdisp_propget(jsdisp_t *jsdisp, DISPID id, jsval_t *val)
1422 DISPPARAMS dp = {NULL,NULL,0,0};
1423 dispex_prop_t *prop;
1425 prop = get_prop(jsdisp, id);
1426 if(!prop)
1427 return DISP_E_MEMBERNOTFOUND;
1429 return prop_get(jsdisp, prop, &dp, val, NULL);
1432 HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t *val)
1434 DISPPARAMS dp = {NULL,NULL,0,0};
1435 IDispatchEx *dispex;
1436 jsdisp_t *jsdisp;
1437 VARIANT var;
1438 HRESULT hres;
1440 jsdisp = iface_to_jsdisp(disp);
1441 if(jsdisp) {
1442 hres = jsdisp_propget(jsdisp, id, val);
1443 jsdisp_release(jsdisp);
1444 return hres;
1447 V_VT(&var) = VT_EMPTY;
1448 clear_ei(ctx);
1449 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1450 if(SUCCEEDED(hres)) {
1451 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, INVOKE_PROPERTYGET, &dp, &var, &ctx->ei.ei,
1452 &ctx->jscaller->IServiceProvider_iface);
1453 IDispatchEx_Release(dispex);
1454 }else {
1455 ULONG err = 0;
1457 TRACE("using IDispatch\n");
1458 hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, INVOKE_PROPERTYGET, &dp, &var, &ctx->ei.ei, &err);
1460 if(FAILED(hres))
1461 return hres;
1463 hres = variant_to_jsval(&var, val);
1464 VariantClear(&var);
1465 return hres;
1468 HRESULT jsdisp_delete_idx(jsdisp_t *obj, DWORD idx)
1470 static const WCHAR formatW[] = {'%','d',0};
1471 WCHAR buf[12];
1472 dispex_prop_t *prop;
1473 BOOL b;
1474 HRESULT hres;
1476 sprintfW(buf, formatW, idx);
1478 hres = find_prop_name(obj, string_hash(buf), buf, &prop);
1479 if(FAILED(hres) || !prop)
1480 return hres;
1482 return delete_prop(prop, &b);
1485 HRESULT disp_delete(IDispatch *disp, DISPID id, BOOL *ret)
1487 IDispatchEx *dispex;
1488 jsdisp_t *jsdisp;
1489 HRESULT hres;
1491 jsdisp = iface_to_jsdisp(disp);
1492 if(jsdisp) {
1493 dispex_prop_t *prop;
1495 prop = get_prop(jsdisp, id);
1496 if(prop)
1497 hres = delete_prop(prop, ret);
1498 else
1499 hres = DISP_E_MEMBERNOTFOUND;
1501 jsdisp_release(jsdisp);
1502 return hres;
1505 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1506 if(FAILED(hres)) {
1507 *ret = FALSE;
1508 return S_OK;
1511 hres = IDispatchEx_DeleteMemberByDispID(dispex, id);
1512 IDispatchEx_Release(dispex);
1513 if(FAILED(hres))
1514 return hres;
1516 *ret = hres == S_OK;
1517 return S_OK;
1520 HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL *ret)
1522 IDispatchEx *dispex;
1523 jsdisp_t *jsdisp;
1524 BSTR bstr;
1525 HRESULT hres;
1527 jsdisp = iface_to_jsdisp(disp);
1528 if(jsdisp) {
1529 dispex_prop_t *prop;
1530 const WCHAR *ptr;
1532 ptr = jsstr_flatten(name);
1533 if(!ptr) {
1534 jsdisp_release(jsdisp);
1535 return E_OUTOFMEMORY;
1538 hres = find_prop_name(jsdisp, string_hash(ptr), ptr, &prop);
1539 if(prop) {
1540 hres = delete_prop(prop, ret);
1541 }else {
1542 *ret = TRUE;
1543 hres = S_OK;
1546 jsdisp_release(jsdisp);
1547 return hres;
1550 bstr = SysAllocStringLen(NULL, jsstr_length(name));
1551 if(!bstr)
1552 return E_OUTOFMEMORY;
1553 jsstr_flush(name, bstr);
1555 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1556 if(SUCCEEDED(hres)) {
1557 hres = IDispatchEx_DeleteMemberByName(dispex, bstr, make_grfdex(ctx, fdexNameCaseSensitive));
1558 if(SUCCEEDED(hres))
1559 *ret = hres == S_OK;
1560 IDispatchEx_Release(dispex);
1561 }else {
1562 DISPID id;
1564 hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, &id);
1565 if(SUCCEEDED(hres)) {
1566 /* Property exists and we can't delete it from pure IDispatch interface, so return false. */
1567 *ret = FALSE;
1568 }else if(hres == DISP_E_UNKNOWNNAME) {
1569 /* Property doesn't exist, so nothing to delete */
1570 *ret = TRUE;
1571 hres = S_OK;
1575 SysFreeString(bstr);
1576 return hres;
1579 HRESULT jsdisp_is_own_prop(jsdisp_t *obj, const WCHAR *name, BOOL *ret)
1581 dispex_prop_t *prop;
1582 HRESULT hres;
1584 hres = find_prop_name(obj, string_hash(name), name, &prop);
1585 if(FAILED(hres))
1586 return hres;
1588 *ret = prop && (prop->type == PROP_JSVAL || prop->type == PROP_BUILTIN);
1589 return S_OK;
1592 HRESULT jsdisp_is_enumerable(jsdisp_t *obj, const WCHAR *name, BOOL *ret)
1594 dispex_prop_t *prop;
1595 HRESULT hres;
1597 hres = find_prop_name(obj, string_hash(name), name, &prop);
1598 if(FAILED(hres))
1599 return hres;
1601 *ret = prop && (prop->flags & PROPF_ENUM) && prop->type != PROP_PROTREF;
1602 return S_OK;