user32/tests: Fix test_listbox_messages() message sequences to support WinEvents.
[wine.git] / dlls / jscript / dispex.c
blobc7e4ba933b723ad68eb7f55670b4cd3650ae0a4b
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 inline DISPID prop_to_id(jsdisp_t *This, dispex_prop_t *prop)
65 return prop - This->props;
68 static inline dispex_prop_t *get_prop(jsdisp_t *This, DISPID id)
70 if(id < 0 || id >= This->prop_cnt || This->props[id].type == PROP_DELETED)
71 return NULL;
73 return This->props+id;
76 static inline BOOL is_function_prop(dispex_prop_t *prop)
78 BOOL ret = FALSE;
80 if (is_object_instance(prop->u.val))
82 jsdisp_t *jsdisp = iface_to_jsdisp(get_object(prop->u.val));
84 if (jsdisp) ret = is_class(jsdisp, JSCLASS_FUNCTION);
85 jsdisp_release(jsdisp);
87 return ret;
90 static DWORD get_flags(jsdisp_t *This, dispex_prop_t *prop)
92 if(prop->type == PROP_PROTREF) {
93 dispex_prop_t *parent = get_prop(This->prototype, prop->u.ref);
94 if(!parent) {
95 prop->type = PROP_DELETED;
96 return 0;
99 return get_flags(This->prototype, parent);
102 return prop->flags;
105 static const builtin_prop_t *find_builtin_prop(jsdisp_t *This, const WCHAR *name)
107 int min = 0, max, i, r;
109 max = This->builtin_info->props_cnt-1;
110 while(min <= max) {
111 i = (min+max)/2;
113 r = wcscmp(name, This->builtin_info->props[i].name);
114 if(!r) {
115 /* Skip prop if it's available only in higher compatibility mode. */
116 unsigned version = (This->builtin_info->props[i].flags & PROPF_VERSION_MASK)
117 >> PROPF_VERSION_SHIFT;
118 if(version && version > This->ctx->version)
119 return NULL;
121 /* Skip prop if it's available only in HTML mode and we're not running in HTML mode. */
122 if((This->builtin_info->props[i].flags & PROPF_HTML) && !This->ctx->html_mode)
123 return NULL;
125 return This->builtin_info->props + i;
128 if(r < 0)
129 max = i-1;
130 else
131 min = i+1;
134 return NULL;
137 static inline unsigned string_hash(const WCHAR *name)
139 unsigned h = 0;
140 for(; *name; name++)
141 h = (h>>(sizeof(unsigned)*8-4)) ^ (h<<4) ^ towlower(*name);
142 return h;
145 static inline unsigned get_props_idx(jsdisp_t *This, unsigned hash)
147 return (hash*GOLDEN_RATIO) & (This->buf_size-1);
150 static inline HRESULT resize_props(jsdisp_t *This)
152 dispex_prop_t *props;
153 int i, bucket;
155 if(This->buf_size != This->prop_cnt)
156 return S_FALSE;
158 props = heap_realloc(This->props, sizeof(dispex_prop_t)*This->buf_size*2);
159 if(!props)
160 return E_OUTOFMEMORY;
161 This->buf_size *= 2;
162 This->props = props;
164 for(i=0; i<This->buf_size; i++) {
165 This->props[i].bucket_head = 0;
166 This->props[i].bucket_next = 0;
169 for(i=1; i<This->prop_cnt; i++) {
170 props = This->props+i;
172 bucket = get_props_idx(This, props->hash);
173 props->bucket_next = This->props[bucket].bucket_head;
174 This->props[bucket].bucket_head = i;
177 return S_OK;
180 static inline dispex_prop_t* alloc_prop(jsdisp_t *This, const WCHAR *name, prop_type_t type, DWORD flags)
182 dispex_prop_t *prop;
183 unsigned bucket;
185 if(FAILED(resize_props(This)))
186 return NULL;
188 prop = &This->props[This->prop_cnt];
189 prop->name = heap_strdupW(name);
190 if(!prop->name)
191 return NULL;
192 prop->type = type;
193 prop->flags = flags;
194 prop->hash = string_hash(name);
196 bucket = get_props_idx(This, prop->hash);
197 prop->bucket_next = This->props[bucket].bucket_head;
198 This->props[bucket].bucket_head = This->prop_cnt++;
199 return prop;
202 static dispex_prop_t *alloc_protref(jsdisp_t *This, const WCHAR *name, DWORD ref)
204 dispex_prop_t *ret;
206 ret = alloc_prop(This, name, PROP_PROTREF, 0);
207 if(!ret)
208 return NULL;
210 ret->u.ref = ref;
211 return ret;
214 static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, dispex_prop_t **ret)
216 const builtin_prop_t *builtin;
217 unsigned bucket, pos, prev = 0;
218 dispex_prop_t *prop;
220 bucket = get_props_idx(This, hash);
221 pos = This->props[bucket].bucket_head;
222 while(pos != 0) {
223 if(!wcscmp(name, This->props[pos].name)) {
224 if(prev != 0) {
225 This->props[prev].bucket_next = This->props[pos].bucket_next;
226 This->props[pos].bucket_next = This->props[bucket].bucket_head;
227 This->props[bucket].bucket_head = pos;
230 *ret = &This->props[pos];
231 return S_OK;
234 prev = pos;
235 pos = This->props[pos].bucket_next;
238 builtin = find_builtin_prop(This, name);
239 if(builtin) {
240 unsigned flags = builtin->flags;
241 if(flags & PROPF_METHOD)
242 flags |= PROPF_WRITABLE | PROPF_CONFIGURABLE;
243 else if(builtin->setter)
244 flags |= PROPF_WRITABLE;
245 flags &= PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE;
246 prop = alloc_prop(This, name, PROP_BUILTIN, flags);
247 if(!prop)
248 return E_OUTOFMEMORY;
250 prop->u.p = builtin;
251 *ret = prop;
252 return S_OK;
255 if(This->builtin_info->idx_length) {
256 const WCHAR *ptr;
257 unsigned idx = 0;
259 for(ptr = name; is_digit(*ptr) && idx < 0x10000; ptr++)
260 idx = idx*10 + (*ptr-'0');
261 if(!*ptr && idx < This->builtin_info->idx_length(This)) {
262 prop = alloc_prop(This, name, PROP_IDX, This->builtin_info->idx_put ? PROPF_WRITABLE : 0);
263 if(!prop)
264 return E_OUTOFMEMORY;
266 prop->u.idx = idx;
267 *ret = prop;
268 return S_OK;
272 *ret = NULL;
273 return S_OK;
276 static HRESULT find_prop_name_prot(jsdisp_t *This, unsigned hash, const WCHAR *name, dispex_prop_t **ret)
278 dispex_prop_t *prop, *del=NULL;
279 HRESULT hres;
281 hres = find_prop_name(This, hash, name, &prop);
282 if(FAILED(hres))
283 return hres;
284 if(prop && prop->type==PROP_DELETED) {
285 del = prop;
286 } else if(prop) {
287 *ret = prop;
288 return S_OK;
291 if(This->prototype) {
292 hres = find_prop_name_prot(This->prototype, hash, name, &prop);
293 if(FAILED(hres))
294 return hres;
295 if(prop) {
296 if(del) {
297 del->type = PROP_PROTREF;
298 del->u.ref = prop - This->prototype->props;
299 prop = del;
300 }else {
301 prop = alloc_protref(This, prop->name, prop - This->prototype->props);
302 if(!prop)
303 return E_OUTOFMEMORY;
306 *ret = prop;
307 return S_OK;
311 *ret = del;
312 return S_OK;
315 static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_flags, dispex_prop_t **ret)
317 dispex_prop_t *prop;
318 HRESULT hres;
320 hres = find_prop_name_prot(This, string_hash(name), name, &prop);
321 if(SUCCEEDED(hres) && (!prop || prop->type == PROP_DELETED)) {
322 TRACE("creating prop %s flags %x\n", debugstr_w(name), create_flags);
324 if(prop) {
325 prop->type = PROP_JSVAL;
326 prop->flags = create_flags;
327 prop->u.val = jsval_undefined();
328 }else {
329 prop = alloc_prop(This, name, PROP_JSVAL, create_flags);
330 if(!prop)
331 return E_OUTOFMEMORY;
334 prop->u.val = jsval_undefined();
337 *ret = prop;
338 return hres;
341 static IDispatch *get_this(DISPPARAMS *dp)
343 DWORD i;
345 for(i=0; i < dp->cNamedArgs; i++) {
346 if(dp->rgdispidNamedArgs[i] == DISPID_THIS) {
347 if(V_VT(dp->rgvarg+i) == VT_DISPATCH)
348 return V_DISPATCH(dp->rgvarg+i);
350 WARN("This is not VT_DISPATCH\n");
351 return NULL;
355 TRACE("no this passed\n");
356 return NULL;
359 static HRESULT convert_params(const DISPPARAMS *dp, jsval_t *buf, unsigned *argc, jsval_t **ret)
361 jsval_t *argv;
362 unsigned cnt;
363 unsigned i;
364 HRESULT hres;
366 cnt = dp->cArgs - dp->cNamedArgs;
368 if(cnt > 6) {
369 argv = heap_alloc(cnt * sizeof(*argv));
370 if(!argv)
371 return E_OUTOFMEMORY;
372 }else {
373 argv = buf;
376 for(i = 0; i < cnt; i++) {
377 hres = variant_to_jsval(dp->rgvarg+dp->cArgs-i-1, argv+i);
378 if(FAILED(hres)) {
379 while(i--)
380 jsval_release(argv[i]);
381 if(argv != buf)
382 heap_free(argv);
383 return hres;
387 *argc = cnt;
388 *ret = argv;
389 return S_OK;
392 static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, jsval_t *r)
394 jsdisp_t *prop_obj = This;
395 HRESULT hres;
397 while(prop->type == PROP_PROTREF) {
398 prop_obj = prop_obj->prototype;
399 prop = prop_obj->props + prop->u.ref;
402 switch(prop->type) {
403 case PROP_BUILTIN:
404 if(prop->u.p->getter) {
405 hres = prop->u.p->getter(This->ctx, This, r);
406 }else {
407 jsdisp_t *obj;
409 assert(prop->u.p->invoke != NULL);
410 hres = create_builtin_function(This->ctx, prop->u.p->invoke, prop->u.p->name, NULL,
411 prop->u.p->flags, NULL, &obj);
412 if(FAILED(hres))
413 break;
415 prop->type = PROP_JSVAL;
416 prop->u.val = jsval_obj(obj);
418 jsdisp_addref(obj);
419 *r = jsval_obj(obj);
421 break;
422 case PROP_JSVAL:
423 hres = jsval_copy(prop->u.val, r);
424 break;
425 case PROP_ACCESSOR:
426 if(prop->u.accessor.getter) {
427 hres = jsdisp_call_value(prop->u.accessor.getter, to_disp(This),
428 DISPATCH_METHOD, 0, NULL, r);
429 }else {
430 *r = jsval_undefined();
431 hres = S_OK;
433 break;
434 case PROP_IDX:
435 hres = prop_obj->builtin_info->idx_get(prop_obj, prop->u.idx, r);
436 break;
437 default:
438 ERR("type %d\n", prop->type);
439 return E_FAIL;
442 if(FAILED(hres)) {
443 TRACE("fail %08x\n", hres);
444 return hres;
447 TRACE("%p.%s ret %s\n", This, debugstr_w(prop->name), debugstr_jsval(*r));
448 return hres;
451 static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val)
453 HRESULT hres;
455 if(prop->type == PROP_PROTREF) {
456 dispex_prop_t *prop_iter = prop;
457 jsdisp_t *prototype_iter = This;
459 do {
460 prototype_iter = prototype_iter->prototype;
461 prop_iter = prototype_iter->props + prop_iter->u.ref;
462 } while(prop_iter->type == PROP_PROTREF);
464 if(prop_iter->type == PROP_ACCESSOR)
465 prop = prop_iter;
468 switch(prop->type) {
469 case PROP_BUILTIN:
470 if(!prop->u.p->setter) {
471 TRACE("getter with no setter\n");
472 return S_OK;
474 return prop->u.p->setter(This->ctx, This, val);
475 case PROP_PROTREF:
476 case PROP_DELETED:
477 if(!This->extensible)
478 return S_OK;
479 prop->type = PROP_JSVAL;
480 prop->flags = PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE;
481 prop->u.val = jsval_undefined();
482 break;
483 case PROP_JSVAL:
484 if(!(prop->flags & PROPF_WRITABLE))
485 return S_OK;
487 jsval_release(prop->u.val);
488 break;
489 case PROP_ACCESSOR:
490 if(!prop->u.accessor.setter) {
491 TRACE("no setter\n");
492 return S_OK;
494 return jsdisp_call_value(prop->u.accessor.setter, to_disp(This), DISPATCH_METHOD, 1, &val, NULL);
495 case PROP_IDX:
496 if(!This->builtin_info->idx_put) {
497 TRACE("no put_idx\n");
498 return S_OK;
500 return This->builtin_info->idx_put(This, prop->u.idx, val);
501 default:
502 ERR("type %d\n", prop->type);
503 return E_FAIL;
506 TRACE("%p.%s = %s\n", This, debugstr_w(prop->name), debugstr_jsval(val));
508 hres = jsval_copy(val, &prop->u.val);
509 if(FAILED(hres))
510 return hres;
512 if(This->builtin_info->on_put)
513 This->builtin_info->on_put(This, prop->name);
515 return S_OK;
518 static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t *prop, WORD flags,
519 unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller)
521 HRESULT hres;
523 switch(prop->type) {
524 case PROP_BUILTIN: {
525 if(flags == DISPATCH_CONSTRUCT && (prop->flags & PROPF_METHOD)) {
526 WARN("%s is not a constructor\n", debugstr_w(prop->name));
527 return E_INVALIDARG;
530 if(prop->name || This->builtin_info->class != JSCLASS_FUNCTION) {
531 vdisp_t vthis;
533 if(This->builtin_info->class != JSCLASS_FUNCTION && prop->u.p->invoke != JSGlobal_eval)
534 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
535 if(jsthis)
536 set_disp(&vthis, jsthis);
537 else
538 set_jsdisp(&vthis, This);
539 hres = prop->u.p->invoke(This->ctx, &vthis, flags, argc, argv, r);
540 vdisp_release(&vthis);
541 }else {
542 /* Function object calls are special case */
543 hres = Function_invoke(This, jsthis, flags, argc, argv, r);
545 return hres;
547 case PROP_PROTREF:
548 return invoke_prop_func(This->prototype, jsthis ? jsthis : (IDispatch *)&This->IDispatchEx_iface,
549 This->prototype->props+prop->u.ref, flags, argc, argv, r, caller);
550 case PROP_JSVAL: {
551 if(!is_object_instance(prop->u.val) || !get_object(prop->u.val)) {
552 FIXME("invoke %s\n", debugstr_jsval(prop->u.val));
553 return E_FAIL;
556 TRACE("call %s %p\n", debugstr_w(prop->name), get_object(prop->u.val));
558 return disp_call_value(This->ctx, get_object(prop->u.val),
559 jsthis ? jsthis : (IDispatch*)&This->IDispatchEx_iface,
560 flags, argc, argv, r);
562 case PROP_ACCESSOR:
563 case PROP_IDX: {
564 jsval_t val;
566 hres = prop_get(This, prop, &val);
567 if(FAILED(hres))
568 return hres;
570 if(is_object_instance(val) && get_object(val)) {
571 hres = disp_call_value(This->ctx, get_object(val),
572 jsthis ? jsthis : (IDispatch*)&This->IDispatchEx_iface,
573 flags, argc, argv, r);
574 }else {
575 FIXME("invoke %s\n", debugstr_jsval(val));
576 hres = E_NOTIMPL;
579 jsval_release(val);
580 return hres;
582 case PROP_DELETED:
583 assert(0);
584 break;
587 return E_FAIL;
590 HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
592 TRACE("%p %s\n", jsthis, debugstr_jsval(value));
593 return S_OK;
596 static HRESULT fill_protrefs(jsdisp_t *This)
598 dispex_prop_t *iter, *prop;
599 HRESULT hres;
601 if(!This->prototype)
602 return S_OK;
604 fill_protrefs(This->prototype);
606 for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) {
607 if(!iter->name)
608 continue;
609 hres = find_prop_name(This, iter->hash, iter->name, &prop);
610 if(FAILED(hres))
611 return hres;
612 if(!prop || prop->type==PROP_DELETED) {
613 if(prop) {
614 prop->type = PROP_PROTREF;
615 prop->flags = 0;
616 prop->u.ref = iter - This->prototype->props;
617 }else {
618 prop = alloc_protref(This, iter->name, iter - This->prototype->props);
619 if(!prop)
620 return E_OUTOFMEMORY;
625 return S_OK;
628 struct typeinfo_func {
629 dispex_prop_t *prop;
630 function_code_t *code;
633 typedef struct {
634 ITypeInfo ITypeInfo_iface;
635 ITypeComp ITypeComp_iface;
636 LONG ref;
638 UINT num_funcs;
639 UINT num_vars;
640 struct typeinfo_func *funcs;
641 dispex_prop_t **vars;
643 jsdisp_t *jsdisp;
644 } ScriptTypeInfo;
646 static struct typeinfo_func *get_func_from_memid(const ScriptTypeInfo *typeinfo, MEMBERID memid)
648 UINT a = 0, b = typeinfo->num_funcs;
650 while (a < b)
652 UINT i = (a + b - 1) / 2;
653 MEMBERID func_memid = prop_to_id(typeinfo->jsdisp, typeinfo->funcs[i].prop);
655 if (memid == func_memid)
656 return &typeinfo->funcs[i];
657 else if (memid < func_memid)
658 b = i;
659 else
660 a = i + 1;
662 return NULL;
665 static dispex_prop_t *get_var_from_memid(const ScriptTypeInfo *typeinfo, MEMBERID memid)
667 UINT a = 0, b = typeinfo->num_vars;
669 while (a < b)
671 UINT i = (a + b - 1) / 2;
672 MEMBERID var_memid = prop_to_id(typeinfo->jsdisp, typeinfo->vars[i]);
674 if (memid == var_memid)
675 return typeinfo->vars[i];
676 else if (memid < var_memid)
677 b = i;
678 else
679 a = i + 1;
681 return NULL;
684 static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeInfo(ITypeInfo *iface)
686 return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeInfo_iface);
689 static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeComp(ITypeComp *iface)
691 return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeComp_iface);
694 static HRESULT WINAPI ScriptTypeInfo_QueryInterface(ITypeInfo *iface, REFIID riid, void **ppv)
696 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
698 if (IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_ITypeInfo, riid))
699 *ppv = &This->ITypeInfo_iface;
700 else if (IsEqualGUID(&IID_ITypeComp, riid))
701 *ppv = &This->ITypeComp_iface;
702 else
704 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
705 *ppv = NULL;
706 return E_NOINTERFACE;
709 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
710 IUnknown_AddRef((IUnknown*)*ppv);
711 return S_OK;
714 static ULONG WINAPI ScriptTypeInfo_AddRef(ITypeInfo *iface)
716 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
717 LONG ref = InterlockedIncrement(&This->ref);
719 TRACE("(%p) ref=%d\n", This, ref);
721 return ref;
724 static ULONG WINAPI ScriptTypeInfo_Release(ITypeInfo *iface)
726 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
727 LONG ref = InterlockedDecrement(&This->ref);
728 UINT i;
730 TRACE("(%p) ref=%d\n", This, ref);
732 if (!ref)
734 for (i = This->num_funcs; i--;)
735 release_bytecode(This->funcs[i].code->bytecode);
736 IDispatchEx_Release(&This->jsdisp->IDispatchEx_iface);
737 heap_free(This->funcs);
738 heap_free(This->vars);
739 heap_free(This);
741 return ref;
744 static HRESULT WINAPI ScriptTypeInfo_GetTypeAttr(ITypeInfo *iface, TYPEATTR **ppTypeAttr)
746 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
747 TYPEATTR *attr;
749 TRACE("(%p)->(%p)\n", This, ppTypeAttr);
751 if (!ppTypeAttr) return E_INVALIDARG;
753 attr = heap_alloc_zero(sizeof(*attr));
754 if (!attr) return E_OUTOFMEMORY;
756 attr->guid = GUID_JScriptTypeInfo;
757 attr->lcid = LOCALE_USER_DEFAULT;
758 attr->memidConstructor = MEMBERID_NIL;
759 attr->memidDestructor = MEMBERID_NIL;
760 attr->cbSizeInstance = 4;
761 attr->typekind = TKIND_DISPATCH;
762 attr->cFuncs = This->num_funcs;
763 attr->cVars = This->num_vars;
764 attr->cImplTypes = 1;
765 attr->cbSizeVft = sizeof(IDispatchVtbl);
766 attr->cbAlignment = 4;
767 attr->wTypeFlags = TYPEFLAG_FDISPATCHABLE;
768 attr->wMajorVerNum = JSCRIPT_MAJOR_VERSION;
769 attr->wMinorVerNum = JSCRIPT_MINOR_VERSION;
771 *ppTypeAttr = attr;
772 return S_OK;
775 static HRESULT WINAPI ScriptTypeInfo_GetTypeComp(ITypeInfo *iface, ITypeComp **ppTComp)
777 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
779 TRACE("(%p)->(%p)\n", This, ppTComp);
781 if (!ppTComp) return E_INVALIDARG;
783 *ppTComp = &This->ITypeComp_iface;
784 ITypeInfo_AddRef(iface);
785 return S_OK;
788 static HRESULT WINAPI ScriptTypeInfo_GetFuncDesc(ITypeInfo *iface, UINT index, FUNCDESC **ppFuncDesc)
790 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
791 struct typeinfo_func *func;
792 FUNCDESC *desc;
793 unsigned i;
795 TRACE("(%p)->(%u %p)\n", This, index, ppFuncDesc);
797 if (!ppFuncDesc) return E_INVALIDARG;
798 if (index >= This->num_funcs) return TYPE_E_ELEMENTNOTFOUND;
799 func = &This->funcs[index];
801 /* Store the parameter array after the FUNCDESC structure */
802 desc = heap_alloc_zero(sizeof(*desc) + sizeof(ELEMDESC) * func->code->param_cnt);
803 if (!desc) return E_OUTOFMEMORY;
805 desc->memid = prop_to_id(This->jsdisp, func->prop);
806 desc->funckind = FUNC_DISPATCH;
807 desc->invkind = INVOKE_FUNC;
808 desc->callconv = CC_STDCALL;
809 desc->cParams = func->code->param_cnt;
810 desc->elemdescFunc.tdesc.vt = VT_VARIANT;
812 if (func->code->param_cnt) desc->lprgelemdescParam = (ELEMDESC*)(desc + 1);
813 for (i = 0; i < func->code->param_cnt; i++)
814 desc->lprgelemdescParam[i].tdesc.vt = VT_VARIANT;
816 *ppFuncDesc = desc;
817 return S_OK;
820 static HRESULT WINAPI ScriptTypeInfo_GetVarDesc(ITypeInfo *iface, UINT index, VARDESC **ppVarDesc)
822 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
823 VARDESC *desc;
825 TRACE("(%p)->(%u %p)\n", This, index, ppVarDesc);
827 if (!ppVarDesc) return E_INVALIDARG;
828 if (index >= This->num_vars) return TYPE_E_ELEMENTNOTFOUND;
830 desc = heap_alloc_zero(sizeof(*desc));
831 if (!desc) return E_OUTOFMEMORY;
833 desc->memid = prop_to_id(This->jsdisp, This->vars[index]);
834 desc->varkind = VAR_DISPATCH;
835 desc->elemdescVar.tdesc.vt = VT_VARIANT;
837 *ppVarDesc = desc;
838 return S_OK;
841 static HRESULT WINAPI ScriptTypeInfo_GetNames(ITypeInfo *iface, MEMBERID memid, BSTR *rgBstrNames,
842 UINT cMaxNames, UINT *pcNames)
844 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
845 struct typeinfo_func *func;
846 ITypeInfo *disp_typeinfo;
847 dispex_prop_t *var;
848 HRESULT hr;
849 UINT i = 0;
851 TRACE("(%p)->(%d %p %u %p)\n", This, memid, rgBstrNames, cMaxNames, pcNames);
853 if (!rgBstrNames || !pcNames) return E_INVALIDARG;
854 if (memid <= 0) return TYPE_E_ELEMENTNOTFOUND;
856 func = get_func_from_memid(This, memid);
857 if (!func)
859 var = get_var_from_memid(This, memid);
860 if (!var)
862 hr = get_dispatch_typeinfo(&disp_typeinfo);
863 if (FAILED(hr)) return hr;
865 return ITypeInfo_GetNames(disp_typeinfo, memid, rgBstrNames, cMaxNames, pcNames);
869 *pcNames = 0;
870 if (!cMaxNames) return S_OK;
872 rgBstrNames[0] = SysAllocString(func ? func->prop->name : var->name);
873 if (!rgBstrNames[0]) return E_OUTOFMEMORY;
874 i++;
876 if (func)
878 unsigned num = min(cMaxNames, func->code->param_cnt + 1);
880 for (; i < num; i++)
882 if (!(rgBstrNames[i] = SysAllocString(func->code->params[i - 1])))
884 do SysFreeString(rgBstrNames[--i]); while (i);
885 return E_OUTOFMEMORY;
890 *pcNames = i;
891 return S_OK;
894 static HRESULT WINAPI ScriptTypeInfo_GetRefTypeOfImplType(ITypeInfo *iface, UINT index, HREFTYPE *pRefType)
896 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
898 TRACE("(%p)->(%u %p)\n", This, index, pRefType);
900 /* We only inherit from IDispatch */
901 if (!pRefType) return E_INVALIDARG;
902 if (index != 0) return TYPE_E_ELEMENTNOTFOUND;
904 *pRefType = 1;
905 return S_OK;
908 static HRESULT WINAPI ScriptTypeInfo_GetImplTypeFlags(ITypeInfo *iface, UINT index, INT *pImplTypeFlags)
910 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
912 TRACE("(%p)->(%u %p)\n", This, index, pImplTypeFlags);
914 if (!pImplTypeFlags) return E_INVALIDARG;
915 if (index != 0) return TYPE_E_ELEMENTNOTFOUND;
917 *pImplTypeFlags = 0;
918 return S_OK;
921 static HRESULT WINAPI ScriptTypeInfo_GetIDsOfNames(ITypeInfo *iface, LPOLESTR *rgszNames, UINT cNames,
922 MEMBERID *pMemId)
924 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
925 ITypeInfo *disp_typeinfo;
926 const WCHAR *name;
927 HRESULT hr = S_OK;
928 int i, j, arg;
930 TRACE("(%p)->(%p %u %p)\n", This, rgszNames, cNames, pMemId);
932 if (!rgszNames || !cNames || !pMemId) return E_INVALIDARG;
934 for (i = 0; i < cNames; i++) pMemId[i] = MEMBERID_NIL;
935 name = rgszNames[0];
937 for (i = 0; i < This->num_funcs; i++)
939 struct typeinfo_func *func = &This->funcs[i];
941 if (wcsicmp(name, func->prop->name)) continue;
942 pMemId[0] = prop_to_id(This->jsdisp, func->prop);
944 for (j = 1; j < cNames; j++)
946 name = rgszNames[j];
947 for (arg = func->code->param_cnt; --arg >= 0;)
948 if (!wcsicmp(name, func->code->params[arg]))
949 break;
950 if (arg >= 0)
951 pMemId[j] = arg;
952 else
953 hr = DISP_E_UNKNOWNNAME;
955 return hr;
958 for (i = 0; i < This->num_vars; i++)
960 dispex_prop_t *var = This->vars[i];
962 if (wcsicmp(name, var->name)) continue;
963 pMemId[0] = prop_to_id(This->jsdisp, var);
964 return S_OK;
967 /* Look into the inherited IDispatch */
968 hr = get_dispatch_typeinfo(&disp_typeinfo);
969 if (FAILED(hr)) return hr;
971 return ITypeInfo_GetIDsOfNames(disp_typeinfo, rgszNames, cNames, pMemId);
974 static HRESULT WINAPI ScriptTypeInfo_Invoke(ITypeInfo *iface, PVOID pvInstance, MEMBERID memid, WORD wFlags,
975 DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
977 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
978 ITypeInfo *disp_typeinfo;
979 IDispatch *disp;
980 HRESULT hr;
982 TRACE("(%p)->(%p %d %d %p %p %p %p)\n", This, pvInstance, memid, wFlags,
983 pDispParams, pVarResult, pExcepInfo, puArgErr);
985 if (!pvInstance) return E_INVALIDARG;
986 if (memid <= 0) return TYPE_E_ELEMENTNOTFOUND;
988 if (!get_func_from_memid(This, memid) && !get_var_from_memid(This, memid))
990 hr = get_dispatch_typeinfo(&disp_typeinfo);
991 if (FAILED(hr)) return hr;
993 return ITypeInfo_Invoke(disp_typeinfo, pvInstance, memid, wFlags, pDispParams,
994 pVarResult, pExcepInfo, puArgErr);
997 hr = IUnknown_QueryInterface((IUnknown*)pvInstance, &IID_IDispatch, (void**)&disp);
998 if (FAILED(hr)) return hr;
1000 hr = IDispatch_Invoke(disp, memid, &IID_NULL, LOCALE_USER_DEFAULT, wFlags,
1001 pDispParams, pVarResult, pExcepInfo, puArgErr);
1002 IDispatch_Release(disp);
1004 return hr;
1007 static HRESULT WINAPI ScriptTypeInfo_GetDocumentation(ITypeInfo *iface, MEMBERID memid, BSTR *pBstrName,
1008 BSTR *pBstrDocString, DWORD *pdwHelpContext, BSTR *pBstrHelpFile)
1010 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1011 struct typeinfo_func *func;
1012 ITypeInfo *disp_typeinfo;
1013 dispex_prop_t *var;
1014 HRESULT hr;
1016 TRACE("(%p)->(%d %p %p %p %p)\n", This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
1018 if (pBstrDocString) *pBstrDocString = NULL;
1019 if (pdwHelpContext) *pdwHelpContext = 0;
1020 if (pBstrHelpFile) *pBstrHelpFile = NULL;
1022 if (memid == MEMBERID_NIL)
1024 if (pBstrName && !(*pBstrName = SysAllocString(L"JScriptTypeInfo")))
1025 return E_OUTOFMEMORY;
1026 if (pBstrDocString &&
1027 !(*pBstrDocString = SysAllocString(L"JScript Type Info")))
1029 if (pBstrName) SysFreeString(*pBstrName);
1030 return E_OUTOFMEMORY;
1032 return S_OK;
1034 if (memid <= 0) return TYPE_E_ELEMENTNOTFOUND;
1036 func = get_func_from_memid(This, memid);
1037 if (!func)
1039 var = get_var_from_memid(This, memid);
1040 if (!var)
1042 hr = get_dispatch_typeinfo(&disp_typeinfo);
1043 if (FAILED(hr)) return hr;
1045 return ITypeInfo_GetDocumentation(disp_typeinfo, memid, pBstrName, pBstrDocString,
1046 pdwHelpContext, pBstrHelpFile);
1050 if (pBstrName)
1052 *pBstrName = SysAllocString(func ? func->prop->name : var->name);
1054 if (!*pBstrName)
1055 return E_OUTOFMEMORY;
1057 return S_OK;
1060 static HRESULT WINAPI ScriptTypeInfo_GetDllEntry(ITypeInfo *iface, MEMBERID memid, INVOKEKIND invKind,
1061 BSTR *pBstrDllName, BSTR *pBstrName, WORD *pwOrdinal)
1063 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1064 ITypeInfo *disp_typeinfo;
1065 HRESULT hr;
1067 TRACE("(%p)->(%d %d %p %p %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
1069 if (pBstrDllName) *pBstrDllName = NULL;
1070 if (pBstrName) *pBstrName = NULL;
1071 if (pwOrdinal) *pwOrdinal = 0;
1073 if (!get_func_from_memid(This, memid) && !get_var_from_memid(This, memid))
1075 hr = get_dispatch_typeinfo(&disp_typeinfo);
1076 if (FAILED(hr)) return hr;
1078 return ITypeInfo_GetDllEntry(disp_typeinfo, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
1080 return TYPE_E_BADMODULEKIND;
1083 static HRESULT WINAPI ScriptTypeInfo_GetRefTypeInfo(ITypeInfo *iface, HREFTYPE hRefType, ITypeInfo **ppTInfo)
1085 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1086 HRESULT hr;
1088 TRACE("(%p)->(%x %p)\n", This, hRefType, ppTInfo);
1090 if (!ppTInfo || (INT)hRefType < 0) return E_INVALIDARG;
1092 if (hRefType & ~3) return E_FAIL;
1093 if (hRefType & 1)
1095 hr = get_dispatch_typeinfo(ppTInfo);
1096 if (FAILED(hr)) return hr;
1098 else
1099 *ppTInfo = iface;
1101 ITypeInfo_AddRef(*ppTInfo);
1102 return S_OK;
1105 static HRESULT WINAPI ScriptTypeInfo_AddressOfMember(ITypeInfo *iface, MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
1107 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1108 ITypeInfo *disp_typeinfo;
1109 HRESULT hr;
1111 TRACE("(%p)->(%d %d %p)\n", This, memid, invKind, ppv);
1113 if (!ppv) return E_INVALIDARG;
1114 *ppv = NULL;
1116 if (!get_func_from_memid(This, memid) && !get_var_from_memid(This, memid))
1118 hr = get_dispatch_typeinfo(&disp_typeinfo);
1119 if (FAILED(hr)) return hr;
1121 return ITypeInfo_AddressOfMember(disp_typeinfo, memid, invKind, ppv);
1123 return TYPE_E_BADMODULEKIND;
1126 static HRESULT WINAPI ScriptTypeInfo_CreateInstance(ITypeInfo *iface, IUnknown *pUnkOuter, REFIID riid, PVOID *ppvObj)
1128 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1130 TRACE("(%p)->(%p %s %p)\n", This, pUnkOuter, debugstr_guid(riid), ppvObj);
1132 if (!ppvObj) return E_INVALIDARG;
1134 *ppvObj = NULL;
1135 return TYPE_E_BADMODULEKIND;
1138 static HRESULT WINAPI ScriptTypeInfo_GetMops(ITypeInfo *iface, MEMBERID memid, BSTR *pBstrMops)
1140 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1141 ITypeInfo *disp_typeinfo;
1142 HRESULT hr;
1144 TRACE("(%p)->(%d %p)\n", This, memid, pBstrMops);
1146 if (!pBstrMops) return E_INVALIDARG;
1148 if (!get_func_from_memid(This, memid) && !get_var_from_memid(This, memid))
1150 hr = get_dispatch_typeinfo(&disp_typeinfo);
1151 if (FAILED(hr)) return hr;
1153 return ITypeInfo_GetMops(disp_typeinfo, memid, pBstrMops);
1156 *pBstrMops = NULL;
1157 return S_OK;
1160 static HRESULT WINAPI ScriptTypeInfo_GetContainingTypeLib(ITypeInfo *iface, ITypeLib **ppTLib, UINT *pIndex)
1162 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1164 FIXME("(%p)->(%p %p)\n", This, ppTLib, pIndex);
1166 return E_NOTIMPL;
1169 static void WINAPI ScriptTypeInfo_ReleaseTypeAttr(ITypeInfo *iface, TYPEATTR *pTypeAttr)
1171 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1173 TRACE("(%p)->(%p)\n", This, pTypeAttr);
1175 heap_free(pTypeAttr);
1178 static void WINAPI ScriptTypeInfo_ReleaseFuncDesc(ITypeInfo *iface, FUNCDESC *pFuncDesc)
1180 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1182 TRACE("(%p)->(%p)\n", This, pFuncDesc);
1184 heap_free(pFuncDesc);
1187 static void WINAPI ScriptTypeInfo_ReleaseVarDesc(ITypeInfo *iface, VARDESC *pVarDesc)
1189 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1191 TRACE("(%p)->(%p)\n", This, pVarDesc);
1193 heap_free(pVarDesc);
1196 static const ITypeInfoVtbl ScriptTypeInfoVtbl = {
1197 ScriptTypeInfo_QueryInterface,
1198 ScriptTypeInfo_AddRef,
1199 ScriptTypeInfo_Release,
1200 ScriptTypeInfo_GetTypeAttr,
1201 ScriptTypeInfo_GetTypeComp,
1202 ScriptTypeInfo_GetFuncDesc,
1203 ScriptTypeInfo_GetVarDesc,
1204 ScriptTypeInfo_GetNames,
1205 ScriptTypeInfo_GetRefTypeOfImplType,
1206 ScriptTypeInfo_GetImplTypeFlags,
1207 ScriptTypeInfo_GetIDsOfNames,
1208 ScriptTypeInfo_Invoke,
1209 ScriptTypeInfo_GetDocumentation,
1210 ScriptTypeInfo_GetDllEntry,
1211 ScriptTypeInfo_GetRefTypeInfo,
1212 ScriptTypeInfo_AddressOfMember,
1213 ScriptTypeInfo_CreateInstance,
1214 ScriptTypeInfo_GetMops,
1215 ScriptTypeInfo_GetContainingTypeLib,
1216 ScriptTypeInfo_ReleaseTypeAttr,
1217 ScriptTypeInfo_ReleaseFuncDesc,
1218 ScriptTypeInfo_ReleaseVarDesc
1221 static HRESULT WINAPI ScriptTypeComp_QueryInterface(ITypeComp *iface, REFIID riid, void **ppv)
1223 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1224 return ITypeInfo_QueryInterface(&This->ITypeInfo_iface, riid, ppv);
1227 static ULONG WINAPI ScriptTypeComp_AddRef(ITypeComp *iface)
1229 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1230 return ITypeInfo_AddRef(&This->ITypeInfo_iface);
1233 static ULONG WINAPI ScriptTypeComp_Release(ITypeComp *iface)
1235 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1236 return ITypeInfo_Release(&This->ITypeInfo_iface);
1239 static HRESULT WINAPI ScriptTypeComp_Bind(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal, WORD wFlags,
1240 ITypeInfo **ppTInfo, DESCKIND *pDescKind, BINDPTR *pBindPtr)
1242 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1243 UINT flags = wFlags ? wFlags : ~0;
1244 ITypeInfo *disp_typeinfo;
1245 ITypeComp *disp_typecomp;
1246 HRESULT hr;
1247 UINT i;
1249 TRACE("(%p)->(%s %08x %d %p %p %p)\n", This, debugstr_w(szName), lHashVal,
1250 wFlags, ppTInfo, pDescKind, pBindPtr);
1252 if (!szName || !ppTInfo || !pDescKind || !pBindPtr)
1253 return E_INVALIDARG;
1255 for (i = 0; i < This->num_funcs; i++)
1257 if (wcsicmp(szName, This->funcs[i].prop->name)) continue;
1258 if (!(flags & INVOKE_FUNC)) return TYPE_E_TYPEMISMATCH;
1260 hr = ITypeInfo_GetFuncDesc(&This->ITypeInfo_iface, i, &pBindPtr->lpfuncdesc);
1261 if (FAILED(hr)) return hr;
1263 *pDescKind = DESCKIND_FUNCDESC;
1264 *ppTInfo = &This->ITypeInfo_iface;
1265 ITypeInfo_AddRef(*ppTInfo);
1266 return S_OK;
1269 for (i = 0; i < This->num_vars; i++)
1271 if (wcsicmp(szName, This->vars[i]->name)) continue;
1272 if (!(flags & INVOKE_PROPERTYGET)) return TYPE_E_TYPEMISMATCH;
1274 hr = ITypeInfo_GetVarDesc(&This->ITypeInfo_iface, i, &pBindPtr->lpvardesc);
1275 if (FAILED(hr)) return hr;
1277 *pDescKind = DESCKIND_VARDESC;
1278 *ppTInfo = &This->ITypeInfo_iface;
1279 ITypeInfo_AddRef(*ppTInfo);
1280 return S_OK;
1283 /* Look into the inherited IDispatch */
1284 hr = get_dispatch_typeinfo(&disp_typeinfo);
1285 if (FAILED(hr)) return hr;
1287 hr = ITypeInfo_GetTypeComp(disp_typeinfo, &disp_typecomp);
1288 if (FAILED(hr)) return hr;
1290 hr = ITypeComp_Bind(disp_typecomp, szName, lHashVal, wFlags, ppTInfo, pDescKind, pBindPtr);
1291 ITypeComp_Release(disp_typecomp);
1292 return hr;
1295 static HRESULT WINAPI ScriptTypeComp_BindType(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal,
1296 ITypeInfo **ppTInfo, ITypeComp **ppTComp)
1298 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1299 ITypeInfo *disp_typeinfo;
1300 ITypeComp *disp_typecomp;
1301 HRESULT hr;
1303 TRACE("(%p)->(%s %08x %p %p)\n", This, debugstr_w(szName), lHashVal, ppTInfo, ppTComp);
1305 if (!szName || !ppTInfo || !ppTComp)
1306 return E_INVALIDARG;
1308 /* Look into the inherited IDispatch */
1309 hr = get_dispatch_typeinfo(&disp_typeinfo);
1310 if (FAILED(hr)) return hr;
1312 hr = ITypeInfo_GetTypeComp(disp_typeinfo, &disp_typecomp);
1313 if (FAILED(hr)) return hr;
1315 hr = ITypeComp_BindType(disp_typecomp, szName, lHashVal, ppTInfo, ppTComp);
1316 ITypeComp_Release(disp_typecomp);
1317 return hr;
1320 static const ITypeCompVtbl ScriptTypeCompVtbl = {
1321 ScriptTypeComp_QueryInterface,
1322 ScriptTypeComp_AddRef,
1323 ScriptTypeComp_Release,
1324 ScriptTypeComp_Bind,
1325 ScriptTypeComp_BindType
1328 static inline jsdisp_t *impl_from_IDispatchEx(IDispatchEx *iface)
1330 return CONTAINING_RECORD(iface, jsdisp_t, IDispatchEx_iface);
1333 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
1335 jsdisp_t *This = impl_from_IDispatchEx(iface);
1337 if(IsEqualGUID(&IID_IUnknown, riid)) {
1338 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
1339 *ppv = &This->IDispatchEx_iface;
1340 }else if(IsEqualGUID(&IID_IDispatch, riid)) {
1341 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
1342 *ppv = &This->IDispatchEx_iface;
1343 }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
1344 TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
1345 *ppv = &This->IDispatchEx_iface;
1346 }else {
1347 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
1348 *ppv = NULL;
1349 return E_NOINTERFACE;
1352 jsdisp_addref(This);
1353 return S_OK;
1356 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
1358 jsdisp_t *This = impl_from_IDispatchEx(iface);
1359 jsdisp_addref(This);
1360 return This->ref;
1363 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
1365 jsdisp_t *This = impl_from_IDispatchEx(iface);
1366 ULONG ref = --This->ref;
1367 TRACE("(%p) ref=%d\n", This, ref);
1368 if(!ref)
1369 jsdisp_free(This);
1370 return ref;
1373 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
1375 jsdisp_t *This = impl_from_IDispatchEx(iface);
1377 TRACE("(%p)->(%p)\n", This, pctinfo);
1379 *pctinfo = 1;
1380 return S_OK;
1383 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid,
1384 ITypeInfo **ppTInfo)
1386 jsdisp_t *This = impl_from_IDispatchEx(iface);
1387 dispex_prop_t *prop, *cur, *end, **typevar;
1388 UINT num_funcs = 0, num_vars = 0;
1389 struct typeinfo_func *typefunc;
1390 function_code_t *func_code;
1391 ScriptTypeInfo *typeinfo;
1392 unsigned pos;
1394 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1396 if (iTInfo != 0) return DISP_E_BADINDEX;
1398 for (prop = This->props, end = prop + This->prop_cnt; prop != end; prop++)
1400 if (!prop->name || prop->type != PROP_JSVAL || !(prop->flags & PROPF_ENUMERABLE))
1401 continue;
1403 /* If two identifiers differ only by case, the TypeInfo fails */
1404 pos = This->props[get_props_idx(This, prop->hash)].bucket_head;
1405 while (pos)
1407 cur = This->props + pos;
1409 if (prop->hash == cur->hash && prop != cur &&
1410 cur->type == PROP_JSVAL && (cur->flags & PROPF_ENUMERABLE) &&
1411 !wcsicmp(prop->name, cur->name))
1413 return TYPE_E_AMBIGUOUSNAME;
1415 pos = cur->bucket_next;
1418 if (is_function_prop(prop))
1420 if (Function_get_code(as_jsdisp(get_object(prop->u.val))))
1421 num_funcs++;
1423 else num_vars++;
1426 if (!(typeinfo = heap_alloc(sizeof(*typeinfo))))
1427 return E_OUTOFMEMORY;
1429 typeinfo->ITypeInfo_iface.lpVtbl = &ScriptTypeInfoVtbl;
1430 typeinfo->ITypeComp_iface.lpVtbl = &ScriptTypeCompVtbl;
1431 typeinfo->ref = 1;
1432 typeinfo->num_vars = num_vars;
1433 typeinfo->num_funcs = num_funcs;
1434 typeinfo->jsdisp = This;
1436 typeinfo->funcs = heap_alloc(sizeof(*typeinfo->funcs) * num_funcs);
1437 if (!typeinfo->funcs)
1439 heap_free(typeinfo);
1440 return E_OUTOFMEMORY;
1443 typeinfo->vars = heap_alloc(sizeof(*typeinfo->vars) * num_vars);
1444 if (!typeinfo->vars)
1446 heap_free(typeinfo->funcs);
1447 heap_free(typeinfo);
1448 return E_OUTOFMEMORY;
1451 typefunc = typeinfo->funcs;
1452 typevar = typeinfo->vars;
1453 for (prop = This->props; prop != end; prop++)
1455 if (!prop->name || prop->type != PROP_JSVAL || !(prop->flags & PROPF_ENUMERABLE))
1456 continue;
1458 if (is_function_prop(prop))
1460 func_code = Function_get_code(as_jsdisp(get_object(prop->u.val)));
1461 if (!func_code) continue;
1463 typefunc->prop = prop;
1464 typefunc->code = func_code;
1465 typefunc++;
1467 /* The function may be deleted, so keep a ref */
1468 bytecode_addref(func_code->bytecode);
1470 else
1471 *typevar++ = prop;
1474 /* Keep a ref to the props and their names */
1475 IDispatchEx_AddRef(&This->IDispatchEx_iface);
1477 *ppTInfo = &typeinfo->ITypeInfo_iface;
1478 return S_OK;
1481 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
1482 LPOLESTR *rgszNames, UINT cNames, LCID lcid,
1483 DISPID *rgDispId)
1485 jsdisp_t *This = impl_from_IDispatchEx(iface);
1486 UINT i;
1487 HRESULT hres;
1489 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1490 lcid, rgDispId);
1492 if(cNames == 0)
1493 return S_OK;
1495 hres = jsdisp_get_id(This, rgszNames[0], 0, rgDispId);
1496 if(FAILED(hres))
1497 return hres;
1499 /* DISPIDs for parameters don't seem to be supported */
1500 if(cNames > 1) {
1501 for(i = 1; i < cNames; i++)
1502 rgDispId[i] = DISPID_UNKNOWN;
1503 hres = DISP_E_UNKNOWNNAME;
1506 return hres;
1509 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
1510 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
1511 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1513 jsdisp_t *This = impl_from_IDispatchEx(iface);
1515 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1516 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1518 return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags,
1519 pDispParams, pVarResult, pExcepInfo, NULL);
1522 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
1524 jsdisp_t *This = impl_from_IDispatchEx(iface);
1526 TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
1528 if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) {
1529 FIXME("Unsupported grfdex %x\n", grfdex);
1530 return E_NOTIMPL;
1533 return jsdisp_get_id(This, bstrName, grfdex, pid);
1536 static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
1537 VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
1539 jsdisp_t *This = impl_from_IDispatchEx(iface);
1540 dispex_prop_t *prop;
1541 jsexcept_t ei;
1542 HRESULT hres;
1544 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
1546 if(pvarRes)
1547 V_VT(pvarRes) = VT_EMPTY;
1549 prop = get_prop(This, id);
1550 if(!prop || prop->type == PROP_DELETED) {
1551 TRACE("invalid id\n");
1552 return DISP_E_MEMBERNOTFOUND;
1555 enter_script(This->ctx, &ei);
1557 switch(wFlags) {
1558 case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
1559 wFlags = DISPATCH_METHOD;
1560 /* fall through */
1561 case DISPATCH_METHOD:
1562 case DISPATCH_CONSTRUCT: {
1563 jsval_t *argv, buf[6], r;
1564 unsigned argc;
1566 hres = convert_params(pdp, buf, &argc, &argv);
1567 if(FAILED(hres))
1568 break;
1570 hres = invoke_prop_func(This, get_this(pdp), prop, wFlags, argc, argv, pvarRes ? &r : NULL, pspCaller);
1571 if(argv != buf)
1572 heap_free(argv);
1573 if(SUCCEEDED(hres) && pvarRes) {
1574 hres = jsval_to_variant(r, pvarRes);
1575 jsval_release(r);
1577 break;
1579 case DISPATCH_PROPERTYGET: {
1580 jsval_t r;
1582 hres = prop_get(This, prop, &r);
1583 if(SUCCEEDED(hres)) {
1584 hres = jsval_to_variant(r, pvarRes);
1585 jsval_release(r);
1587 break;
1589 case DISPATCH_PROPERTYPUT: {
1590 jsval_t val;
1591 DWORD i;
1593 for(i=0; i < pdp->cNamedArgs; i++) {
1594 if(pdp->rgdispidNamedArgs[i] == DISPID_PROPERTYPUT)
1595 break;
1598 if(i == pdp->cNamedArgs) {
1599 TRACE("no value to set\n");
1600 hres = DISP_E_PARAMNOTOPTIONAL;
1601 break;
1604 hres = variant_to_jsval(pdp->rgvarg+i, &val);
1605 if(FAILED(hres))
1606 break;
1608 hres = prop_put(This, prop, val);
1609 jsval_release(val);
1610 break;
1612 default:
1613 FIXME("Unimplemented flags %x\n", wFlags);
1614 hres = E_INVALIDARG;
1615 break;
1618 return leave_script(This->ctx, hres);
1621 static HRESULT delete_prop(dispex_prop_t *prop, BOOL *ret)
1623 if(!(prop->flags & PROPF_CONFIGURABLE)) {
1624 *ret = FALSE;
1625 return S_OK;
1628 *ret = TRUE; /* FIXME: not exactly right */
1630 if(prop->type == PROP_JSVAL) {
1631 jsval_release(prop->u.val);
1632 prop->type = PROP_DELETED;
1634 if(prop->type == PROP_ACCESSOR)
1635 FIXME("not supported on accessor property\n");
1636 return S_OK;
1639 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
1641 jsdisp_t *This = impl_from_IDispatchEx(iface);
1642 dispex_prop_t *prop;
1643 BOOL b;
1644 HRESULT hres;
1646 TRACE("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex);
1648 if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK))
1649 FIXME("Unsupported grfdex %x\n", grfdex);
1651 hres = find_prop_name(This, string_hash(bstrName), bstrName, &prop);
1652 if(FAILED(hres))
1653 return hres;
1654 if(!prop) {
1655 TRACE("not found\n");
1656 return S_OK;
1659 return delete_prop(prop, &b);
1662 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
1664 jsdisp_t *This = impl_from_IDispatchEx(iface);
1665 dispex_prop_t *prop;
1666 BOOL b;
1668 TRACE("(%p)->(%x)\n", This, id);
1670 prop = get_prop(This, id);
1671 if(!prop) {
1672 WARN("invalid id\n");
1673 return DISP_E_MEMBERNOTFOUND;
1676 return delete_prop(prop, &b);
1679 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
1681 jsdisp_t *This = impl_from_IDispatchEx(iface);
1682 FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex);
1683 return E_NOTIMPL;
1686 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
1688 jsdisp_t *This = impl_from_IDispatchEx(iface);
1689 dispex_prop_t *prop;
1691 TRACE("(%p)->(%x %p)\n", This, id, pbstrName);
1693 prop = get_prop(This, id);
1694 if(!prop || !prop->name || prop->type == PROP_DELETED)
1695 return DISP_E_MEMBERNOTFOUND;
1697 *pbstrName = SysAllocString(prop->name);
1698 if(!*pbstrName)
1699 return E_OUTOFMEMORY;
1701 return S_OK;
1704 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
1706 jsdisp_t *This = impl_from_IDispatchEx(iface);
1707 HRESULT hres;
1709 TRACE("(%p)->(%x %x %p)\n", This, grfdex, id, pid);
1711 hres = jsdisp_next_prop(This, id, JSDISP_ENUM_ALL, pid);
1712 if(hres == S_FALSE)
1713 *pid = DISPID_STARTENUM;
1714 return hres;
1717 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
1719 jsdisp_t *This = impl_from_IDispatchEx(iface);
1720 FIXME("(%p)->(%p)\n", This, ppunk);
1721 return E_NOTIMPL;
1724 static IDispatchExVtbl DispatchExVtbl = {
1725 DispatchEx_QueryInterface,
1726 DispatchEx_AddRef,
1727 DispatchEx_Release,
1728 DispatchEx_GetTypeInfoCount,
1729 DispatchEx_GetTypeInfo,
1730 DispatchEx_GetIDsOfNames,
1731 DispatchEx_Invoke,
1732 DispatchEx_GetDispID,
1733 DispatchEx_InvokeEx,
1734 DispatchEx_DeleteMemberByName,
1735 DispatchEx_DeleteMemberByDispID,
1736 DispatchEx_GetMemberProperties,
1737 DispatchEx_GetMemberName,
1738 DispatchEx_GetNextDispID,
1739 DispatchEx_GetNameSpaceParent
1742 jsdisp_t *as_jsdisp(IDispatch *disp)
1744 assert(disp->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl);
1745 return impl_from_IDispatchEx((IDispatchEx*)disp);
1748 jsdisp_t *to_jsdisp(IDispatch *disp)
1750 return disp->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl ? impl_from_IDispatchEx((IDispatchEx*)disp) : NULL;
1753 HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype)
1755 TRACE("%p (%p)\n", dispex, prototype);
1757 dispex->IDispatchEx_iface.lpVtbl = &DispatchExVtbl;
1758 dispex->ref = 1;
1759 dispex->builtin_info = builtin_info;
1760 dispex->extensible = TRUE;
1762 dispex->props = heap_alloc_zero(sizeof(dispex_prop_t)*(dispex->buf_size=4));
1763 if(!dispex->props)
1764 return E_OUTOFMEMORY;
1766 dispex->prototype = prototype;
1767 if(prototype)
1768 jsdisp_addref(prototype);
1770 dispex->prop_cnt = 1;
1771 if(builtin_info->value_prop.invoke || builtin_info->value_prop.getter) {
1772 dispex->props[0].type = PROP_BUILTIN;
1773 dispex->props[0].u.p = &builtin_info->value_prop;
1774 }else {
1775 dispex->props[0].type = PROP_DELETED;
1778 script_addref(ctx);
1779 dispex->ctx = ctx;
1781 return S_OK;
1784 static const builtin_info_t dispex_info = {
1785 JSCLASS_NONE,
1786 {NULL, NULL, 0},
1787 0, NULL,
1788 NULL,
1789 NULL
1792 HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype, jsdisp_t **dispex)
1794 jsdisp_t *ret;
1795 HRESULT hres;
1797 ret = heap_alloc_zero(sizeof(jsdisp_t));
1798 if(!ret)
1799 return E_OUTOFMEMORY;
1801 hres = init_dispex(ret, ctx, builtin_info ? builtin_info : &dispex_info, prototype);
1802 if(FAILED(hres)) {
1803 heap_free(ret);
1804 return hres;
1807 *dispex = ret;
1808 return S_OK;
1811 void jsdisp_free(jsdisp_t *obj)
1813 dispex_prop_t *prop;
1815 TRACE("(%p)\n", obj);
1817 for(prop = obj->props; prop < obj->props+obj->prop_cnt; prop++) {
1818 switch(prop->type) {
1819 case PROP_JSVAL:
1820 jsval_release(prop->u.val);
1821 break;
1822 case PROP_ACCESSOR:
1823 if(prop->u.accessor.getter)
1824 jsdisp_release(prop->u.accessor.getter);
1825 if(prop->u.accessor.setter)
1826 jsdisp_release(prop->u.accessor.setter);
1827 break;
1828 default:
1829 break;
1831 heap_free(prop->name);
1833 heap_free(obj->props);
1834 script_release(obj->ctx);
1835 if(obj->prototype)
1836 jsdisp_release(obj->prototype);
1838 if(obj->builtin_info->destructor)
1839 obj->builtin_info->destructor(obj);
1840 else
1841 heap_free(obj);
1844 #ifdef TRACE_REFCNT
1846 jsdisp_t *jsdisp_addref(jsdisp_t *jsdisp)
1848 ULONG ref = ++jsdisp->ref;
1849 TRACE("(%p) ref=%d\n", jsdisp, ref);
1850 return jsdisp;
1853 void jsdisp_release(jsdisp_t *jsdisp)
1855 ULONG ref = --jsdisp->ref;
1857 TRACE("(%p) ref=%d\n", jsdisp, ref);
1859 if(!ref)
1860 jsdisp_free(jsdisp);
1863 #endif
1865 HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *constr)
1867 jsdisp_t *prot = NULL;
1868 dispex_prop_t *prop;
1869 HRESULT hres;
1871 hres = find_prop_name_prot(constr, string_hash(L"prototype"), L"prototype", &prop);
1872 if(SUCCEEDED(hres) && prop && prop->type!=PROP_DELETED) {
1873 jsval_t val;
1875 hres = prop_get(constr, prop, &val);
1876 if(FAILED(hres)) {
1877 ERR("Could not get prototype\n");
1878 return hres;
1881 if(is_object_instance(val) && get_object(val))
1882 prot = iface_to_jsdisp(get_object(val));
1883 else
1884 prot = jsdisp_addref(ctx->object_prototype);
1886 jsval_release(val);
1889 hres = init_dispex(dispex, ctx, builtin_info, prot);
1891 if(prot)
1892 jsdisp_release(prot);
1893 return hres;
1896 jsdisp_t *iface_to_jsdisp(IDispatch *iface)
1898 return iface->lpVtbl == (const IDispatchVtbl*)&DispatchExVtbl
1899 ? jsdisp_addref( impl_from_IDispatchEx((IDispatchEx*)iface))
1900 : NULL;
1903 HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID *id)
1905 dispex_prop_t *prop;
1906 HRESULT hres;
1908 if(jsdisp->extensible && (flags & fdexNameEnsure))
1909 hres = ensure_prop_name(jsdisp, name, PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE,
1910 &prop);
1911 else
1912 hres = find_prop_name_prot(jsdisp, string_hash(name), name, &prop);
1913 if(FAILED(hres))
1914 return hres;
1916 if(prop && prop->type!=PROP_DELETED) {
1917 *id = prop_to_id(jsdisp, prop);
1918 return S_OK;
1921 TRACE("not found %s\n", debugstr_w(name));
1922 *id = DISPID_UNKNOWN;
1923 return DISP_E_UNKNOWNNAME;
1926 HRESULT jsdisp_call_value(jsdisp_t *jsfunc, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1928 HRESULT hres;
1930 assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT|DISPATCH_JSCRIPT_INTERNAL_MASK)));
1932 if(is_class(jsfunc, JSCLASS_FUNCTION)) {
1933 hres = Function_invoke(jsfunc, jsthis, flags, argc, argv, r);
1934 }else {
1935 vdisp_t vdisp;
1937 if(!jsfunc->builtin_info->value_prop.invoke) {
1938 WARN("Not a function\n");
1939 return JS_E_FUNCTION_EXPECTED;
1942 set_disp(&vdisp, jsthis);
1943 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
1944 hres = jsfunc->builtin_info->value_prop.invoke(jsfunc->ctx, &vdisp, flags, argc, argv, r);
1945 vdisp_release(&vdisp);
1947 return hres;
1950 HRESULT jsdisp_call(jsdisp_t *disp, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1952 dispex_prop_t *prop;
1954 prop = get_prop(disp, id);
1955 if(!prop)
1956 return DISP_E_MEMBERNOTFOUND;
1958 return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, NULL);
1961 HRESULT jsdisp_call_name(jsdisp_t *disp, const WCHAR *name, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1963 dispex_prop_t *prop;
1964 HRESULT hres;
1966 hres = find_prop_name_prot(disp, string_hash(name), name, &prop);
1967 if(FAILED(hres))
1968 return hres;
1970 return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, NULL);
1973 static HRESULT disp_invoke(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, DISPPARAMS *params, VARIANT *r)
1975 IDispatchEx *dispex;
1976 EXCEPINFO ei;
1977 HRESULT hres;
1979 memset(&ei, 0, sizeof(ei));
1980 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1981 if(SUCCEEDED(hres)) {
1982 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, params, r, &ei, &ctx->jscaller->IServiceProvider_iface);
1983 IDispatchEx_Release(dispex);
1984 }else {
1985 UINT err = 0;
1987 if(flags == DISPATCH_CONSTRUCT) {
1988 WARN("IDispatch cannot be constructor\n");
1989 return DISP_E_MEMBERNOTFOUND;
1992 if(params->cNamedArgs == 1 && params->rgdispidNamedArgs[0] == DISPID_THIS) {
1993 params->cNamedArgs = 0;
1994 params->rgdispidNamedArgs = NULL;
1995 params->cArgs--;
1996 params->rgvarg++;
1999 TRACE("using IDispatch\n");
2000 hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, params, r, &ei, &err);
2003 if(hres == DISP_E_EXCEPTION) {
2004 TRACE("DISP_E_EXCEPTION: %08x %s %s\n", ei.scode, debugstr_w(ei.bstrSource), debugstr_w(ei.bstrDescription));
2005 reset_ei(ctx->ei);
2006 ctx->ei->error = (SUCCEEDED(ei.scode) || ei.scode == DISP_E_EXCEPTION) ? E_FAIL : ei.scode;
2007 if(ei.bstrSource)
2008 ctx->ei->source = jsstr_alloc_len(ei.bstrSource, SysStringLen(ei.bstrSource));
2009 if(ei.bstrDescription)
2010 ctx->ei->message = jsstr_alloc_len(ei.bstrDescription, SysStringLen(ei.bstrDescription));
2011 SysFreeString(ei.bstrSource);
2012 SysFreeString(ei.bstrDescription);
2013 SysFreeString(ei.bstrHelpFile);
2016 return hres;
2019 HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *ret)
2021 VARIANT buf[6], retv;
2022 jsdisp_t *jsdisp;
2023 DISPPARAMS dp;
2024 unsigned i;
2025 HRESULT hres;
2027 jsdisp = iface_to_jsdisp(disp);
2028 if(jsdisp && jsdisp->ctx == ctx) {
2029 if(flags & DISPATCH_PROPERTYPUT) {
2030 FIXME("disp_call(propput) on builtin object\n");
2031 return E_FAIL;
2034 if(ctx != jsdisp->ctx)
2035 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
2036 hres = jsdisp_call(jsdisp, id, flags, argc, argv, ret);
2037 jsdisp_release(jsdisp);
2038 return hres;
2041 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
2042 if(ret && argc)
2043 flags |= DISPATCH_PROPERTYGET;
2045 dp.cArgs = argc;
2047 if(flags & DISPATCH_PROPERTYPUT) {
2048 static DISPID propput_dispid = DISPID_PROPERTYPUT;
2050 dp.cNamedArgs = 1;
2051 dp.rgdispidNamedArgs = &propput_dispid;
2052 }else {
2053 dp.cNamedArgs = 0;
2054 dp.rgdispidNamedArgs = NULL;
2057 if(dp.cArgs > ARRAY_SIZE(buf)) {
2058 dp.rgvarg = heap_alloc(argc*sizeof(VARIANT));
2059 if(!dp.rgvarg)
2060 return E_OUTOFMEMORY;
2061 }else {
2062 dp.rgvarg = buf;
2065 for(i=0; i<argc; i++) {
2066 hres = jsval_to_variant(argv[i], dp.rgvarg+argc-i-1);
2067 if(FAILED(hres)) {
2068 while(i--)
2069 VariantClear(dp.rgvarg+argc-i-1);
2070 if(dp.rgvarg != buf)
2071 heap_free(dp.rgvarg);
2072 return hres;
2076 V_VT(&retv) = VT_EMPTY;
2077 hres = disp_invoke(ctx, disp, id, flags, &dp, ret ? &retv : NULL);
2079 for(i=0; i<argc; i++)
2080 VariantClear(dp.rgvarg+argc-i-1);
2081 if(dp.rgvarg != buf)
2082 heap_free(dp.rgvarg);
2084 if(SUCCEEDED(hres) && ret)
2085 hres = variant_to_jsval(&retv, ret);
2086 VariantClear(&retv);
2087 return hres;
2090 HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2091 jsval_t *r)
2093 VARIANT buf[6], retv, *args = buf;
2094 jsdisp_t *jsdisp;
2095 DISPPARAMS dp;
2096 unsigned i;
2097 HRESULT hres = S_OK;
2099 static DISPID this_id = DISPID_THIS;
2101 assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT|DISPATCH_JSCRIPT_INTERNAL_MASK)));
2103 jsdisp = iface_to_jsdisp(disp);
2104 if(jsdisp && jsdisp->ctx == ctx) {
2105 hres = jsdisp_call_value(jsdisp, jsthis, flags, argc, argv, r);
2106 jsdisp_release(jsdisp);
2107 return hres;
2110 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
2111 if(r && argc && flags == DISPATCH_METHOD)
2112 flags |= DISPATCH_PROPERTYGET;
2114 if(jsthis) {
2115 dp.cArgs = argc + 1;
2116 dp.cNamedArgs = 1;
2117 dp.rgdispidNamedArgs = &this_id;
2118 }else {
2119 dp.cArgs = argc;
2120 dp.cNamedArgs = 0;
2121 dp.rgdispidNamedArgs = NULL;
2124 if(dp.cArgs > ARRAY_SIZE(buf) && !(args = heap_alloc(dp.cArgs * sizeof(VARIANT))))
2125 return E_OUTOFMEMORY;
2126 dp.rgvarg = args;
2128 if(jsthis) {
2129 V_VT(dp.rgvarg) = VT_DISPATCH;
2130 V_DISPATCH(dp.rgvarg) = jsthis;
2133 for(i=0; SUCCEEDED(hres) && i < argc; i++)
2134 hres = jsval_to_variant(argv[i], dp.rgvarg+dp.cArgs-i-1);
2136 if(SUCCEEDED(hres)) {
2137 V_VT(&retv) = VT_EMPTY;
2138 hres = disp_invoke(ctx, disp, DISPID_VALUE, flags, &dp, r ? &retv : NULL);
2141 for(i = 0; i < argc; i++)
2142 VariantClear(dp.rgvarg + dp.cArgs - i - 1);
2143 if(args != buf)
2144 heap_free(args);
2146 if(FAILED(hres))
2147 return hres;
2148 if(!r)
2149 return S_OK;
2151 hres = variant_to_jsval(&retv, r);
2152 VariantClear(&retv);
2153 return hres;
2156 HRESULT jsdisp_propput(jsdisp_t *obj, const WCHAR *name, DWORD flags, BOOL throw, jsval_t val)
2158 dispex_prop_t *prop;
2159 HRESULT hres;
2161 if(obj->extensible)
2162 hres = ensure_prop_name(obj, name, flags, &prop);
2163 else
2164 hres = find_prop_name(obj, string_hash(name), name, &prop);
2165 if(FAILED(hres))
2166 return hres;
2167 if(!prop || (prop->type == PROP_DELETED && !obj->extensible))
2168 return throw ? JS_E_INVALID_ACTION : S_OK;
2170 return prop_put(obj, prop, val);
2173 HRESULT jsdisp_propput_name(jsdisp_t *obj, const WCHAR *name, jsval_t val)
2175 return jsdisp_propput(obj, name, PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE, FALSE, val);
2178 HRESULT jsdisp_propput_idx(jsdisp_t *obj, DWORD idx, jsval_t val)
2180 WCHAR buf[12];
2182 swprintf(buf, ARRAY_SIZE(buf), L"%d", idx);
2183 return jsdisp_propput(obj, buf, PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE, TRUE, val);
2186 HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val)
2188 jsdisp_t *jsdisp;
2189 HRESULT hres;
2191 jsdisp = iface_to_jsdisp(disp);
2192 if(jsdisp && jsdisp->ctx == ctx) {
2193 dispex_prop_t *prop;
2195 prop = get_prop(jsdisp, id);
2196 if(prop)
2197 hres = prop_put(jsdisp, prop, val);
2198 else
2199 hres = DISP_E_MEMBERNOTFOUND;
2201 jsdisp_release(jsdisp);
2202 }else {
2203 DISPID dispid = DISPID_PROPERTYPUT;
2204 DWORD flags = DISPATCH_PROPERTYPUT;
2205 VARIANT var;
2206 DISPPARAMS dp = {&var, &dispid, 1, 1};
2208 hres = jsval_to_variant(val, &var);
2209 if(FAILED(hres))
2210 return hres;
2212 if(V_VT(&var) == VT_DISPATCH)
2213 flags |= DISPATCH_PROPERTYPUTREF;
2215 hres = disp_invoke(ctx, disp, id, flags, &dp, NULL);
2216 VariantClear(&var);
2219 return hres;
2222 HRESULT disp_propput_name(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name, jsval_t val)
2224 jsdisp_t *jsdisp;
2225 HRESULT hres;
2227 jsdisp = iface_to_jsdisp(disp);
2228 if(!jsdisp || jsdisp->ctx != ctx) {
2229 IDispatchEx *dispex;
2230 BSTR str;
2231 DISPID id;
2233 if(!(str = SysAllocString(name)))
2234 return E_OUTOFMEMORY;
2236 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
2237 if(SUCCEEDED(hres)) {
2238 hres = IDispatchEx_GetDispID(dispex, str, make_grfdex(ctx, fdexNameEnsure|fdexNameCaseSensitive), &id);
2239 IDispatchEx_Release(dispex);
2240 }else {
2241 TRACE("using IDispatch\n");
2242 hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &str, 1, 0, &id);
2244 SysFreeString(str);
2245 if(FAILED(hres))
2246 return hres;
2248 return disp_propput(ctx, disp, id, val);
2251 return jsdisp_propput_name(jsdisp, name, val);
2254 HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val)
2256 dispex_prop_t *prop;
2257 HRESULT hres;
2259 hres = find_prop_name_prot(obj, string_hash(name), name, &prop);
2260 if(FAILED(hres))
2261 return hres;
2263 if(!prop || prop->type==PROP_DELETED) {
2264 *val = jsval_undefined();
2265 return S_OK;
2268 return prop_get(obj, prop, val);
2271 HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r)
2273 WCHAR name[12];
2274 dispex_prop_t *prop;
2275 HRESULT hres;
2277 swprintf(name, ARRAY_SIZE(name), L"%d", idx);
2279 hres = find_prop_name_prot(obj, string_hash(name), name, &prop);
2280 if(FAILED(hres))
2281 return hres;
2283 if(!prop || prop->type==PROP_DELETED) {
2284 *r = jsval_undefined();
2285 return DISP_E_UNKNOWNNAME;
2288 return prop_get(obj, prop, r);
2291 HRESULT jsdisp_propget(jsdisp_t *jsdisp, DISPID id, jsval_t *val)
2293 dispex_prop_t *prop;
2295 prop = get_prop(jsdisp, id);
2296 if(!prop)
2297 return DISP_E_MEMBERNOTFOUND;
2299 return prop_get(jsdisp, prop, val);
2302 HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t *val)
2304 DISPPARAMS dp = {NULL,NULL,0,0};
2305 jsdisp_t *jsdisp;
2306 VARIANT var;
2307 HRESULT hres;
2309 jsdisp = iface_to_jsdisp(disp);
2310 if(jsdisp && jsdisp->ctx == ctx) {
2311 hres = jsdisp_propget(jsdisp, id, val);
2312 jsdisp_release(jsdisp);
2313 return hres;
2316 V_VT(&var) = VT_EMPTY;
2317 hres = disp_invoke(ctx, disp, id, INVOKE_PROPERTYGET, &dp, &var);
2318 if(SUCCEEDED(hres)) {
2319 hres = variant_to_jsval(&var, val);
2320 VariantClear(&var);
2322 return hres;
2325 HRESULT jsdisp_delete_idx(jsdisp_t *obj, DWORD idx)
2327 WCHAR buf[12];
2328 dispex_prop_t *prop;
2329 BOOL b;
2330 HRESULT hres;
2332 swprintf(buf, ARRAY_SIZE(buf), L"%d", idx);
2334 hres = find_prop_name(obj, string_hash(buf), buf, &prop);
2335 if(FAILED(hres) || !prop)
2336 return hres;
2338 hres = delete_prop(prop, &b);
2339 if(FAILED(hres))
2340 return hres;
2341 return b ? S_OK : JS_E_INVALID_ACTION;
2344 HRESULT disp_delete(IDispatch *disp, DISPID id, BOOL *ret)
2346 IDispatchEx *dispex;
2347 jsdisp_t *jsdisp;
2348 HRESULT hres;
2350 jsdisp = iface_to_jsdisp(disp);
2351 if(jsdisp) {
2352 dispex_prop_t *prop;
2354 prop = get_prop(jsdisp, id);
2355 if(prop)
2356 hres = delete_prop(prop, ret);
2357 else
2358 hres = DISP_E_MEMBERNOTFOUND;
2360 jsdisp_release(jsdisp);
2361 return hres;
2364 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
2365 if(FAILED(hres)) {
2366 *ret = FALSE;
2367 return S_OK;
2370 hres = IDispatchEx_DeleteMemberByDispID(dispex, id);
2371 IDispatchEx_Release(dispex);
2372 if(FAILED(hres))
2373 return hres;
2375 *ret = hres == S_OK;
2376 return S_OK;
2379 HRESULT jsdisp_next_prop(jsdisp_t *obj, DISPID id, enum jsdisp_enum_type enum_type, DISPID *ret)
2381 dispex_prop_t *iter;
2382 HRESULT hres;
2384 if(id == DISPID_STARTENUM && enum_type == JSDISP_ENUM_ALL) {
2385 hres = fill_protrefs(obj);
2386 if(FAILED(hres))
2387 return hres;
2390 if(id + 1 < 0 || id+1 >= obj->prop_cnt)
2391 return S_FALSE;
2393 for(iter = &obj->props[id + 1]; iter < obj->props + obj->prop_cnt; iter++) {
2394 if(!iter->name || iter->type == PROP_DELETED)
2395 continue;
2396 if(enum_type != JSDISP_ENUM_ALL && iter->type == PROP_PROTREF)
2397 continue;
2398 if(enum_type != JSDISP_ENUM_OWN && !(get_flags(obj, iter) & PROPF_ENUMERABLE))
2399 continue;
2400 *ret = prop_to_id(obj, iter);
2401 return S_OK;
2404 return S_FALSE;
2407 HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL *ret)
2409 IDispatchEx *dispex;
2410 jsdisp_t *jsdisp;
2411 BSTR bstr;
2412 HRESULT hres;
2414 jsdisp = iface_to_jsdisp(disp);
2415 if(jsdisp) {
2416 dispex_prop_t *prop;
2417 const WCHAR *ptr;
2419 ptr = jsstr_flatten(name);
2420 if(!ptr) {
2421 jsdisp_release(jsdisp);
2422 return E_OUTOFMEMORY;
2425 hres = find_prop_name(jsdisp, string_hash(ptr), ptr, &prop);
2426 if(prop) {
2427 hres = delete_prop(prop, ret);
2428 }else {
2429 *ret = TRUE;
2430 hres = S_OK;
2433 jsdisp_release(jsdisp);
2434 return hres;
2437 bstr = SysAllocStringLen(NULL, jsstr_length(name));
2438 if(!bstr)
2439 return E_OUTOFMEMORY;
2440 jsstr_flush(name, bstr);
2442 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
2443 if(SUCCEEDED(hres)) {
2444 hres = IDispatchEx_DeleteMemberByName(dispex, bstr, make_grfdex(ctx, fdexNameCaseSensitive));
2445 if(SUCCEEDED(hres))
2446 *ret = hres == S_OK;
2447 IDispatchEx_Release(dispex);
2448 }else {
2449 DISPID id;
2451 hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, &id);
2452 if(SUCCEEDED(hres)) {
2453 /* Property exists and we can't delete it from pure IDispatch interface, so return false. */
2454 *ret = FALSE;
2455 }else if(hres == DISP_E_UNKNOWNNAME) {
2456 /* Property doesn't exist, so nothing to delete */
2457 *ret = TRUE;
2458 hres = S_OK;
2462 SysFreeString(bstr);
2463 return hres;
2466 HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_only,
2467 property_desc_t *desc)
2469 dispex_prop_t *prop;
2470 HRESULT hres;
2472 hres = find_prop_name(obj, string_hash(name), name, &prop);
2473 if(FAILED(hres))
2474 return hres;
2476 if(!prop)
2477 return DISP_E_UNKNOWNNAME;
2479 memset(desc, 0, sizeof(*desc));
2481 switch(prop->type) {
2482 case PROP_BUILTIN:
2483 case PROP_JSVAL:
2484 desc->mask |= PROPF_WRITABLE;
2485 desc->explicit_value = TRUE;
2486 if(!flags_only) {
2487 hres = prop_get(obj, prop, &desc->value);
2488 if(FAILED(hres))
2489 return hres;
2491 break;
2492 case PROP_ACCESSOR:
2493 desc->explicit_getter = desc->explicit_setter = TRUE;
2494 if(!flags_only) {
2495 desc->getter = prop->u.accessor.getter
2496 ? jsdisp_addref(prop->u.accessor.getter) : NULL;
2497 desc->setter = prop->u.accessor.setter
2498 ? jsdisp_addref(prop->u.accessor.setter) : NULL;
2500 break;
2501 default:
2502 return DISP_E_UNKNOWNNAME;
2505 desc->flags = prop->flags & (PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE);
2506 desc->mask |= PROPF_ENUMERABLE | PROPF_CONFIGURABLE;
2507 return S_OK;
2510 HRESULT jsdisp_define_property(jsdisp_t *obj, const WCHAR *name, property_desc_t *desc)
2512 dispex_prop_t *prop;
2513 HRESULT hres;
2515 hres = find_prop_name(obj, string_hash(name), name, &prop);
2516 if(FAILED(hres))
2517 return hres;
2519 if((!prop || prop->type == PROP_DELETED) && !obj->extensible)
2520 return throw_error(obj->ctx, JS_E_OBJECT_NONEXTENSIBLE, name);
2522 if(!prop && !(prop = alloc_prop(obj, name, PROP_DELETED, 0)))
2523 return E_OUTOFMEMORY;
2525 if(prop->type == PROP_DELETED || prop->type == PROP_PROTREF) {
2526 prop->flags = desc->flags;
2527 if(desc->explicit_getter || desc->explicit_setter) {
2528 prop->type = PROP_ACCESSOR;
2529 prop->u.accessor.getter = desc->getter ? jsdisp_addref(desc->getter) : NULL;
2530 prop->u.accessor.setter = desc->setter ? jsdisp_addref(desc->setter) : NULL;
2531 TRACE("%s = accessor { get: %p set: %p }\n", debugstr_w(name),
2532 prop->u.accessor.getter, prop->u.accessor.setter);
2533 }else {
2534 prop->type = PROP_JSVAL;
2535 if(desc->explicit_value) {
2536 hres = jsval_copy(desc->value, &prop->u.val);
2537 if(FAILED(hres))
2538 return hres;
2539 }else {
2540 prop->u.val = jsval_undefined();
2542 TRACE("%s = %s\n", debugstr_w(name), debugstr_jsval(prop->u.val));
2544 return S_OK;
2547 TRACE("existing prop %s prop flags %x desc flags %x desc mask %x\n", debugstr_w(name),
2548 prop->flags, desc->flags, desc->mask);
2550 if(!(prop->flags & PROPF_CONFIGURABLE)) {
2551 if(((desc->mask & PROPF_CONFIGURABLE) && (desc->flags & PROPF_CONFIGURABLE))
2552 || ((desc->mask & PROPF_ENUMERABLE)
2553 && ((desc->flags & PROPF_ENUMERABLE) != (prop->flags & PROPF_ENUMERABLE))))
2554 return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name);
2557 if(desc->explicit_value || (desc->mask & PROPF_WRITABLE)) {
2558 if(prop->type == PROP_ACCESSOR) {
2559 if(!(prop->flags & PROPF_CONFIGURABLE))
2560 return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name);
2561 if(prop->u.accessor.getter)
2562 jsdisp_release(prop->u.accessor.getter);
2563 if(prop->u.accessor.setter)
2564 jsdisp_release(prop->u.accessor.setter);
2566 prop->type = PROP_JSVAL;
2567 hres = jsval_copy(desc->value, &prop->u.val);
2568 if(FAILED(hres)) {
2569 prop->u.val = jsval_undefined();
2570 return hres;
2572 }else {
2573 if(!(prop->flags & PROPF_CONFIGURABLE) && !(prop->flags & PROPF_WRITABLE)) {
2574 if((desc->mask & PROPF_WRITABLE) && (desc->flags & PROPF_WRITABLE))
2575 return throw_error(obj->ctx, JS_E_NONWRITABLE_MODIFIED, name);
2576 if(desc->explicit_value) {
2577 if(prop->type == PROP_JSVAL) {
2578 BOOL eq;
2579 hres = jsval_strict_equal(desc->value, prop->u.val, &eq);
2580 if(FAILED(hres))
2581 return hres;
2582 if(!eq)
2583 return throw_error(obj->ctx, JS_E_NONWRITABLE_MODIFIED, name);
2584 }else {
2585 FIXME("redefinition of property type %d\n", prop->type);
2589 if(desc->explicit_value) {
2590 if(prop->type == PROP_JSVAL)
2591 jsval_release(prop->u.val);
2592 else
2593 prop->type = PROP_JSVAL;
2594 hres = jsval_copy(desc->value, &prop->u.val);
2595 if(FAILED(hres)) {
2596 prop->u.val = jsval_undefined();
2597 return hres;
2601 }else if(desc->explicit_getter || desc->explicit_setter) {
2602 if(prop->type != PROP_ACCESSOR) {
2603 if(!(prop->flags & PROPF_CONFIGURABLE))
2604 return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name);
2605 if(prop->type == PROP_JSVAL)
2606 jsval_release(prop->u.val);
2607 prop->type = PROP_ACCESSOR;
2608 prop->u.accessor.getter = prop->u.accessor.setter = NULL;
2609 }else if(!(prop->flags & PROPF_CONFIGURABLE)) {
2610 if((desc->explicit_getter && desc->getter != prop->u.accessor.getter)
2611 || (desc->explicit_setter && desc->setter != prop->u.accessor.setter))
2612 return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name);
2615 if(desc->explicit_getter) {
2616 if(prop->u.accessor.getter) {
2617 jsdisp_release(prop->u.accessor.getter);
2618 prop->u.accessor.getter = NULL;
2620 if(desc->getter)
2621 prop->u.accessor.getter = jsdisp_addref(desc->getter);
2623 if(desc->explicit_setter) {
2624 if(prop->u.accessor.setter) {
2625 jsdisp_release(prop->u.accessor.setter);
2626 prop->u.accessor.setter = NULL;
2628 if(desc->setter)
2629 prop->u.accessor.setter = jsdisp_addref(desc->setter);
2633 prop->flags = (prop->flags & ~desc->mask) | (desc->flags & desc->mask);
2634 return S_OK;
2637 HRESULT jsdisp_define_data_property(jsdisp_t *obj, const WCHAR *name, unsigned flags, jsval_t value)
2639 property_desc_t prop_desc = { flags, flags, TRUE };
2640 prop_desc.value = value;
2641 return jsdisp_define_property(obj, name, &prop_desc);
2644 void jsdisp_freeze(jsdisp_t *obj, BOOL seal)
2646 unsigned int i;
2648 for(i = 0; i < obj->prop_cnt; i++) {
2649 if(!seal && obj->props[i].type == PROP_JSVAL)
2650 obj->props[i].flags &= ~PROPF_WRITABLE;
2651 obj->props[i].flags &= ~PROPF_CONFIGURABLE;
2654 obj->extensible = FALSE;
2657 BOOL jsdisp_is_frozen(jsdisp_t *obj, BOOL sealed)
2659 unsigned int i;
2661 if(obj->extensible)
2662 return FALSE;
2664 for(i = 0; i < obj->prop_cnt; i++) {
2665 if(obj->props[i].type == PROP_JSVAL) {
2666 if(!sealed && (obj->props[i].flags & PROPF_WRITABLE))
2667 return FALSE;
2668 }else if(obj->props[i].type != PROP_ACCESSOR)
2669 continue;
2670 if(obj->props[i].flags & PROPF_CONFIGURABLE)
2671 return FALSE;
2674 return TRUE;
2677 HRESULT jsdisp_get_prop_name(jsdisp_t *obj, DISPID id, jsstr_t **r)
2679 dispex_prop_t *prop = get_prop(obj, id);
2681 if(!prop || !prop->name || prop->type == PROP_DELETED)
2682 return DISP_E_MEMBERNOTFOUND;
2684 *r = jsstr_alloc(prop->name);
2685 return *r ? S_OK : E_OUTOFMEMORY;