d3d11: Remove null dxgi object checks.
[wine.git] / dlls / jscript / dispex.c
blob298f7e1af899d0b0f8bf75223e79f582a616cef6
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"
22 #include "engine.h"
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
28 static const GUID GUID_JScriptTypeInfo = {0xc59c6b12,0xf6c1,0x11cf,{0x88,0x35,0x00,0xa0,0xc9,0x11,0xe8,0xb2}};
30 #define FDEX_VERSION_MASK 0xf0000000
31 #define GOLDEN_RATIO 0x9E3779B9U
33 typedef enum {
34 PROP_JSVAL,
35 PROP_BUILTIN,
36 PROP_PROTREF,
37 PROP_ACCESSOR,
38 PROP_DELETED,
39 PROP_IDX
40 } prop_type_t;
42 struct _dispex_prop_t {
43 WCHAR *name;
44 unsigned hash;
45 prop_type_t type;
46 DWORD flags;
48 union {
49 jsval_t val;
50 const builtin_prop_t *p;
51 DWORD ref;
52 unsigned idx;
53 struct {
54 jsdisp_t *getter;
55 jsdisp_t *setter;
56 } accessor;
57 } u;
59 int bucket_head;
60 int bucket_next;
63 static void fix_protref_prop(jsdisp_t *jsdisp, dispex_prop_t *prop)
65 DWORD ref;
67 if(prop->type != PROP_PROTREF)
68 return;
69 ref = prop->u.ref;
71 while((jsdisp = jsdisp->prototype)) {
72 if(ref >= jsdisp->prop_cnt || jsdisp->props[ref].type == PROP_DELETED)
73 break;
74 if(jsdisp->props[ref].type != PROP_PROTREF)
75 return;
76 ref = jsdisp->props[ref].u.ref;
78 prop->type = PROP_DELETED;
81 static inline DISPID prop_to_id(jsdisp_t *This, dispex_prop_t *prop)
83 /* don't overlap with DISPID_VALUE */
84 return prop - This->props + 1;
87 static inline dispex_prop_t *get_prop(jsdisp_t *This, DISPID id)
89 DWORD idx = id - 1;
91 if(idx >= This->prop_cnt)
92 return NULL;
93 fix_protref_prop(This, &This->props[idx]);
95 return This->props[idx].type == PROP_DELETED ? NULL : &This->props[idx];
98 static inline BOOL is_function_prop(dispex_prop_t *prop)
100 BOOL ret = FALSE;
102 if (is_object_instance(prop->u.val))
104 jsdisp_t *jsdisp = iface_to_jsdisp(get_object(prop->u.val));
106 if (jsdisp) ret = is_class(jsdisp, JSCLASS_FUNCTION);
107 jsdisp_release(jsdisp);
109 return ret;
112 static DWORD get_flags(jsdisp_t *This, dispex_prop_t *prop)
114 if(prop->type == PROP_PROTREF) {
115 dispex_prop_t *parent = NULL;
117 if(prop->u.ref < This->prototype->prop_cnt)
118 parent = &This->prototype->props[prop->u.ref];
120 if(!parent || parent->type == PROP_DELETED) {
121 prop->type = PROP_DELETED;
122 return 0;
125 return get_flags(This->prototype, parent);
128 return prop->flags;
131 static const builtin_prop_t *find_builtin_prop(jsdisp_t *This, const WCHAR *name)
133 int min = 0, max, i, r;
135 max = This->builtin_info->props_cnt-1;
136 while(min <= max) {
137 i = (min+max)/2;
139 r = wcscmp(name, This->builtin_info->props[i].name);
140 if(!r) {
141 /* Skip prop if it's available only in higher compatibility mode. */
142 unsigned version = (This->builtin_info->props[i].flags & PROPF_VERSION_MASK)
143 >> PROPF_VERSION_SHIFT;
144 if(version && version > This->ctx->version)
145 return NULL;
147 /* Skip prop if it's available only in HTML mode and we're not running in HTML mode. */
148 if((This->builtin_info->props[i].flags & PROPF_HTML) && !This->ctx->html_mode)
149 return NULL;
151 return This->builtin_info->props + i;
154 if(r < 0)
155 max = i-1;
156 else
157 min = i+1;
160 return NULL;
163 static inline unsigned string_hash(const WCHAR *name)
165 unsigned h = 0;
166 for(; *name; name++)
167 h = (h>>(sizeof(unsigned)*8-4)) ^ (h<<4) ^ towlower(*name);
168 return h;
171 static inline unsigned get_props_idx(jsdisp_t *This, unsigned hash)
173 return (hash*GOLDEN_RATIO) & (This->buf_size-1);
176 static inline HRESULT resize_props(jsdisp_t *This)
178 dispex_prop_t *props;
179 int i, bucket;
181 if(This->buf_size != This->prop_cnt)
182 return S_FALSE;
184 props = heap_realloc(This->props, sizeof(dispex_prop_t)*This->buf_size*2);
185 if(!props)
186 return E_OUTOFMEMORY;
187 This->buf_size *= 2;
188 This->props = props;
190 for(i=0; i<This->buf_size; i++) {
191 This->props[i].bucket_head = ~0;
192 This->props[i].bucket_next = ~0;
195 for(i=0; i<This->prop_cnt; i++) {
196 props = This->props+i;
198 bucket = get_props_idx(This, props->hash);
199 props->bucket_next = This->props[bucket].bucket_head;
200 This->props[bucket].bucket_head = i;
203 return S_OK;
206 static inline dispex_prop_t* alloc_prop(jsdisp_t *This, const WCHAR *name, prop_type_t type, DWORD flags)
208 dispex_prop_t *prop;
209 unsigned bucket;
211 if(FAILED(resize_props(This)))
212 return NULL;
214 prop = &This->props[This->prop_cnt];
215 prop->name = heap_strdupW(name);
216 if(!prop->name)
217 return NULL;
218 prop->type = type;
219 prop->flags = flags;
220 prop->hash = string_hash(name);
222 bucket = get_props_idx(This, prop->hash);
223 prop->bucket_next = This->props[bucket].bucket_head;
224 This->props[bucket].bucket_head = This->prop_cnt++;
225 return prop;
228 static dispex_prop_t *alloc_protref(jsdisp_t *This, const WCHAR *name, DWORD ref)
230 dispex_prop_t *ret;
232 ret = alloc_prop(This, name, PROP_PROTREF, 0);
233 if(!ret)
234 return NULL;
236 ret->u.ref = ref;
237 return ret;
240 static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, dispex_prop_t **ret)
242 const builtin_prop_t *builtin;
243 unsigned bucket, pos, prev = ~0;
244 dispex_prop_t *prop;
245 HRESULT hres;
247 bucket = get_props_idx(This, hash);
248 pos = This->props[bucket].bucket_head;
249 while(pos != ~0) {
250 if(!wcscmp(name, This->props[pos].name)) {
251 if(prev != ~0) {
252 This->props[prev].bucket_next = This->props[pos].bucket_next;
253 This->props[pos].bucket_next = This->props[bucket].bucket_head;
254 This->props[bucket].bucket_head = pos;
257 *ret = &This->props[pos];
258 return S_OK;
261 prev = pos;
262 pos = This->props[pos].bucket_next;
265 builtin = find_builtin_prop(This, name);
266 if(builtin) {
267 unsigned flags = builtin->flags;
268 if(flags & PROPF_METHOD) {
269 jsdisp_t *obj;
271 hres = create_builtin_function(This->ctx, builtin->invoke, builtin->name, NULL, flags, NULL, &obj);
272 if(FAILED(hres))
273 return hres;
275 prop = alloc_prop(This, name, PROP_JSVAL, (flags & PROPF_ALL) | PROPF_WRITABLE | PROPF_CONFIGURABLE);
276 if(!prop) {
277 jsdisp_release(obj);
278 return E_OUTOFMEMORY;
281 prop->type = PROP_JSVAL;
282 prop->u.val = jsval_obj(obj);
283 *ret = prop;
284 return S_OK;
285 }else if(builtin->setter)
286 flags |= PROPF_WRITABLE;
287 flags &= PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE;
288 prop = alloc_prop(This, name, PROP_BUILTIN, flags);
289 if(!prop)
290 return E_OUTOFMEMORY;
292 prop->u.p = builtin;
293 *ret = prop;
294 return S_OK;
297 if(This->builtin_info->idx_length) {
298 const WCHAR *ptr;
299 unsigned idx = 0;
301 for(ptr = name; is_digit(*ptr) && idx < 0x10000; ptr++)
302 idx = idx*10 + (*ptr-'0');
303 if(!*ptr && idx < This->builtin_info->idx_length(This)) {
304 unsigned flags = PROPF_ENUMERABLE;
305 if(This->builtin_info->idx_put)
306 flags |= PROPF_WRITABLE;
307 prop = alloc_prop(This, name, PROP_IDX, flags);
308 if(!prop)
309 return E_OUTOFMEMORY;
311 prop->u.idx = idx;
312 *ret = prop;
313 return S_OK;
317 *ret = NULL;
318 return S_OK;
321 static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *name, dispex_prop_t **ret)
323 dispex_prop_t *prop, *del=NULL;
324 HRESULT hres;
326 hres = find_prop_name(This, hash, name, &prop);
327 if(FAILED(hres))
328 return hres;
329 if(prop && prop->type==PROP_DELETED) {
330 del = prop;
331 } else if(prop) {
332 fix_protref_prop(This, prop);
333 *ret = prop;
334 return S_OK;
337 if(This->prototype) {
338 hres = find_prop_name_prot(This->prototype, hash, name, &prop);
339 if(FAILED(hres))
340 return hres;
341 if(prop && prop->type != PROP_DELETED) {
342 if(del) {
343 del->type = PROP_PROTREF;
344 del->u.ref = prop - This->prototype->props;
345 prop = del;
346 }else {
347 prop = alloc_protref(This, prop->name, prop - This->prototype->props);
348 if(!prop)
349 return E_OUTOFMEMORY;
352 *ret = prop;
353 return S_OK;
357 *ret = del;
358 return S_OK;
361 static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_flags, dispex_prop_t **ret)
363 dispex_prop_t *prop;
364 HRESULT hres;
366 hres = find_prop_name_prot(This, string_hash(name), name, &prop);
367 if(SUCCEEDED(hres) && (!prop || prop->type == PROP_DELETED)) {
368 TRACE("creating prop %s flags %lx\n", debugstr_w(name), create_flags);
370 if(prop) {
371 prop->type = PROP_JSVAL;
372 prop->flags = create_flags;
373 prop->u.val = jsval_undefined();
374 }else {
375 prop = alloc_prop(This, name, PROP_JSVAL, create_flags);
376 if(!prop)
377 return E_OUTOFMEMORY;
380 prop->u.val = jsval_undefined();
383 *ret = prop;
384 return hres;
387 static IDispatch *get_this(DISPPARAMS *dp)
389 DWORD i;
391 for(i=0; i < dp->cNamedArgs; i++) {
392 if(dp->rgdispidNamedArgs[i] == DISPID_THIS) {
393 if(V_VT(dp->rgvarg+i) == VT_DISPATCH)
394 return V_DISPATCH(dp->rgvarg+i);
396 WARN("This is not VT_DISPATCH\n");
397 return NULL;
401 TRACE("no this passed\n");
402 return NULL;
405 static HRESULT convert_params(script_ctx_t *ctx, const DISPPARAMS *dp, jsval_t *buf, unsigned *argc, jsval_t **ret)
407 jsval_t *argv;
408 unsigned cnt;
409 unsigned i;
410 HRESULT hres;
412 cnt = dp->cArgs - dp->cNamedArgs;
414 if(cnt > 6) {
415 argv = heap_alloc(cnt * sizeof(*argv));
416 if(!argv)
417 return E_OUTOFMEMORY;
418 }else {
419 argv = buf;
422 for(i = 0; i < cnt; i++) {
423 hres = variant_to_jsval(ctx, dp->rgvarg+dp->cArgs-i-1, argv+i);
424 if(FAILED(hres)) {
425 while(i--)
426 jsval_release(argv[i]);
427 if(argv != buf)
428 heap_free(argv);
429 return hres;
433 *argc = cnt;
434 *ret = argv;
435 return S_OK;
438 static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, jsval_t *r)
440 jsdisp_t *prop_obj = This;
441 HRESULT hres;
443 while(prop->type == PROP_PROTREF) {
444 prop_obj = prop_obj->prototype;
445 prop = prop_obj->props + prop->u.ref;
448 switch(prop->type) {
449 case PROP_BUILTIN:
450 hres = prop->u.p->getter(This->ctx, This, r);
451 break;
452 case PROP_JSVAL:
453 hres = jsval_copy(prop->u.val, r);
454 break;
455 case PROP_ACCESSOR:
456 if(prop->u.accessor.getter) {
457 hres = jsdisp_call_value(prop->u.accessor.getter, to_disp(This),
458 DISPATCH_METHOD, 0, NULL, r);
459 }else {
460 *r = jsval_undefined();
461 hres = S_OK;
463 break;
464 case PROP_IDX:
465 hres = prop_obj->builtin_info->idx_get(prop_obj, prop->u.idx, r);
466 break;
467 default:
468 ERR("type %d\n", prop->type);
469 return E_FAIL;
472 if(FAILED(hres)) {
473 TRACE("fail %08lx\n", hres);
474 return hres;
477 TRACE("%p.%s ret %s\n", This, debugstr_w(prop->name), debugstr_jsval(*r));
478 return hres;
481 static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val)
483 HRESULT hres;
485 if(prop->type == PROP_PROTREF) {
486 dispex_prop_t *prop_iter = prop;
487 jsdisp_t *prototype_iter = This;
489 do {
490 prototype_iter = prototype_iter->prototype;
491 prop_iter = prototype_iter->props + prop_iter->u.ref;
492 } while(prop_iter->type == PROP_PROTREF);
494 if(prop_iter->type == PROP_ACCESSOR)
495 prop = prop_iter;
498 switch(prop->type) {
499 case PROP_BUILTIN:
500 if(!prop->u.p->setter) {
501 TRACE("getter with no setter\n");
502 return S_OK;
504 return prop->u.p->setter(This->ctx, This, val);
505 case PROP_PROTREF:
506 case PROP_DELETED:
507 if(!This->extensible)
508 return S_OK;
509 prop->type = PROP_JSVAL;
510 prop->flags = PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE;
511 prop->u.val = jsval_undefined();
512 break;
513 case PROP_JSVAL:
514 if(!(prop->flags & PROPF_WRITABLE))
515 return S_OK;
517 jsval_release(prop->u.val);
518 break;
519 case PROP_ACCESSOR:
520 if(!prop->u.accessor.setter) {
521 TRACE("no setter\n");
522 return S_OK;
524 return jsdisp_call_value(prop->u.accessor.setter, to_disp(This), DISPATCH_METHOD, 1, &val, NULL);
525 case PROP_IDX:
526 if(!This->builtin_info->idx_put) {
527 TRACE("no put_idx\n");
528 return S_OK;
530 return This->builtin_info->idx_put(This, prop->u.idx, val);
531 default:
532 ERR("type %d\n", prop->type);
533 return E_FAIL;
536 TRACE("%p.%s = %s\n", This, debugstr_w(prop->name), debugstr_jsval(val));
538 hres = jsval_copy(val, &prop->u.val);
539 if(FAILED(hres))
540 return hres;
542 if(This->builtin_info->on_put)
543 This->builtin_info->on_put(This, prop->name);
545 return S_OK;
548 static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t *prop, WORD flags,
549 unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller)
551 HRESULT hres;
553 switch(prop->type) {
554 case PROP_BUILTIN:
555 return JS_E_FUNCTION_EXPECTED;
556 case PROP_PROTREF:
557 return invoke_prop_func(This->prototype, jsthis ? jsthis : (IDispatch *)&This->IDispatchEx_iface,
558 This->prototype->props+prop->u.ref, flags, argc, argv, r, caller);
559 case PROP_JSVAL: {
560 if(!is_object_instance(prop->u.val)) {
561 FIXME("invoke %s\n", debugstr_jsval(prop->u.val));
562 return E_FAIL;
565 TRACE("call %s %p\n", debugstr_w(prop->name), get_object(prop->u.val));
567 return disp_call_value(This->ctx, get_object(prop->u.val),
568 jsthis ? jsthis : (IDispatch*)&This->IDispatchEx_iface,
569 flags, argc, argv, r);
571 case PROP_ACCESSOR:
572 case PROP_IDX: {
573 jsval_t val;
575 hres = prop_get(This, prop, &val);
576 if(FAILED(hres))
577 return hres;
579 if(is_object_instance(val)) {
580 hres = disp_call_value(This->ctx, get_object(val),
581 jsthis ? jsthis : (IDispatch*)&This->IDispatchEx_iface,
582 flags, argc, argv, r);
583 }else {
584 FIXME("invoke %s\n", debugstr_jsval(val));
585 hres = E_NOTIMPL;
588 jsval_release(val);
589 return hres;
591 case PROP_DELETED:
592 assert(0);
593 break;
596 return E_FAIL;
599 HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
601 TRACE("%p %s\n", jsthis, debugstr_jsval(value));
602 return S_OK;
605 static HRESULT fill_protrefs(jsdisp_t *This)
607 dispex_prop_t *iter, *prop;
608 HRESULT hres;
610 if(!This->prototype)
611 return S_OK;
613 fill_protrefs(This->prototype);
615 for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) {
616 hres = find_prop_name(This, iter->hash, iter->name, &prop);
617 if(FAILED(hres))
618 return hres;
619 if(!prop || prop->type==PROP_DELETED) {
620 if(prop) {
621 prop->type = PROP_PROTREF;
622 prop->flags = 0;
623 prop->u.ref = iter - This->prototype->props;
624 }else {
625 prop = alloc_protref(This, iter->name, iter - This->prototype->props);
626 if(!prop)
627 return E_OUTOFMEMORY;
632 return S_OK;
635 struct typeinfo_func {
636 dispex_prop_t *prop;
637 function_code_t *code;
640 typedef struct {
641 ITypeInfo ITypeInfo_iface;
642 ITypeComp ITypeComp_iface;
643 LONG ref;
645 UINT num_funcs;
646 UINT num_vars;
647 struct typeinfo_func *funcs;
648 dispex_prop_t **vars;
650 jsdisp_t *jsdisp;
651 } ScriptTypeInfo;
653 static struct typeinfo_func *get_func_from_memid(const ScriptTypeInfo *typeinfo, MEMBERID memid)
655 UINT a = 0, b = typeinfo->num_funcs;
657 while (a < b)
659 UINT i = (a + b - 1) / 2;
660 MEMBERID func_memid = prop_to_id(typeinfo->jsdisp, typeinfo->funcs[i].prop);
662 if (memid == func_memid)
663 return &typeinfo->funcs[i];
664 else if (memid < func_memid)
665 b = i;
666 else
667 a = i + 1;
669 return NULL;
672 static dispex_prop_t *get_var_from_memid(const ScriptTypeInfo *typeinfo, MEMBERID memid)
674 UINT a = 0, b = typeinfo->num_vars;
676 while (a < b)
678 UINT i = (a + b - 1) / 2;
679 MEMBERID var_memid = prop_to_id(typeinfo->jsdisp, typeinfo->vars[i]);
681 if (memid == var_memid)
682 return typeinfo->vars[i];
683 else if (memid < var_memid)
684 b = i;
685 else
686 a = i + 1;
688 return NULL;
691 static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeInfo(ITypeInfo *iface)
693 return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeInfo_iface);
696 static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeComp(ITypeComp *iface)
698 return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeComp_iface);
701 static HRESULT WINAPI ScriptTypeInfo_QueryInterface(ITypeInfo *iface, REFIID riid, void **ppv)
703 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
705 if (IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_ITypeInfo, riid))
706 *ppv = &This->ITypeInfo_iface;
707 else if (IsEqualGUID(&IID_ITypeComp, riid))
708 *ppv = &This->ITypeComp_iface;
709 else
711 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
712 *ppv = NULL;
713 return E_NOINTERFACE;
716 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
717 IUnknown_AddRef((IUnknown*)*ppv);
718 return S_OK;
721 static ULONG WINAPI ScriptTypeInfo_AddRef(ITypeInfo *iface)
723 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
724 LONG ref = InterlockedIncrement(&This->ref);
726 TRACE("(%p) ref=%ld\n", This, ref);
728 return ref;
731 static ULONG WINAPI ScriptTypeInfo_Release(ITypeInfo *iface)
733 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
734 LONG ref = InterlockedDecrement(&This->ref);
735 UINT i;
737 TRACE("(%p) ref=%ld\n", This, ref);
739 if (!ref)
741 for (i = This->num_funcs; i--;)
742 release_bytecode(This->funcs[i].code->bytecode);
743 IDispatchEx_Release(&This->jsdisp->IDispatchEx_iface);
744 heap_free(This->funcs);
745 heap_free(This->vars);
746 heap_free(This);
748 return ref;
751 static HRESULT WINAPI ScriptTypeInfo_GetTypeAttr(ITypeInfo *iface, TYPEATTR **ppTypeAttr)
753 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
754 TYPEATTR *attr;
756 TRACE("(%p)->(%p)\n", This, ppTypeAttr);
758 if (!ppTypeAttr) return E_INVALIDARG;
760 attr = heap_alloc_zero(sizeof(*attr));
761 if (!attr) return E_OUTOFMEMORY;
763 attr->guid = GUID_JScriptTypeInfo;
764 attr->lcid = LOCALE_USER_DEFAULT;
765 attr->memidConstructor = MEMBERID_NIL;
766 attr->memidDestructor = MEMBERID_NIL;
767 attr->cbSizeInstance = 4;
768 attr->typekind = TKIND_DISPATCH;
769 attr->cFuncs = This->num_funcs;
770 attr->cVars = This->num_vars;
771 attr->cImplTypes = 1;
772 attr->cbSizeVft = sizeof(IDispatchVtbl);
773 attr->cbAlignment = 4;
774 attr->wTypeFlags = TYPEFLAG_FDISPATCHABLE;
775 attr->wMajorVerNum = JSCRIPT_MAJOR_VERSION;
776 attr->wMinorVerNum = JSCRIPT_MINOR_VERSION;
778 *ppTypeAttr = attr;
779 return S_OK;
782 static HRESULT WINAPI ScriptTypeInfo_GetTypeComp(ITypeInfo *iface, ITypeComp **ppTComp)
784 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
786 TRACE("(%p)->(%p)\n", This, ppTComp);
788 if (!ppTComp) return E_INVALIDARG;
790 *ppTComp = &This->ITypeComp_iface;
791 ITypeInfo_AddRef(iface);
792 return S_OK;
795 static HRESULT WINAPI ScriptTypeInfo_GetFuncDesc(ITypeInfo *iface, UINT index, FUNCDESC **ppFuncDesc)
797 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
798 struct typeinfo_func *func;
799 FUNCDESC *desc;
800 unsigned i;
802 TRACE("(%p)->(%u %p)\n", This, index, ppFuncDesc);
804 if (!ppFuncDesc) return E_INVALIDARG;
805 if (index >= This->num_funcs) return TYPE_E_ELEMENTNOTFOUND;
806 func = &This->funcs[index];
808 /* Store the parameter array after the FUNCDESC structure */
809 desc = heap_alloc_zero(sizeof(*desc) + sizeof(ELEMDESC) * func->code->param_cnt);
810 if (!desc) return E_OUTOFMEMORY;
812 desc->memid = prop_to_id(This->jsdisp, func->prop);
813 desc->funckind = FUNC_DISPATCH;
814 desc->invkind = INVOKE_FUNC;
815 desc->callconv = CC_STDCALL;
816 desc->cParams = func->code->param_cnt;
817 desc->elemdescFunc.tdesc.vt = VT_VARIANT;
819 if (func->code->param_cnt) desc->lprgelemdescParam = (ELEMDESC*)(desc + 1);
820 for (i = 0; i < func->code->param_cnt; i++)
821 desc->lprgelemdescParam[i].tdesc.vt = VT_VARIANT;
823 *ppFuncDesc = desc;
824 return S_OK;
827 static HRESULT WINAPI ScriptTypeInfo_GetVarDesc(ITypeInfo *iface, UINT index, VARDESC **ppVarDesc)
829 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
830 VARDESC *desc;
832 TRACE("(%p)->(%u %p)\n", This, index, ppVarDesc);
834 if (!ppVarDesc) return E_INVALIDARG;
835 if (index >= This->num_vars) return TYPE_E_ELEMENTNOTFOUND;
837 desc = heap_alloc_zero(sizeof(*desc));
838 if (!desc) return E_OUTOFMEMORY;
840 desc->memid = prop_to_id(This->jsdisp, This->vars[index]);
841 desc->varkind = VAR_DISPATCH;
842 desc->elemdescVar.tdesc.vt = VT_VARIANT;
844 *ppVarDesc = desc;
845 return S_OK;
848 static HRESULT WINAPI ScriptTypeInfo_GetNames(ITypeInfo *iface, MEMBERID memid, BSTR *rgBstrNames,
849 UINT cMaxNames, UINT *pcNames)
851 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
852 struct typeinfo_func *func;
853 ITypeInfo *disp_typeinfo;
854 dispex_prop_t *var;
855 HRESULT hr;
856 UINT i = 0;
858 TRACE("(%p)->(%ld %p %u %p)\n", This, memid, rgBstrNames, cMaxNames, pcNames);
860 if (!rgBstrNames || !pcNames) return E_INVALIDARG;
861 if (memid <= 0) return TYPE_E_ELEMENTNOTFOUND;
863 func = get_func_from_memid(This, memid);
864 if (!func)
866 var = get_var_from_memid(This, memid);
867 if (!var)
869 hr = get_dispatch_typeinfo(&disp_typeinfo);
870 if (FAILED(hr)) return hr;
872 return ITypeInfo_GetNames(disp_typeinfo, memid, rgBstrNames, cMaxNames, pcNames);
876 *pcNames = 0;
877 if (!cMaxNames) return S_OK;
879 rgBstrNames[0] = SysAllocString(func ? func->prop->name : var->name);
880 if (!rgBstrNames[0]) return E_OUTOFMEMORY;
881 i++;
883 if (func)
885 unsigned num = min(cMaxNames, func->code->param_cnt + 1);
887 for (; i < num; i++)
889 if (!(rgBstrNames[i] = SysAllocString(func->code->params[i - 1])))
891 do SysFreeString(rgBstrNames[--i]); while (i);
892 return E_OUTOFMEMORY;
897 *pcNames = i;
898 return S_OK;
901 static HRESULT WINAPI ScriptTypeInfo_GetRefTypeOfImplType(ITypeInfo *iface, UINT index, HREFTYPE *pRefType)
903 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
905 TRACE("(%p)->(%u %p)\n", This, index, pRefType);
907 /* We only inherit from IDispatch */
908 if (!pRefType) return E_INVALIDARG;
909 if (index != 0) return TYPE_E_ELEMENTNOTFOUND;
911 *pRefType = 1;
912 return S_OK;
915 static HRESULT WINAPI ScriptTypeInfo_GetImplTypeFlags(ITypeInfo *iface, UINT index, INT *pImplTypeFlags)
917 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
919 TRACE("(%p)->(%u %p)\n", This, index, pImplTypeFlags);
921 if (!pImplTypeFlags) return E_INVALIDARG;
922 if (index != 0) return TYPE_E_ELEMENTNOTFOUND;
924 *pImplTypeFlags = 0;
925 return S_OK;
928 static HRESULT WINAPI ScriptTypeInfo_GetIDsOfNames(ITypeInfo *iface, LPOLESTR *rgszNames, UINT cNames,
929 MEMBERID *pMemId)
931 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
932 ITypeInfo *disp_typeinfo;
933 const WCHAR *name;
934 HRESULT hr = S_OK;
935 int i, j, arg;
937 TRACE("(%p)->(%p %u %p)\n", This, rgszNames, cNames, pMemId);
939 if (!rgszNames || !cNames || !pMemId) return E_INVALIDARG;
941 for (i = 0; i < cNames; i++) pMemId[i] = MEMBERID_NIL;
942 name = rgszNames[0];
944 for (i = 0; i < This->num_funcs; i++)
946 struct typeinfo_func *func = &This->funcs[i];
948 if (wcsicmp(name, func->prop->name)) continue;
949 pMemId[0] = prop_to_id(This->jsdisp, func->prop);
951 for (j = 1; j < cNames; j++)
953 name = rgszNames[j];
954 for (arg = func->code->param_cnt; --arg >= 0;)
955 if (!wcsicmp(name, func->code->params[arg]))
956 break;
957 if (arg >= 0)
958 pMemId[j] = arg;
959 else
960 hr = DISP_E_UNKNOWNNAME;
962 return hr;
965 for (i = 0; i < This->num_vars; i++)
967 dispex_prop_t *var = This->vars[i];
969 if (wcsicmp(name, var->name)) continue;
970 pMemId[0] = prop_to_id(This->jsdisp, var);
971 return S_OK;
974 /* Look into the inherited IDispatch */
975 hr = get_dispatch_typeinfo(&disp_typeinfo);
976 if (FAILED(hr)) return hr;
978 return ITypeInfo_GetIDsOfNames(disp_typeinfo, rgszNames, cNames, pMemId);
981 static HRESULT WINAPI ScriptTypeInfo_Invoke(ITypeInfo *iface, PVOID pvInstance, MEMBERID memid, WORD wFlags,
982 DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
984 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
985 ITypeInfo *disp_typeinfo;
986 IDispatch *disp;
987 HRESULT hr;
989 TRACE("(%p)->(%p %ld %d %p %p %p %p)\n", This, pvInstance, memid, wFlags,
990 pDispParams, pVarResult, pExcepInfo, puArgErr);
992 if (!pvInstance) return E_INVALIDARG;
993 if (memid <= 0) return TYPE_E_ELEMENTNOTFOUND;
995 if (!get_func_from_memid(This, memid) && !get_var_from_memid(This, memid))
997 hr = get_dispatch_typeinfo(&disp_typeinfo);
998 if (FAILED(hr)) return hr;
1000 return ITypeInfo_Invoke(disp_typeinfo, pvInstance, memid, wFlags, pDispParams,
1001 pVarResult, pExcepInfo, puArgErr);
1004 hr = IUnknown_QueryInterface((IUnknown*)pvInstance, &IID_IDispatch, (void**)&disp);
1005 if (FAILED(hr)) return hr;
1007 hr = IDispatch_Invoke(disp, memid, &IID_NULL, LOCALE_USER_DEFAULT, wFlags,
1008 pDispParams, pVarResult, pExcepInfo, puArgErr);
1009 IDispatch_Release(disp);
1011 return hr;
1014 static HRESULT WINAPI ScriptTypeInfo_GetDocumentation(ITypeInfo *iface, MEMBERID memid, BSTR *pBstrName,
1015 BSTR *pBstrDocString, DWORD *pdwHelpContext, BSTR *pBstrHelpFile)
1017 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1018 struct typeinfo_func *func;
1019 ITypeInfo *disp_typeinfo;
1020 dispex_prop_t *var;
1021 HRESULT hr;
1023 TRACE("(%p)->(%ld %p %p %p %p)\n", This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
1025 if (pBstrDocString) *pBstrDocString = NULL;
1026 if (pdwHelpContext) *pdwHelpContext = 0;
1027 if (pBstrHelpFile) *pBstrHelpFile = NULL;
1029 if (memid == MEMBERID_NIL)
1031 if (pBstrName && !(*pBstrName = SysAllocString(L"JScriptTypeInfo")))
1032 return E_OUTOFMEMORY;
1033 if (pBstrDocString &&
1034 !(*pBstrDocString = SysAllocString(L"JScript Type Info")))
1036 if (pBstrName) SysFreeString(*pBstrName);
1037 return E_OUTOFMEMORY;
1039 return S_OK;
1041 if (memid <= 0) return TYPE_E_ELEMENTNOTFOUND;
1043 func = get_func_from_memid(This, memid);
1044 if (!func)
1046 var = get_var_from_memid(This, memid);
1047 if (!var)
1049 hr = get_dispatch_typeinfo(&disp_typeinfo);
1050 if (FAILED(hr)) return hr;
1052 return ITypeInfo_GetDocumentation(disp_typeinfo, memid, pBstrName, pBstrDocString,
1053 pdwHelpContext, pBstrHelpFile);
1057 if (pBstrName)
1059 *pBstrName = SysAllocString(func ? func->prop->name : var->name);
1061 if (!*pBstrName)
1062 return E_OUTOFMEMORY;
1064 return S_OK;
1067 static HRESULT WINAPI ScriptTypeInfo_GetDllEntry(ITypeInfo *iface, MEMBERID memid, INVOKEKIND invKind,
1068 BSTR *pBstrDllName, BSTR *pBstrName, WORD *pwOrdinal)
1070 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1071 ITypeInfo *disp_typeinfo;
1072 HRESULT hr;
1074 TRACE("(%p)->(%ld %d %p %p %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
1076 if (pBstrDllName) *pBstrDllName = NULL;
1077 if (pBstrName) *pBstrName = NULL;
1078 if (pwOrdinal) *pwOrdinal = 0;
1080 if (!get_func_from_memid(This, memid) && !get_var_from_memid(This, memid))
1082 hr = get_dispatch_typeinfo(&disp_typeinfo);
1083 if (FAILED(hr)) return hr;
1085 return ITypeInfo_GetDllEntry(disp_typeinfo, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
1087 return TYPE_E_BADMODULEKIND;
1090 static HRESULT WINAPI ScriptTypeInfo_GetRefTypeInfo(ITypeInfo *iface, HREFTYPE hRefType, ITypeInfo **ppTInfo)
1092 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1093 HRESULT hr;
1095 TRACE("(%p)->(%lx %p)\n", This, hRefType, ppTInfo);
1097 if (!ppTInfo || (INT)hRefType < 0) return E_INVALIDARG;
1099 if (hRefType & ~3) return E_FAIL;
1100 if (hRefType & 1)
1102 hr = get_dispatch_typeinfo(ppTInfo);
1103 if (FAILED(hr)) return hr;
1105 else
1106 *ppTInfo = iface;
1108 ITypeInfo_AddRef(*ppTInfo);
1109 return S_OK;
1112 static HRESULT WINAPI ScriptTypeInfo_AddressOfMember(ITypeInfo *iface, MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
1114 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1115 ITypeInfo *disp_typeinfo;
1116 HRESULT hr;
1118 TRACE("(%p)->(%ld %d %p)\n", This, memid, invKind, ppv);
1120 if (!ppv) return E_INVALIDARG;
1121 *ppv = NULL;
1123 if (!get_func_from_memid(This, memid) && !get_var_from_memid(This, memid))
1125 hr = get_dispatch_typeinfo(&disp_typeinfo);
1126 if (FAILED(hr)) return hr;
1128 return ITypeInfo_AddressOfMember(disp_typeinfo, memid, invKind, ppv);
1130 return TYPE_E_BADMODULEKIND;
1133 static HRESULT WINAPI ScriptTypeInfo_CreateInstance(ITypeInfo *iface, IUnknown *pUnkOuter, REFIID riid, PVOID *ppvObj)
1135 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1137 TRACE("(%p)->(%p %s %p)\n", This, pUnkOuter, debugstr_guid(riid), ppvObj);
1139 if (!ppvObj) return E_INVALIDARG;
1141 *ppvObj = NULL;
1142 return TYPE_E_BADMODULEKIND;
1145 static HRESULT WINAPI ScriptTypeInfo_GetMops(ITypeInfo *iface, MEMBERID memid, BSTR *pBstrMops)
1147 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1148 ITypeInfo *disp_typeinfo;
1149 HRESULT hr;
1151 TRACE("(%p)->(%ld %p)\n", This, memid, pBstrMops);
1153 if (!pBstrMops) return E_INVALIDARG;
1155 if (!get_func_from_memid(This, memid) && !get_var_from_memid(This, memid))
1157 hr = get_dispatch_typeinfo(&disp_typeinfo);
1158 if (FAILED(hr)) return hr;
1160 return ITypeInfo_GetMops(disp_typeinfo, memid, pBstrMops);
1163 *pBstrMops = NULL;
1164 return S_OK;
1167 static HRESULT WINAPI ScriptTypeInfo_GetContainingTypeLib(ITypeInfo *iface, ITypeLib **ppTLib, UINT *pIndex)
1169 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1171 FIXME("(%p)->(%p %p)\n", This, ppTLib, pIndex);
1173 return E_NOTIMPL;
1176 static void WINAPI ScriptTypeInfo_ReleaseTypeAttr(ITypeInfo *iface, TYPEATTR *pTypeAttr)
1178 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1180 TRACE("(%p)->(%p)\n", This, pTypeAttr);
1182 heap_free(pTypeAttr);
1185 static void WINAPI ScriptTypeInfo_ReleaseFuncDesc(ITypeInfo *iface, FUNCDESC *pFuncDesc)
1187 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1189 TRACE("(%p)->(%p)\n", This, pFuncDesc);
1191 heap_free(pFuncDesc);
1194 static void WINAPI ScriptTypeInfo_ReleaseVarDesc(ITypeInfo *iface, VARDESC *pVarDesc)
1196 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1198 TRACE("(%p)->(%p)\n", This, pVarDesc);
1200 heap_free(pVarDesc);
1203 static const ITypeInfoVtbl ScriptTypeInfoVtbl = {
1204 ScriptTypeInfo_QueryInterface,
1205 ScriptTypeInfo_AddRef,
1206 ScriptTypeInfo_Release,
1207 ScriptTypeInfo_GetTypeAttr,
1208 ScriptTypeInfo_GetTypeComp,
1209 ScriptTypeInfo_GetFuncDesc,
1210 ScriptTypeInfo_GetVarDesc,
1211 ScriptTypeInfo_GetNames,
1212 ScriptTypeInfo_GetRefTypeOfImplType,
1213 ScriptTypeInfo_GetImplTypeFlags,
1214 ScriptTypeInfo_GetIDsOfNames,
1215 ScriptTypeInfo_Invoke,
1216 ScriptTypeInfo_GetDocumentation,
1217 ScriptTypeInfo_GetDllEntry,
1218 ScriptTypeInfo_GetRefTypeInfo,
1219 ScriptTypeInfo_AddressOfMember,
1220 ScriptTypeInfo_CreateInstance,
1221 ScriptTypeInfo_GetMops,
1222 ScriptTypeInfo_GetContainingTypeLib,
1223 ScriptTypeInfo_ReleaseTypeAttr,
1224 ScriptTypeInfo_ReleaseFuncDesc,
1225 ScriptTypeInfo_ReleaseVarDesc
1228 static HRESULT WINAPI ScriptTypeComp_QueryInterface(ITypeComp *iface, REFIID riid, void **ppv)
1230 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1231 return ITypeInfo_QueryInterface(&This->ITypeInfo_iface, riid, ppv);
1234 static ULONG WINAPI ScriptTypeComp_AddRef(ITypeComp *iface)
1236 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1237 return ITypeInfo_AddRef(&This->ITypeInfo_iface);
1240 static ULONG WINAPI ScriptTypeComp_Release(ITypeComp *iface)
1242 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1243 return ITypeInfo_Release(&This->ITypeInfo_iface);
1246 static HRESULT WINAPI ScriptTypeComp_Bind(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal, WORD wFlags,
1247 ITypeInfo **ppTInfo, DESCKIND *pDescKind, BINDPTR *pBindPtr)
1249 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1250 UINT flags = wFlags ? wFlags : ~0;
1251 ITypeInfo *disp_typeinfo;
1252 ITypeComp *disp_typecomp;
1253 HRESULT hr;
1254 UINT i;
1256 TRACE("(%p)->(%s %08lx %d %p %p %p)\n", This, debugstr_w(szName), lHashVal,
1257 wFlags, ppTInfo, pDescKind, pBindPtr);
1259 if (!szName || !ppTInfo || !pDescKind || !pBindPtr)
1260 return E_INVALIDARG;
1262 for (i = 0; i < This->num_funcs; i++)
1264 if (wcsicmp(szName, This->funcs[i].prop->name)) continue;
1265 if (!(flags & INVOKE_FUNC)) return TYPE_E_TYPEMISMATCH;
1267 hr = ITypeInfo_GetFuncDesc(&This->ITypeInfo_iface, i, &pBindPtr->lpfuncdesc);
1268 if (FAILED(hr)) return hr;
1270 *pDescKind = DESCKIND_FUNCDESC;
1271 *ppTInfo = &This->ITypeInfo_iface;
1272 ITypeInfo_AddRef(*ppTInfo);
1273 return S_OK;
1276 for (i = 0; i < This->num_vars; i++)
1278 if (wcsicmp(szName, This->vars[i]->name)) continue;
1279 if (!(flags & INVOKE_PROPERTYGET)) return TYPE_E_TYPEMISMATCH;
1281 hr = ITypeInfo_GetVarDesc(&This->ITypeInfo_iface, i, &pBindPtr->lpvardesc);
1282 if (FAILED(hr)) return hr;
1284 *pDescKind = DESCKIND_VARDESC;
1285 *ppTInfo = &This->ITypeInfo_iface;
1286 ITypeInfo_AddRef(*ppTInfo);
1287 return S_OK;
1290 /* Look into the inherited IDispatch */
1291 hr = get_dispatch_typeinfo(&disp_typeinfo);
1292 if (FAILED(hr)) return hr;
1294 hr = ITypeInfo_GetTypeComp(disp_typeinfo, &disp_typecomp);
1295 if (FAILED(hr)) return hr;
1297 hr = ITypeComp_Bind(disp_typecomp, szName, lHashVal, wFlags, ppTInfo, pDescKind, pBindPtr);
1298 ITypeComp_Release(disp_typecomp);
1299 return hr;
1302 static HRESULT WINAPI ScriptTypeComp_BindType(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal,
1303 ITypeInfo **ppTInfo, ITypeComp **ppTComp)
1305 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1306 ITypeInfo *disp_typeinfo;
1307 ITypeComp *disp_typecomp;
1308 HRESULT hr;
1310 TRACE("(%p)->(%s %08lx %p %p)\n", This, debugstr_w(szName), lHashVal, ppTInfo, ppTComp);
1312 if (!szName || !ppTInfo || !ppTComp)
1313 return E_INVALIDARG;
1315 /* Look into the inherited IDispatch */
1316 hr = get_dispatch_typeinfo(&disp_typeinfo);
1317 if (FAILED(hr)) return hr;
1319 hr = ITypeInfo_GetTypeComp(disp_typeinfo, &disp_typecomp);
1320 if (FAILED(hr)) return hr;
1322 hr = ITypeComp_BindType(disp_typecomp, szName, lHashVal, ppTInfo, ppTComp);
1323 ITypeComp_Release(disp_typecomp);
1324 return hr;
1327 static const ITypeCompVtbl ScriptTypeCompVtbl = {
1328 ScriptTypeComp_QueryInterface,
1329 ScriptTypeComp_AddRef,
1330 ScriptTypeComp_Release,
1331 ScriptTypeComp_Bind,
1332 ScriptTypeComp_BindType
1335 static inline jsdisp_t *impl_from_IDispatchEx(IDispatchEx *iface)
1337 return CONTAINING_RECORD(iface, jsdisp_t, IDispatchEx_iface);
1340 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
1342 jsdisp_t *This = impl_from_IDispatchEx(iface);
1344 if(IsEqualGUID(&IID_IUnknown, riid)) {
1345 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
1346 *ppv = &This->IDispatchEx_iface;
1347 }else if(IsEqualGUID(&IID_IDispatch, riid)) {
1348 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
1349 *ppv = &This->IDispatchEx_iface;
1350 }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
1351 TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
1352 *ppv = &This->IDispatchEx_iface;
1353 }else {
1354 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
1355 *ppv = NULL;
1356 return E_NOINTERFACE;
1359 jsdisp_addref(This);
1360 return S_OK;
1363 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
1365 jsdisp_t *This = impl_from_IDispatchEx(iface);
1366 jsdisp_addref(This);
1367 return This->ref;
1370 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
1372 jsdisp_t *This = impl_from_IDispatchEx(iface);
1373 ULONG ref = --This->ref;
1374 TRACE("(%p) ref=%ld\n", This, ref);
1375 if(!ref)
1376 jsdisp_free(This);
1377 return ref;
1380 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
1382 jsdisp_t *This = impl_from_IDispatchEx(iface);
1384 TRACE("(%p)->(%p)\n", This, pctinfo);
1386 *pctinfo = 1;
1387 return S_OK;
1390 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid,
1391 ITypeInfo **ppTInfo)
1393 jsdisp_t *This = impl_from_IDispatchEx(iface);
1394 dispex_prop_t *prop, *cur, *end, **typevar;
1395 UINT num_funcs = 0, num_vars = 0;
1396 struct typeinfo_func *typefunc;
1397 function_code_t *func_code;
1398 ScriptTypeInfo *typeinfo;
1399 unsigned pos;
1401 TRACE("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ppTInfo);
1403 if (iTInfo != 0) return DISP_E_BADINDEX;
1405 for (prop = This->props, end = prop + This->prop_cnt; prop != end; prop++)
1407 if (prop->type != PROP_JSVAL || !(prop->flags & PROPF_ENUMERABLE))
1408 continue;
1410 /* If two identifiers differ only by case, the TypeInfo fails */
1411 pos = This->props[get_props_idx(This, prop->hash)].bucket_head;
1412 while (pos != ~0)
1414 cur = This->props + pos;
1416 if (prop->hash == cur->hash && prop != cur &&
1417 cur->type == PROP_JSVAL && (cur->flags & PROPF_ENUMERABLE) &&
1418 !wcsicmp(prop->name, cur->name))
1420 return TYPE_E_AMBIGUOUSNAME;
1422 pos = cur->bucket_next;
1425 if (is_function_prop(prop))
1427 if (Function_get_code(as_jsdisp(get_object(prop->u.val))))
1428 num_funcs++;
1430 else num_vars++;
1433 if (!(typeinfo = heap_alloc(sizeof(*typeinfo))))
1434 return E_OUTOFMEMORY;
1436 typeinfo->ITypeInfo_iface.lpVtbl = &ScriptTypeInfoVtbl;
1437 typeinfo->ITypeComp_iface.lpVtbl = &ScriptTypeCompVtbl;
1438 typeinfo->ref = 1;
1439 typeinfo->num_vars = num_vars;
1440 typeinfo->num_funcs = num_funcs;
1441 typeinfo->jsdisp = This;
1443 typeinfo->funcs = heap_alloc(sizeof(*typeinfo->funcs) * num_funcs);
1444 if (!typeinfo->funcs)
1446 heap_free(typeinfo);
1447 return E_OUTOFMEMORY;
1450 typeinfo->vars = heap_alloc(sizeof(*typeinfo->vars) * num_vars);
1451 if (!typeinfo->vars)
1453 heap_free(typeinfo->funcs);
1454 heap_free(typeinfo);
1455 return E_OUTOFMEMORY;
1458 typefunc = typeinfo->funcs;
1459 typevar = typeinfo->vars;
1460 for (prop = This->props; prop != end; prop++)
1462 if (prop->type != PROP_JSVAL || !(prop->flags & PROPF_ENUMERABLE))
1463 continue;
1465 if (is_function_prop(prop))
1467 func_code = Function_get_code(as_jsdisp(get_object(prop->u.val)));
1468 if (!func_code) continue;
1470 typefunc->prop = prop;
1471 typefunc->code = func_code;
1472 typefunc++;
1474 /* The function may be deleted, so keep a ref */
1475 bytecode_addref(func_code->bytecode);
1477 else
1478 *typevar++ = prop;
1481 /* Keep a ref to the props and their names */
1482 IDispatchEx_AddRef(&This->IDispatchEx_iface);
1484 *ppTInfo = &typeinfo->ITypeInfo_iface;
1485 return S_OK;
1488 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
1489 LPOLESTR *rgszNames, UINT cNames, LCID lcid,
1490 DISPID *rgDispId)
1492 jsdisp_t *This = impl_from_IDispatchEx(iface);
1493 UINT i;
1494 HRESULT hres;
1496 TRACE("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1497 lcid, rgDispId);
1499 if(cNames == 0)
1500 return S_OK;
1502 hres = jsdisp_get_id(This, rgszNames[0], 0, rgDispId);
1503 if(FAILED(hres))
1504 return hres;
1506 /* DISPIDs for parameters don't seem to be supported */
1507 if(cNames > 1) {
1508 for(i = 1; i < cNames; i++)
1509 rgDispId[i] = DISPID_UNKNOWN;
1510 hres = DISP_E_UNKNOWNNAME;
1513 return hres;
1516 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
1517 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
1518 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1520 jsdisp_t *This = impl_from_IDispatchEx(iface);
1522 TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1523 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1525 return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags,
1526 pDispParams, pVarResult, pExcepInfo, NULL);
1529 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
1531 jsdisp_t *This = impl_from_IDispatchEx(iface);
1533 TRACE("(%p)->(%s %lx %p)\n", This, debugstr_w(bstrName), grfdex, pid);
1535 if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) {
1536 FIXME("Unsupported grfdex %lx\n", grfdex);
1537 return E_NOTIMPL;
1540 return jsdisp_get_id(This, bstrName, grfdex, pid);
1543 static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
1544 VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
1546 jsdisp_t *This = impl_from_IDispatchEx(iface);
1547 dispex_prop_t *prop;
1548 jsexcept_t ei;
1549 HRESULT hres;
1551 TRACE("(%p)->(%lx %lx %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
1553 if(pvarRes)
1554 V_VT(pvarRes) = VT_EMPTY;
1556 prop = get_prop(This, id);
1557 if(!prop && id != DISPID_VALUE) {
1558 TRACE("invalid id\n");
1559 return DISP_E_MEMBERNOTFOUND;
1562 enter_script(This->ctx, &ei);
1564 switch(wFlags) {
1565 case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
1566 wFlags = DISPATCH_METHOD;
1567 /* fall through */
1568 case DISPATCH_METHOD:
1569 case DISPATCH_CONSTRUCT: {
1570 jsval_t *argv, buf[6], r;
1571 unsigned argc;
1573 hres = convert_params(This->ctx, pdp, buf, &argc, &argv);
1574 if(FAILED(hres))
1575 break;
1577 if(prop)
1578 hres = invoke_prop_func(This, get_this(pdp), prop, wFlags, argc, argv, pvarRes ? &r : NULL, pspCaller);
1579 else
1580 hres = jsdisp_call_value(This, get_this(pdp), wFlags, argc, argv, pvarRes ? &r : NULL);
1582 if(argv != buf)
1583 heap_free(argv);
1584 if(SUCCEEDED(hres) && pvarRes) {
1585 hres = jsval_to_variant(r, pvarRes);
1586 jsval_release(r);
1588 break;
1590 case DISPATCH_PROPERTYGET: {
1591 jsval_t r;
1593 if(prop)
1594 hres = prop_get(This, prop, &r);
1595 else {
1596 hres = to_primitive(This->ctx, jsval_obj(This), &r, NO_HINT);
1597 if(hres == JS_E_TO_PRIMITIVE)
1598 hres = DISP_E_MEMBERNOTFOUND;
1601 if(SUCCEEDED(hres)) {
1602 hres = jsval_to_variant(r, pvarRes);
1603 jsval_release(r);
1605 break;
1607 case DISPATCH_PROPERTYPUTREF | DISPATCH_PROPERTYPUT:
1608 case DISPATCH_PROPERTYPUTREF:
1609 case DISPATCH_PROPERTYPUT: {
1610 jsval_t val;
1611 DWORD i;
1613 if(!prop) {
1614 hres = DISP_E_MEMBERNOTFOUND;
1615 break;
1618 for(i=0; i < pdp->cNamedArgs; i++) {
1619 if(pdp->rgdispidNamedArgs[i] == DISPID_PROPERTYPUT)
1620 break;
1623 if(i == pdp->cNamedArgs) {
1624 TRACE("no value to set\n");
1625 hres = DISP_E_PARAMNOTOPTIONAL;
1626 break;
1629 hres = variant_to_jsval(This->ctx, pdp->rgvarg+i, &val);
1630 if(FAILED(hres))
1631 break;
1633 hres = prop_put(This, prop, val);
1634 jsval_release(val);
1635 break;
1637 default:
1638 FIXME("Unimplemented flags %x\n", wFlags);
1639 hres = E_INVALIDARG;
1640 break;
1643 return leave_script(This->ctx, hres);
1646 static HRESULT delete_prop(dispex_prop_t *prop, BOOL *ret)
1648 if(prop->type == PROP_PROTREF) {
1649 *ret = TRUE;
1650 return S_OK;
1653 if(!(prop->flags & PROPF_CONFIGURABLE)) {
1654 *ret = FALSE;
1655 return S_OK;
1658 *ret = TRUE;
1660 if(prop->type == PROP_JSVAL)
1661 jsval_release(prop->u.val);
1662 if(prop->type == PROP_ACCESSOR) {
1663 if(prop->u.accessor.getter)
1664 jsdisp_release(prop->u.accessor.getter);
1665 if(prop->u.accessor.setter)
1666 jsdisp_release(prop->u.accessor.setter);
1668 prop->type = PROP_DELETED;
1669 return S_OK;
1672 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
1674 jsdisp_t *This = impl_from_IDispatchEx(iface);
1675 dispex_prop_t *prop;
1676 BOOL b;
1677 HRESULT hres;
1679 TRACE("(%p)->(%s %lx)\n", This, debugstr_w(bstrName), grfdex);
1681 if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK))
1682 FIXME("Unsupported grfdex %lx\n", grfdex);
1684 hres = find_prop_name(This, string_hash(bstrName), bstrName, &prop);
1685 if(FAILED(hres))
1686 return hres;
1687 if(!prop) {
1688 TRACE("not found\n");
1689 return S_OK;
1692 return delete_prop(prop, &b);
1695 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
1697 jsdisp_t *This = impl_from_IDispatchEx(iface);
1698 dispex_prop_t *prop;
1699 BOOL b;
1701 TRACE("(%p)->(%lx)\n", This, id);
1703 prop = get_prop(This, id);
1704 if(!prop) {
1705 WARN("invalid id\n");
1706 return DISP_E_MEMBERNOTFOUND;
1709 return delete_prop(prop, &b);
1712 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
1714 jsdisp_t *This = impl_from_IDispatchEx(iface);
1715 FIXME("(%p)->(%lx %lx %p)\n", This, id, grfdexFetch, pgrfdex);
1716 return E_NOTIMPL;
1719 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
1721 jsdisp_t *This = impl_from_IDispatchEx(iface);
1722 dispex_prop_t *prop;
1724 TRACE("(%p)->(%lx %p)\n", This, id, pbstrName);
1726 prop = get_prop(This, id);
1727 if(!prop)
1728 return DISP_E_MEMBERNOTFOUND;
1730 *pbstrName = SysAllocString(prop->name);
1731 if(!*pbstrName)
1732 return E_OUTOFMEMORY;
1734 return S_OK;
1737 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
1739 jsdisp_t *This = impl_from_IDispatchEx(iface);
1740 HRESULT hres = S_FALSE;
1742 TRACE("(%p)->(%lx %lx %p)\n", This, grfdex, id, pid);
1744 if(id != DISPID_VALUE)
1745 hres = jsdisp_next_prop(This, id, JSDISP_ENUM_ALL, pid);
1746 if(hres == S_FALSE)
1747 *pid = DISPID_STARTENUM;
1748 return hres;
1751 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
1753 jsdisp_t *This = impl_from_IDispatchEx(iface);
1754 FIXME("(%p)->(%p)\n", This, ppunk);
1755 return E_NOTIMPL;
1758 static IDispatchExVtbl DispatchExVtbl = {
1759 DispatchEx_QueryInterface,
1760 DispatchEx_AddRef,
1761 DispatchEx_Release,
1762 DispatchEx_GetTypeInfoCount,
1763 DispatchEx_GetTypeInfo,
1764 DispatchEx_GetIDsOfNames,
1765 DispatchEx_Invoke,
1766 DispatchEx_GetDispID,
1767 DispatchEx_InvokeEx,
1768 DispatchEx_DeleteMemberByName,
1769 DispatchEx_DeleteMemberByDispID,
1770 DispatchEx_GetMemberProperties,
1771 DispatchEx_GetMemberName,
1772 DispatchEx_GetNextDispID,
1773 DispatchEx_GetNameSpaceParent
1776 jsdisp_t *as_jsdisp(IDispatch *disp)
1778 assert(disp->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl);
1779 return impl_from_IDispatchEx((IDispatchEx*)disp);
1782 jsdisp_t *to_jsdisp(IDispatch *disp)
1784 return disp->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl ? impl_from_IDispatchEx((IDispatchEx*)disp) : NULL;
1787 HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype)
1789 unsigned i;
1791 TRACE("%p (%p)\n", dispex, prototype);
1793 dispex->IDispatchEx_iface.lpVtbl = &DispatchExVtbl;
1794 dispex->ref = 1;
1795 dispex->builtin_info = builtin_info;
1796 dispex->extensible = TRUE;
1797 dispex->prop_cnt = 0;
1799 dispex->props = heap_alloc_zero(sizeof(dispex_prop_t)*(dispex->buf_size=4));
1800 if(!dispex->props)
1801 return E_OUTOFMEMORY;
1803 for(i = 0; i < dispex->buf_size; i++) {
1804 dispex->props[i].bucket_head = ~0;
1805 dispex->props[i].bucket_next = ~0;
1808 dispex->prototype = prototype;
1809 if(prototype)
1810 jsdisp_addref(prototype);
1812 script_addref(ctx);
1813 dispex->ctx = ctx;
1815 return S_OK;
1818 static const builtin_info_t dispex_info = {
1819 JSCLASS_NONE,
1820 NULL,
1821 0, NULL,
1822 NULL,
1823 NULL
1826 HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype, jsdisp_t **dispex)
1828 jsdisp_t *ret;
1829 HRESULT hres;
1831 ret = heap_alloc_zero(sizeof(jsdisp_t));
1832 if(!ret)
1833 return E_OUTOFMEMORY;
1835 hres = init_dispex(ret, ctx, builtin_info ? builtin_info : &dispex_info, prototype);
1836 if(FAILED(hres)) {
1837 heap_free(ret);
1838 return hres;
1841 *dispex = ret;
1842 return S_OK;
1845 void jsdisp_free(jsdisp_t *obj)
1847 dispex_prop_t *prop;
1849 TRACE("(%p)\n", obj);
1851 for(prop = obj->props; prop < obj->props+obj->prop_cnt; prop++) {
1852 switch(prop->type) {
1853 case PROP_JSVAL:
1854 jsval_release(prop->u.val);
1855 break;
1856 case PROP_ACCESSOR:
1857 if(prop->u.accessor.getter)
1858 jsdisp_release(prop->u.accessor.getter);
1859 if(prop->u.accessor.setter)
1860 jsdisp_release(prop->u.accessor.setter);
1861 break;
1862 default:
1863 break;
1865 heap_free(prop->name);
1867 heap_free(obj->props);
1868 script_release(obj->ctx);
1869 if(obj->prototype)
1870 jsdisp_release(obj->prototype);
1872 if(obj->builtin_info->destructor)
1873 obj->builtin_info->destructor(obj);
1874 else
1875 heap_free(obj);
1878 #ifdef TRACE_REFCNT
1880 jsdisp_t *jsdisp_addref(jsdisp_t *jsdisp)
1882 ULONG ref = ++jsdisp->ref;
1883 TRACE("(%p) ref=%d\n", jsdisp, ref);
1884 return jsdisp;
1887 void jsdisp_release(jsdisp_t *jsdisp)
1889 ULONG ref = --jsdisp->ref;
1891 TRACE("(%p) ref=%d\n", jsdisp, ref);
1893 if(!ref)
1894 jsdisp_free(jsdisp);
1897 #endif
1899 HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *constr)
1901 jsdisp_t *prot = NULL;
1902 dispex_prop_t *prop;
1903 HRESULT hres;
1905 hres = find_prop_name_prot(constr, string_hash(L"prototype"), L"prototype", &prop);
1906 if(SUCCEEDED(hres) && prop && prop->type!=PROP_DELETED) {
1907 jsval_t val;
1909 hres = prop_get(constr, prop, &val);
1910 if(FAILED(hres)) {
1911 ERR("Could not get prototype\n");
1912 return hres;
1915 if(is_object_instance(val))
1916 prot = iface_to_jsdisp(get_object(val));
1917 else
1918 prot = jsdisp_addref(ctx->object_prototype);
1920 jsval_release(val);
1923 hres = init_dispex(dispex, ctx, builtin_info, prot);
1925 if(prot)
1926 jsdisp_release(prot);
1927 return hres;
1930 jsdisp_t *iface_to_jsdisp(IDispatch *iface)
1932 return iface->lpVtbl == (const IDispatchVtbl*)&DispatchExVtbl
1933 ? jsdisp_addref( impl_from_IDispatchEx((IDispatchEx*)iface))
1934 : NULL;
1937 HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID *id)
1939 dispex_prop_t *prop;
1940 HRESULT hres;
1942 if(jsdisp->extensible && (flags & fdexNameEnsure))
1943 hres = ensure_prop_name(jsdisp, name, PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE,
1944 &prop);
1945 else
1946 hres = find_prop_name_prot(jsdisp, string_hash(name), name, &prop);
1947 if(FAILED(hres))
1948 return hres;
1950 if(prop && prop->type!=PROP_DELETED) {
1951 *id = prop_to_id(jsdisp, prop);
1952 return S_OK;
1955 TRACE("not found %s\n", debugstr_w(name));
1956 *id = DISPID_UNKNOWN;
1957 return DISP_E_UNKNOWNNAME;
1960 HRESULT jsdisp_call_value(jsdisp_t *jsfunc, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1962 HRESULT hres;
1964 assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT|DISPATCH_JSCRIPT_INTERNAL_MASK)));
1966 if(is_class(jsfunc, JSCLASS_FUNCTION)) {
1967 hres = Function_invoke(jsfunc, jsthis, flags, argc, argv, r);
1968 }else {
1969 if(!jsfunc->builtin_info->call) {
1970 WARN("Not a function\n");
1971 return JS_E_FUNCTION_EXPECTED;
1974 if(jsfunc->ctx->state == SCRIPTSTATE_UNINITIALIZED || jsfunc->ctx->state == SCRIPTSTATE_CLOSED)
1975 return E_UNEXPECTED;
1977 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
1978 hres = jsfunc->builtin_info->call(jsfunc->ctx, jsthis ? jsval_disp(jsthis) : jsval_null(), flags, argc, argv, r);
1980 return hres;
1983 HRESULT jsdisp_call(jsdisp_t *disp, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1985 dispex_prop_t *prop;
1987 prop = get_prop(disp, id);
1988 if(!prop)
1989 return DISP_E_MEMBERNOTFOUND;
1991 return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, NULL);
1994 HRESULT jsdisp_call_name(jsdisp_t *disp, const WCHAR *name, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1996 dispex_prop_t *prop;
1997 HRESULT hres;
1999 hres = find_prop_name_prot(disp, string_hash(name), name, &prop);
2000 if(FAILED(hres))
2001 return hres;
2003 if(!prop || prop->type == PROP_DELETED)
2004 return JS_E_INVALID_PROPERTY;
2006 return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, NULL);
2009 static HRESULT disp_invoke(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, DISPPARAMS *params, VARIANT *r)
2011 IDispatchEx *dispex;
2012 EXCEPINFO ei;
2013 HRESULT hres;
2015 memset(&ei, 0, sizeof(ei));
2016 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
2017 if(SUCCEEDED(hres)) {
2018 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, params, r, &ei, &ctx->jscaller->IServiceProvider_iface);
2019 IDispatchEx_Release(dispex);
2020 }else {
2021 UINT err = 0;
2023 if(flags == DISPATCH_CONSTRUCT) {
2024 WARN("IDispatch cannot be constructor\n");
2025 return DISP_E_MEMBERNOTFOUND;
2028 if(params->cNamedArgs == 1 && params->rgdispidNamedArgs[0] == DISPID_THIS) {
2029 params->cNamedArgs = 0;
2030 params->rgdispidNamedArgs = NULL;
2031 params->cArgs--;
2032 params->rgvarg++;
2035 TRACE("using IDispatch\n");
2036 hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, params, r, &ei, &err);
2039 if(hres == DISP_E_EXCEPTION) {
2040 TRACE("DISP_E_EXCEPTION: %08lx %s %s\n", ei.scode, debugstr_w(ei.bstrSource), debugstr_w(ei.bstrDescription));
2041 reset_ei(ctx->ei);
2042 ctx->ei->error = (SUCCEEDED(ei.scode) || ei.scode == DISP_E_EXCEPTION) ? E_FAIL : ei.scode;
2043 if(ei.bstrSource)
2044 ctx->ei->source = jsstr_alloc_len(ei.bstrSource, SysStringLen(ei.bstrSource));
2045 if(ei.bstrDescription)
2046 ctx->ei->message = jsstr_alloc_len(ei.bstrDescription, SysStringLen(ei.bstrDescription));
2047 SysFreeString(ei.bstrSource);
2048 SysFreeString(ei.bstrDescription);
2049 SysFreeString(ei.bstrHelpFile);
2052 return hres;
2055 HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *ret)
2057 VARIANT buf[6], retv;
2058 jsdisp_t *jsdisp;
2059 DISPPARAMS dp;
2060 unsigned i;
2061 HRESULT hres;
2063 jsdisp = iface_to_jsdisp(disp);
2064 if(jsdisp && jsdisp->ctx == ctx) {
2065 if(flags & DISPATCH_PROPERTYPUT) {
2066 FIXME("disp_call(propput) on builtin object\n");
2067 jsdisp_release(jsdisp);
2068 return E_FAIL;
2071 if(ctx != jsdisp->ctx)
2072 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
2073 hres = jsdisp_call(jsdisp, id, flags, argc, argv, ret);
2074 jsdisp_release(jsdisp);
2075 return hres;
2077 if(jsdisp)
2078 jsdisp_release(jsdisp);
2080 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
2081 if(ret && argc)
2082 flags |= DISPATCH_PROPERTYGET;
2084 dp.cArgs = argc;
2086 if(flags & DISPATCH_PROPERTYPUT) {
2087 static DISPID propput_dispid = DISPID_PROPERTYPUT;
2089 dp.cNamedArgs = 1;
2090 dp.rgdispidNamedArgs = &propput_dispid;
2091 }else {
2092 dp.cNamedArgs = 0;
2093 dp.rgdispidNamedArgs = NULL;
2096 if(dp.cArgs > ARRAY_SIZE(buf)) {
2097 dp.rgvarg = heap_alloc(argc*sizeof(VARIANT));
2098 if(!dp.rgvarg)
2099 return E_OUTOFMEMORY;
2100 }else {
2101 dp.rgvarg = buf;
2104 for(i=0; i<argc; i++) {
2105 hres = jsval_to_variant(argv[i], dp.rgvarg+argc-i-1);
2106 if(FAILED(hres)) {
2107 while(i--)
2108 VariantClear(dp.rgvarg+argc-i-1);
2109 if(dp.rgvarg != buf)
2110 heap_free(dp.rgvarg);
2111 return hres;
2115 V_VT(&retv) = VT_EMPTY;
2116 hres = disp_invoke(ctx, disp, id, flags, &dp, ret ? &retv : NULL);
2118 for(i=0; i<argc; i++)
2119 VariantClear(dp.rgvarg+argc-i-1);
2120 if(dp.rgvarg != buf)
2121 heap_free(dp.rgvarg);
2123 if(SUCCEEDED(hres) && ret)
2124 hres = variant_to_jsval(ctx, &retv, ret);
2125 VariantClear(&retv);
2126 return hres;
2129 HRESULT disp_call_name(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name, WORD flags, unsigned argc, jsval_t *argv, jsval_t *ret)
2131 IDispatchEx *dispex;
2132 jsdisp_t *jsdisp;
2133 HRESULT hres;
2134 DISPID id;
2135 BSTR bstr;
2137 if((jsdisp = to_jsdisp(disp)) && jsdisp->ctx == ctx)
2138 return jsdisp_call_name(jsdisp, name, flags, argc, argv, ret);
2140 if(!(bstr = SysAllocString(name)))
2141 return E_OUTOFMEMORY;
2142 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
2143 if(SUCCEEDED(hres) && dispex) {
2144 hres = IDispatchEx_GetDispID(dispex, bstr, make_grfdex(ctx, fdexNameCaseSensitive), &id);
2145 IDispatchEx_Release(dispex);
2146 }else {
2147 hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, &id);
2149 SysFreeString(bstr);
2150 if(FAILED(hres))
2151 return hres;
2153 return disp_call(ctx, disp, id, flags, argc, argv, ret);
2156 HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2157 jsval_t *r)
2159 VARIANT buf[6], retv, *args = buf;
2160 jsdisp_t *jsdisp;
2161 DISPPARAMS dp;
2162 unsigned i;
2163 HRESULT hres = S_OK;
2165 static DISPID this_id = DISPID_THIS;
2167 assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT|DISPATCH_JSCRIPT_INTERNAL_MASK)));
2169 jsdisp = iface_to_jsdisp(disp);
2170 if(jsdisp && jsdisp->ctx == ctx) {
2171 hres = jsdisp_call_value(jsdisp, jsthis, flags, argc, argv, r);
2172 jsdisp_release(jsdisp);
2173 return hres;
2175 if(jsdisp)
2176 jsdisp_release(jsdisp);
2178 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
2179 if(r && argc && flags == DISPATCH_METHOD)
2180 flags |= DISPATCH_PROPERTYGET;
2182 if(jsthis) {
2183 dp.cArgs = argc + 1;
2184 dp.cNamedArgs = 1;
2185 dp.rgdispidNamedArgs = &this_id;
2186 }else {
2187 dp.cArgs = argc;
2188 dp.cNamedArgs = 0;
2189 dp.rgdispidNamedArgs = NULL;
2192 if(dp.cArgs > ARRAY_SIZE(buf) && !(args = heap_alloc(dp.cArgs * sizeof(VARIANT))))
2193 return E_OUTOFMEMORY;
2194 dp.rgvarg = args;
2196 if(jsthis) {
2197 V_VT(dp.rgvarg) = VT_DISPATCH;
2198 V_DISPATCH(dp.rgvarg) = jsthis;
2201 for(i=0; SUCCEEDED(hres) && i < argc; i++)
2202 hres = jsval_to_variant(argv[i], dp.rgvarg+dp.cArgs-i-1);
2204 if(SUCCEEDED(hres)) {
2205 V_VT(&retv) = VT_EMPTY;
2206 hres = disp_invoke(ctx, disp, DISPID_VALUE, flags, &dp, r ? &retv : NULL);
2209 for(i = 0; i < argc; i++)
2210 VariantClear(dp.rgvarg + dp.cArgs - i - 1);
2211 if(args != buf)
2212 heap_free(args);
2214 if(FAILED(hres))
2215 return hres;
2216 if(!r)
2217 return S_OK;
2219 hres = variant_to_jsval(ctx, &retv, r);
2220 VariantClear(&retv);
2221 return hres;
2224 HRESULT jsdisp_propput(jsdisp_t *obj, const WCHAR *name, DWORD flags, BOOL throw, jsval_t val)
2226 dispex_prop_t *prop;
2227 HRESULT hres;
2229 if(obj->extensible)
2230 hres = ensure_prop_name(obj, name, flags, &prop);
2231 else
2232 hres = find_prop_name(obj, string_hash(name), name, &prop);
2233 if(FAILED(hres))
2234 return hres;
2235 if(!prop || (prop->type == PROP_DELETED && !obj->extensible))
2236 return throw ? JS_E_INVALID_ACTION : S_OK;
2238 return prop_put(obj, prop, val);
2241 HRESULT jsdisp_propput_name(jsdisp_t *obj, const WCHAR *name, jsval_t val)
2243 return jsdisp_propput(obj, name, PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE, FALSE, val);
2246 HRESULT jsdisp_propput_idx(jsdisp_t *obj, DWORD idx, jsval_t val)
2248 WCHAR buf[12];
2250 swprintf(buf, ARRAY_SIZE(buf), L"%d", idx);
2251 return jsdisp_propput(obj, buf, PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE, TRUE, val);
2254 HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val)
2256 jsdisp_t *jsdisp;
2257 HRESULT hres;
2259 jsdisp = iface_to_jsdisp(disp);
2260 if(jsdisp && jsdisp->ctx == ctx) {
2261 dispex_prop_t *prop;
2263 prop = get_prop(jsdisp, id);
2264 if(prop)
2265 hres = prop_put(jsdisp, prop, val);
2266 else
2267 hres = DISP_E_MEMBERNOTFOUND;
2269 jsdisp_release(jsdisp);
2270 }else {
2271 DISPID dispid = DISPID_PROPERTYPUT;
2272 DWORD flags = DISPATCH_PROPERTYPUT;
2273 VARIANT var;
2274 DISPPARAMS dp = {&var, &dispid, 1, 1};
2276 if(jsdisp)
2277 jsdisp_release(jsdisp);
2278 hres = jsval_to_variant(val, &var);
2279 if(FAILED(hres))
2280 return hres;
2282 if(V_VT(&var) == VT_DISPATCH)
2283 flags |= DISPATCH_PROPERTYPUTREF;
2285 hres = disp_invoke(ctx, disp, id, flags, &dp, NULL);
2286 VariantClear(&var);
2289 return hres;
2292 HRESULT disp_propput_name(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name, jsval_t val)
2294 jsdisp_t *jsdisp;
2295 HRESULT hres;
2297 jsdisp = iface_to_jsdisp(disp);
2298 if(!jsdisp || jsdisp->ctx != ctx) {
2299 IDispatchEx *dispex;
2300 BSTR str;
2301 DISPID id;
2303 if(jsdisp)
2304 jsdisp_release(jsdisp);
2305 if(!(str = SysAllocString(name)))
2306 return E_OUTOFMEMORY;
2308 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
2309 if(SUCCEEDED(hres)) {
2310 hres = IDispatchEx_GetDispID(dispex, str, make_grfdex(ctx, fdexNameEnsure|fdexNameCaseSensitive), &id);
2311 IDispatchEx_Release(dispex);
2312 }else {
2313 TRACE("using IDispatch\n");
2314 hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &str, 1, 0, &id);
2316 SysFreeString(str);
2317 if(FAILED(hres))
2318 return hres;
2320 return disp_propput(ctx, disp, id, val);
2323 hres = jsdisp_propput_name(jsdisp, name, val);
2324 jsdisp_release(jsdisp);
2325 return hres;
2328 HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val)
2330 dispex_prop_t *prop;
2331 HRESULT hres;
2333 hres = find_prop_name_prot(obj, string_hash(name), name, &prop);
2334 if(FAILED(hres))
2335 return hres;
2337 if(!prop || prop->type==PROP_DELETED) {
2338 *val = jsval_undefined();
2339 return S_OK;
2342 return prop_get(obj, prop, val);
2345 HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r)
2347 WCHAR name[12];
2348 dispex_prop_t *prop;
2349 HRESULT hres;
2351 swprintf(name, ARRAY_SIZE(name), L"%d", idx);
2353 hres = find_prop_name_prot(obj, string_hash(name), name, &prop);
2354 if(FAILED(hres))
2355 return hres;
2357 if(!prop || prop->type==PROP_DELETED) {
2358 *r = jsval_undefined();
2359 return DISP_E_UNKNOWNNAME;
2362 return prop_get(obj, prop, r);
2365 HRESULT jsdisp_propget(jsdisp_t *jsdisp, DISPID id, jsval_t *val)
2367 dispex_prop_t *prop;
2369 prop = get_prop(jsdisp, id);
2370 if(!prop)
2371 return DISP_E_MEMBERNOTFOUND;
2373 return prop_get(jsdisp, prop, val);
2376 HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t *val)
2378 DISPPARAMS dp = {NULL,NULL,0,0};
2379 jsdisp_t *jsdisp;
2380 VARIANT var;
2381 HRESULT hres;
2383 jsdisp = iface_to_jsdisp(disp);
2384 if(jsdisp && jsdisp->ctx == ctx) {
2385 hres = jsdisp_propget(jsdisp, id, val);
2386 jsdisp_release(jsdisp);
2387 return hres;
2389 if(jsdisp)
2390 jsdisp_release(jsdisp);
2392 V_VT(&var) = VT_EMPTY;
2393 hres = disp_invoke(ctx, disp, id, INVOKE_PROPERTYGET, &dp, &var);
2394 if(SUCCEEDED(hres)) {
2395 hres = variant_to_jsval(ctx, &var, val);
2396 VariantClear(&var);
2398 return hres;
2401 HRESULT jsdisp_delete_idx(jsdisp_t *obj, DWORD idx)
2403 WCHAR buf[12];
2404 dispex_prop_t *prop;
2405 BOOL b;
2406 HRESULT hres;
2408 swprintf(buf, ARRAY_SIZE(buf), L"%d", idx);
2410 hres = find_prop_name(obj, string_hash(buf), buf, &prop);
2411 if(FAILED(hres) || !prop)
2412 return hres;
2414 hres = delete_prop(prop, &b);
2415 if(FAILED(hres))
2416 return hres;
2417 return b ? S_OK : JS_E_INVALID_ACTION;
2420 HRESULT disp_delete(IDispatch *disp, DISPID id, BOOL *ret)
2422 IDispatchEx *dispex;
2423 jsdisp_t *jsdisp;
2424 HRESULT hres;
2426 jsdisp = iface_to_jsdisp(disp);
2427 if(jsdisp) {
2428 dispex_prop_t *prop;
2430 prop = get_prop(jsdisp, id);
2431 if(prop)
2432 hres = delete_prop(prop, ret);
2433 else
2434 hres = DISP_E_MEMBERNOTFOUND;
2436 jsdisp_release(jsdisp);
2437 return hres;
2440 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
2441 if(FAILED(hres)) {
2442 *ret = FALSE;
2443 return S_OK;
2446 hres = IDispatchEx_DeleteMemberByDispID(dispex, id);
2447 IDispatchEx_Release(dispex);
2448 if(FAILED(hres))
2449 return hres;
2451 *ret = hres == S_OK;
2452 return S_OK;
2455 HRESULT jsdisp_next_prop(jsdisp_t *obj, DISPID id, enum jsdisp_enum_type enum_type, DISPID *ret)
2457 dispex_prop_t *iter;
2458 DWORD idx = id;
2459 HRESULT hres;
2461 if(id == DISPID_STARTENUM) {
2462 if(obj->builtin_info->idx_length) {
2463 unsigned i = 0, len = obj->builtin_info->idx_length(obj);
2464 WCHAR name[12];
2466 for(i = 0; i < len; i++) {
2467 swprintf(name, ARRAY_SIZE(name), L"%d", i);
2468 hres = find_prop_name(obj, string_hash(name), name, &iter);
2469 if(FAILED(hres))
2470 return hres;
2474 if (enum_type == JSDISP_ENUM_ALL) {
2475 hres = fill_protrefs(obj);
2476 if(FAILED(hres))
2477 return hres;
2479 idx = 0;
2482 if(idx >= obj->prop_cnt)
2483 return S_FALSE;
2485 for(iter = &obj->props[idx]; iter < obj->props + obj->prop_cnt; iter++) {
2486 if(iter->type == PROP_DELETED)
2487 continue;
2488 if(enum_type != JSDISP_ENUM_ALL && iter->type == PROP_PROTREF)
2489 continue;
2490 if(enum_type != JSDISP_ENUM_OWN && !(get_flags(obj, iter) & PROPF_ENUMERABLE))
2491 continue;
2492 *ret = prop_to_id(obj, iter);
2493 return S_OK;
2496 return S_FALSE;
2499 HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL *ret)
2501 IDispatchEx *dispex;
2502 jsdisp_t *jsdisp;
2503 BSTR bstr;
2504 HRESULT hres;
2506 jsdisp = iface_to_jsdisp(disp);
2507 if(jsdisp) {
2508 dispex_prop_t *prop;
2509 const WCHAR *ptr;
2511 ptr = jsstr_flatten(name);
2512 if(!ptr) {
2513 jsdisp_release(jsdisp);
2514 return E_OUTOFMEMORY;
2517 hres = find_prop_name(jsdisp, string_hash(ptr), ptr, &prop);
2518 if(prop) {
2519 hres = delete_prop(prop, ret);
2520 }else {
2521 *ret = TRUE;
2522 hres = S_OK;
2525 jsdisp_release(jsdisp);
2526 return hres;
2529 bstr = SysAllocStringLen(NULL, jsstr_length(name));
2530 if(!bstr)
2531 return E_OUTOFMEMORY;
2532 jsstr_flush(name, bstr);
2534 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
2535 if(SUCCEEDED(hres)) {
2536 hres = IDispatchEx_DeleteMemberByName(dispex, bstr, make_grfdex(ctx, fdexNameCaseSensitive));
2537 if(SUCCEEDED(hres))
2538 *ret = hres == S_OK;
2539 IDispatchEx_Release(dispex);
2540 }else {
2541 DISPID id;
2543 hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, &id);
2544 if(SUCCEEDED(hres)) {
2545 /* Property exists and we can't delete it from pure IDispatch interface, so return false. */
2546 *ret = FALSE;
2547 }else if(hres == DISP_E_UNKNOWNNAME) {
2548 /* Property doesn't exist, so nothing to delete */
2549 *ret = TRUE;
2550 hres = S_OK;
2554 SysFreeString(bstr);
2555 return hres;
2558 HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_only,
2559 property_desc_t *desc)
2561 dispex_prop_t *prop;
2562 HRESULT hres;
2564 hres = find_prop_name(obj, string_hash(name), name, &prop);
2565 if(FAILED(hres))
2566 return hres;
2568 if(!prop)
2569 return DISP_E_UNKNOWNNAME;
2571 memset(desc, 0, sizeof(*desc));
2573 switch(prop->type) {
2574 case PROP_BUILTIN:
2575 case PROP_JSVAL:
2576 case PROP_IDX:
2577 desc->mask |= PROPF_WRITABLE;
2578 desc->explicit_value = TRUE;
2579 if(!flags_only) {
2580 hres = prop_get(obj, prop, &desc->value);
2581 if(FAILED(hres))
2582 return hres;
2584 break;
2585 case PROP_ACCESSOR:
2586 desc->explicit_getter = desc->explicit_setter = TRUE;
2587 if(!flags_only) {
2588 desc->getter = prop->u.accessor.getter
2589 ? jsdisp_addref(prop->u.accessor.getter) : NULL;
2590 desc->setter = prop->u.accessor.setter
2591 ? jsdisp_addref(prop->u.accessor.setter) : NULL;
2593 break;
2594 default:
2595 return DISP_E_UNKNOWNNAME;
2598 desc->flags = prop->flags & (PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE);
2599 desc->mask |= PROPF_ENUMERABLE | PROPF_CONFIGURABLE;
2600 return S_OK;
2603 HRESULT jsdisp_define_property(jsdisp_t *obj, const WCHAR *name, property_desc_t *desc)
2605 dispex_prop_t *prop;
2606 HRESULT hres;
2608 hres = find_prop_name(obj, string_hash(name), name, &prop);
2609 if(FAILED(hres))
2610 return hres;
2612 if((!prop || prop->type == PROP_DELETED || prop->type == PROP_PROTREF) && !obj->extensible)
2613 return throw_error(obj->ctx, JS_E_OBJECT_NONEXTENSIBLE, name);
2615 if(!prop && !(prop = alloc_prop(obj, name, PROP_DELETED, 0)))
2616 return E_OUTOFMEMORY;
2618 if(prop->type == PROP_DELETED || prop->type == PROP_PROTREF) {
2619 prop->flags = desc->flags;
2620 if(desc->explicit_getter || desc->explicit_setter) {
2621 prop->type = PROP_ACCESSOR;
2622 prop->u.accessor.getter = desc->getter ? jsdisp_addref(desc->getter) : NULL;
2623 prop->u.accessor.setter = desc->setter ? jsdisp_addref(desc->setter) : NULL;
2624 TRACE("%s = accessor { get: %p set: %p }\n", debugstr_w(name),
2625 prop->u.accessor.getter, prop->u.accessor.setter);
2626 }else {
2627 prop->type = PROP_JSVAL;
2628 if(desc->explicit_value) {
2629 hres = jsval_copy(desc->value, &prop->u.val);
2630 if(FAILED(hres))
2631 return hres;
2632 }else {
2633 prop->u.val = jsval_undefined();
2635 TRACE("%s = %s\n", debugstr_w(name), debugstr_jsval(prop->u.val));
2637 return S_OK;
2640 TRACE("existing prop %s prop flags %lx desc flags %x desc mask %x\n", debugstr_w(name),
2641 prop->flags, desc->flags, desc->mask);
2643 if(!(prop->flags & PROPF_CONFIGURABLE)) {
2644 if(((desc->mask & PROPF_CONFIGURABLE) && (desc->flags & PROPF_CONFIGURABLE))
2645 || ((desc->mask & PROPF_ENUMERABLE)
2646 && ((desc->flags & PROPF_ENUMERABLE) != (prop->flags & PROPF_ENUMERABLE))))
2647 return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name);
2650 if(desc->explicit_value || (desc->mask & PROPF_WRITABLE)) {
2651 if(prop->type == PROP_ACCESSOR) {
2652 if(!(prop->flags & PROPF_CONFIGURABLE))
2653 return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name);
2654 if(prop->u.accessor.getter)
2655 jsdisp_release(prop->u.accessor.getter);
2656 if(prop->u.accessor.setter)
2657 jsdisp_release(prop->u.accessor.setter);
2659 prop->type = PROP_JSVAL;
2660 hres = jsval_copy(desc->value, &prop->u.val);
2661 if(FAILED(hres)) {
2662 prop->u.val = jsval_undefined();
2663 return hres;
2665 }else {
2666 if(!(prop->flags & PROPF_CONFIGURABLE) && !(prop->flags & PROPF_WRITABLE)) {
2667 if((desc->mask & PROPF_WRITABLE) && (desc->flags & PROPF_WRITABLE))
2668 return throw_error(obj->ctx, JS_E_NONWRITABLE_MODIFIED, name);
2669 if(desc->explicit_value) {
2670 if(prop->type == PROP_JSVAL) {
2671 BOOL eq;
2672 hres = jsval_strict_equal(desc->value, prop->u.val, &eq);
2673 if(FAILED(hres))
2674 return hres;
2675 if(!eq)
2676 return throw_error(obj->ctx, JS_E_NONWRITABLE_MODIFIED, name);
2677 }else {
2678 FIXME("redefinition of property type %d\n", prop->type);
2682 if(desc->explicit_value) {
2683 if(prop->type == PROP_JSVAL)
2684 jsval_release(prop->u.val);
2685 else
2686 prop->type = PROP_JSVAL;
2687 hres = jsval_copy(desc->value, &prop->u.val);
2688 if(FAILED(hres)) {
2689 prop->u.val = jsval_undefined();
2690 return hres;
2694 }else if(desc->explicit_getter || desc->explicit_setter) {
2695 if(prop->type != PROP_ACCESSOR) {
2696 if(!(prop->flags & PROPF_CONFIGURABLE))
2697 return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name);
2698 if(prop->type == PROP_JSVAL)
2699 jsval_release(prop->u.val);
2700 prop->type = PROP_ACCESSOR;
2701 prop->u.accessor.getter = prop->u.accessor.setter = NULL;
2702 }else if(!(prop->flags & PROPF_CONFIGURABLE)) {
2703 if((desc->explicit_getter && desc->getter != prop->u.accessor.getter)
2704 || (desc->explicit_setter && desc->setter != prop->u.accessor.setter))
2705 return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name);
2708 if(desc->explicit_getter) {
2709 if(prop->u.accessor.getter) {
2710 jsdisp_release(prop->u.accessor.getter);
2711 prop->u.accessor.getter = NULL;
2713 if(desc->getter)
2714 prop->u.accessor.getter = jsdisp_addref(desc->getter);
2716 if(desc->explicit_setter) {
2717 if(prop->u.accessor.setter) {
2718 jsdisp_release(prop->u.accessor.setter);
2719 prop->u.accessor.setter = NULL;
2721 if(desc->setter)
2722 prop->u.accessor.setter = jsdisp_addref(desc->setter);
2726 prop->flags = (prop->flags & ~desc->mask) | (desc->flags & desc->mask);
2727 return S_OK;
2730 HRESULT jsdisp_define_data_property(jsdisp_t *obj, const WCHAR *name, unsigned flags, jsval_t value)
2732 property_desc_t prop_desc = { flags, flags, TRUE };
2733 prop_desc.value = value;
2734 return jsdisp_define_property(obj, name, &prop_desc);
2737 HRESULT jsdisp_change_prototype(jsdisp_t *obj, jsdisp_t *proto)
2739 jsdisp_t *iter;
2740 DWORD i;
2742 if(obj->prototype == proto)
2743 return S_OK;
2744 if(!obj->extensible)
2745 return JS_E_CANNOT_CREATE_FOR_NONEXTENSIBLE;
2747 for(iter = proto; iter; iter = iter->prototype)
2748 if(iter == obj)
2749 return JS_E_CYCLIC_PROTO_VALUE;
2751 if(obj->prototype) {
2752 for(i = 0; i < obj->prop_cnt; i++)
2753 if(obj->props[i].type == PROP_PROTREF)
2754 obj->props[i].type = PROP_DELETED;
2755 jsdisp_release(obj->prototype);
2758 obj->prototype = proto;
2759 if(proto)
2760 jsdisp_addref(proto);
2761 return S_OK;
2764 void jsdisp_freeze(jsdisp_t *obj, BOOL seal)
2766 unsigned int i;
2768 for(i = 0; i < obj->prop_cnt; i++) {
2769 if(!seal && obj->props[i].type == PROP_JSVAL)
2770 obj->props[i].flags &= ~PROPF_WRITABLE;
2771 obj->props[i].flags &= ~PROPF_CONFIGURABLE;
2774 obj->extensible = FALSE;
2777 BOOL jsdisp_is_frozen(jsdisp_t *obj, BOOL sealed)
2779 unsigned int i;
2781 if(obj->extensible)
2782 return FALSE;
2784 for(i = 0; i < obj->prop_cnt; i++) {
2785 if(obj->props[i].type == PROP_JSVAL) {
2786 if(!sealed && (obj->props[i].flags & PROPF_WRITABLE))
2787 return FALSE;
2788 }else if(obj->props[i].type != PROP_ACCESSOR)
2789 continue;
2790 if(obj->props[i].flags & PROPF_CONFIGURABLE)
2791 return FALSE;
2794 return TRUE;
2797 HRESULT jsdisp_get_prop_name(jsdisp_t *obj, DISPID id, jsstr_t **r)
2799 dispex_prop_t *prop = get_prop(obj, id);
2801 if(!prop)
2802 return DISP_E_MEMBERNOTFOUND;
2804 *r = jsstr_alloc(prop->name);
2805 return *r ? S_OK : E_OUTOFMEMORY;