msvcrt: Use fpclass constants from public header.
[wine/zf.git] / dlls / jscript / dispex.c
blob5829cebe55b7589f14f1c972c25deee034d8ed31
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 invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t *prop, WORD flags,
393 unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller)
395 HRESULT hres;
397 switch(prop->type) {
398 case PROP_BUILTIN: {
399 if(flags == DISPATCH_CONSTRUCT && (prop->flags & PROPF_METHOD)) {
400 WARN("%s is not a constructor\n", debugstr_w(prop->name));
401 return E_INVALIDARG;
404 if(prop->name || This->builtin_info->class != JSCLASS_FUNCTION) {
405 vdisp_t vthis;
407 if(This->builtin_info->class != JSCLASS_FUNCTION && prop->u.p->invoke != JSGlobal_eval)
408 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
409 if(jsthis)
410 set_disp(&vthis, jsthis);
411 else
412 set_jsdisp(&vthis, This);
413 hres = prop->u.p->invoke(This->ctx, &vthis, flags, argc, argv, r);
414 vdisp_release(&vthis);
415 }else {
416 /* Function object calls are special case */
417 hres = Function_invoke(This, jsthis, flags, argc, argv, r);
419 return hres;
421 case PROP_PROTREF:
422 return invoke_prop_func(This->prototype, jsthis ? jsthis : (IDispatch *)&This->IDispatchEx_iface,
423 This->prototype->props+prop->u.ref, flags, argc, argv, r, caller);
424 case PROP_JSVAL: {
425 if(!is_object_instance(prop->u.val)) {
426 FIXME("invoke %s\n", debugstr_jsval(prop->u.val));
427 return E_FAIL;
430 TRACE("call %s %p\n", debugstr_w(prop->name), get_object(prop->u.val));
432 return disp_call_value(This->ctx, get_object(prop->u.val),
433 jsthis ? jsthis : (IDispatch*)&This->IDispatchEx_iface,
434 flags, argc, argv, r);
436 case PROP_ACCESSOR:
437 FIXME("accessor\n");
438 return E_NOTIMPL;
439 case PROP_IDX:
440 FIXME("Invoking PROP_IDX not yet supported\n");
441 return E_NOTIMPL;
442 case PROP_DELETED:
443 assert(0);
446 assert(0);
447 return E_FAIL;
450 static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, jsval_t *r)
452 jsdisp_t *prop_obj = This;
453 HRESULT hres;
455 while(prop->type == PROP_PROTREF) {
456 prop_obj = prop_obj->prototype;
457 prop = prop_obj->props + prop->u.ref;
460 switch(prop->type) {
461 case PROP_BUILTIN:
462 if(prop->u.p->getter) {
463 hres = prop->u.p->getter(This->ctx, This, r);
464 }else {
465 jsdisp_t *obj;
467 assert(prop->u.p->invoke != NULL);
468 hres = create_builtin_function(This->ctx, prop->u.p->invoke, prop->u.p->name, NULL,
469 prop->u.p->flags, NULL, &obj);
470 if(FAILED(hres))
471 break;
473 prop->type = PROP_JSVAL;
474 prop->u.val = jsval_obj(obj);
476 jsdisp_addref(obj);
477 *r = jsval_obj(obj);
479 break;
480 case PROP_JSVAL:
481 hres = jsval_copy(prop->u.val, r);
482 break;
483 case PROP_ACCESSOR:
484 if(prop->u.accessor.getter) {
485 hres = jsdisp_call_value(prop->u.accessor.getter, to_disp(This),
486 DISPATCH_METHOD, 0, NULL, r);
487 }else {
488 *r = jsval_undefined();
489 hres = S_OK;
491 break;
492 case PROP_IDX:
493 hres = prop_obj->builtin_info->idx_get(prop_obj, prop->u.idx, r);
494 break;
495 default:
496 ERR("type %d\n", prop->type);
497 return E_FAIL;
500 if(FAILED(hres)) {
501 TRACE("fail %08x\n", hres);
502 return hres;
505 TRACE("%s ret %s\n", debugstr_w(prop->name), debugstr_jsval(*r));
506 return hres;
509 static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val)
511 HRESULT hres;
513 if(prop->type == PROP_PROTREF) {
514 dispex_prop_t *prop_iter = prop;
515 jsdisp_t *prototype_iter = This;
517 do {
518 prototype_iter = prototype_iter->prototype;
519 prop_iter = prototype_iter->props + prop_iter->u.ref;
520 } while(prop_iter->type == PROP_PROTREF);
522 if(prop_iter->type == PROP_ACCESSOR)
523 prop = prop_iter;
526 switch(prop->type) {
527 case PROP_BUILTIN:
528 if(!prop->u.p->setter) {
529 TRACE("getter with no setter\n");
530 return S_OK;
532 return prop->u.p->setter(This->ctx, This, val);
533 case PROP_PROTREF:
534 case PROP_DELETED:
535 prop->type = PROP_JSVAL;
536 prop->flags = PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE;
537 prop->u.val = jsval_undefined();
538 break;
539 case PROP_JSVAL:
540 if(!(prop->flags & PROPF_WRITABLE))
541 return S_OK;
543 jsval_release(prop->u.val);
544 break;
545 case PROP_ACCESSOR:
546 if(!prop->u.accessor.setter) {
547 TRACE("no setter\n");
548 return S_OK;
550 return jsdisp_call_value(prop->u.accessor.setter, to_disp(This), DISPATCH_METHOD, 1, &val, NULL);
551 case PROP_IDX:
552 if(!This->builtin_info->idx_put) {
553 TRACE("no put_idx\n");
554 return S_OK;
556 return This->builtin_info->idx_put(This, prop->u.idx, val);
557 default:
558 ERR("type %d\n", prop->type);
559 return E_FAIL;
562 TRACE("%s = %s\n", debugstr_w(prop->name), debugstr_jsval(val));
564 hres = jsval_copy(val, &prop->u.val);
565 if(FAILED(hres))
566 return hres;
568 if(This->builtin_info->on_put)
569 This->builtin_info->on_put(This, prop->name);
571 return S_OK;
574 HRESULT builtin_set_const(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t value)
576 TRACE("%p %s\n", jsthis, debugstr_jsval(value));
577 return S_OK;
580 static HRESULT fill_protrefs(jsdisp_t *This)
582 dispex_prop_t *iter, *prop;
583 HRESULT hres;
585 if(!This->prototype)
586 return S_OK;
588 fill_protrefs(This->prototype);
590 for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) {
591 if(!iter->name)
592 continue;
593 hres = find_prop_name(This, iter->hash, iter->name, &prop);
594 if(FAILED(hres))
595 return hres;
596 if(!prop || prop->type==PROP_DELETED) {
597 if(prop) {
598 prop->type = PROP_PROTREF;
599 prop->flags = 0;
600 prop->u.ref = iter - This->prototype->props;
601 }else {
602 prop = alloc_protref(This, iter->name, iter - This->prototype->props);
603 if(!prop)
604 return E_OUTOFMEMORY;
609 return S_OK;
612 struct typeinfo_func {
613 dispex_prop_t *prop;
614 function_code_t *code;
617 typedef struct {
618 ITypeInfo ITypeInfo_iface;
619 ITypeComp ITypeComp_iface;
620 LONG ref;
622 UINT num_funcs;
623 UINT num_vars;
624 struct typeinfo_func *funcs;
625 dispex_prop_t **vars;
627 jsdisp_t *jsdisp;
628 } ScriptTypeInfo;
630 static struct typeinfo_func *get_func_from_memid(const ScriptTypeInfo *typeinfo, MEMBERID memid)
632 UINT a = 0, b = typeinfo->num_funcs;
634 while (a < b)
636 UINT i = (a + b - 1) / 2;
637 MEMBERID func_memid = prop_to_id(typeinfo->jsdisp, typeinfo->funcs[i].prop);
639 if (memid == func_memid)
640 return &typeinfo->funcs[i];
641 else if (memid < func_memid)
642 b = i;
643 else
644 a = i + 1;
646 return NULL;
649 static dispex_prop_t *get_var_from_memid(const ScriptTypeInfo *typeinfo, MEMBERID memid)
651 UINT a = 0, b = typeinfo->num_vars;
653 while (a < b)
655 UINT i = (a + b - 1) / 2;
656 MEMBERID var_memid = prop_to_id(typeinfo->jsdisp, typeinfo->vars[i]);
658 if (memid == var_memid)
659 return typeinfo->vars[i];
660 else if (memid < var_memid)
661 b = i;
662 else
663 a = i + 1;
665 return NULL;
668 static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeInfo(ITypeInfo *iface)
670 return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeInfo_iface);
673 static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeComp(ITypeComp *iface)
675 return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeComp_iface);
678 static HRESULT WINAPI ScriptTypeInfo_QueryInterface(ITypeInfo *iface, REFIID riid, void **ppv)
680 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
682 if (IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_ITypeInfo, riid))
683 *ppv = &This->ITypeInfo_iface;
684 else if (IsEqualGUID(&IID_ITypeComp, riid))
685 *ppv = &This->ITypeComp_iface;
686 else
688 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
689 *ppv = NULL;
690 return E_NOINTERFACE;
693 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
694 IUnknown_AddRef((IUnknown*)*ppv);
695 return S_OK;
698 static ULONG WINAPI ScriptTypeInfo_AddRef(ITypeInfo *iface)
700 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
701 LONG ref = InterlockedIncrement(&This->ref);
703 TRACE("(%p) ref=%d\n", This, ref);
705 return ref;
708 static ULONG WINAPI ScriptTypeInfo_Release(ITypeInfo *iface)
710 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
711 LONG ref = InterlockedDecrement(&This->ref);
712 UINT i;
714 TRACE("(%p) ref=%d\n", This, ref);
716 if (!ref)
718 for (i = This->num_funcs; i--;)
719 release_bytecode(This->funcs[i].code->bytecode);
720 IDispatchEx_Release(&This->jsdisp->IDispatchEx_iface);
721 heap_free(This->funcs);
722 heap_free(This->vars);
723 heap_free(This);
725 return ref;
728 static HRESULT WINAPI ScriptTypeInfo_GetTypeAttr(ITypeInfo *iface, TYPEATTR **ppTypeAttr)
730 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
731 TYPEATTR *attr;
733 TRACE("(%p)->(%p)\n", This, ppTypeAttr);
735 if (!ppTypeAttr) return E_INVALIDARG;
737 attr = heap_alloc_zero(sizeof(*attr));
738 if (!attr) return E_OUTOFMEMORY;
740 attr->guid = GUID_JScriptTypeInfo;
741 attr->lcid = LOCALE_USER_DEFAULT;
742 attr->memidConstructor = MEMBERID_NIL;
743 attr->memidDestructor = MEMBERID_NIL;
744 attr->cbSizeInstance = 4;
745 attr->typekind = TKIND_DISPATCH;
746 attr->cFuncs = This->num_funcs;
747 attr->cVars = This->num_vars;
748 attr->cImplTypes = 1;
749 attr->cbSizeVft = sizeof(IDispatchVtbl);
750 attr->cbAlignment = 4;
751 attr->wTypeFlags = TYPEFLAG_FDISPATCHABLE;
752 attr->wMajorVerNum = JSCRIPT_MAJOR_VERSION;
753 attr->wMinorVerNum = JSCRIPT_MINOR_VERSION;
755 *ppTypeAttr = attr;
756 return S_OK;
759 static HRESULT WINAPI ScriptTypeInfo_GetTypeComp(ITypeInfo *iface, ITypeComp **ppTComp)
761 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
763 TRACE("(%p)->(%p)\n", This, ppTComp);
765 if (!ppTComp) return E_INVALIDARG;
767 *ppTComp = &This->ITypeComp_iface;
768 ITypeInfo_AddRef(iface);
769 return S_OK;
772 static HRESULT WINAPI ScriptTypeInfo_GetFuncDesc(ITypeInfo *iface, UINT index, FUNCDESC **ppFuncDesc)
774 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
775 struct typeinfo_func *func;
776 FUNCDESC *desc;
777 unsigned i;
779 TRACE("(%p)->(%u %p)\n", This, index, ppFuncDesc);
781 if (!ppFuncDesc) return E_INVALIDARG;
782 if (index >= This->num_funcs) return TYPE_E_ELEMENTNOTFOUND;
783 func = &This->funcs[index];
785 /* Store the parameter array after the FUNCDESC structure */
786 desc = heap_alloc_zero(sizeof(*desc) + sizeof(ELEMDESC) * func->code->param_cnt);
787 if (!desc) return E_OUTOFMEMORY;
789 desc->memid = prop_to_id(This->jsdisp, func->prop);
790 desc->funckind = FUNC_DISPATCH;
791 desc->invkind = INVOKE_FUNC;
792 desc->callconv = CC_STDCALL;
793 desc->cParams = func->code->param_cnt;
794 desc->elemdescFunc.tdesc.vt = VT_VARIANT;
796 if (func->code->param_cnt) desc->lprgelemdescParam = (ELEMDESC*)(desc + 1);
797 for (i = 0; i < func->code->param_cnt; i++)
798 desc->lprgelemdescParam[i].tdesc.vt = VT_VARIANT;
800 *ppFuncDesc = desc;
801 return S_OK;
804 static HRESULT WINAPI ScriptTypeInfo_GetVarDesc(ITypeInfo *iface, UINT index, VARDESC **ppVarDesc)
806 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
807 VARDESC *desc;
809 TRACE("(%p)->(%u %p)\n", This, index, ppVarDesc);
811 if (!ppVarDesc) return E_INVALIDARG;
812 if (index >= This->num_vars) return TYPE_E_ELEMENTNOTFOUND;
814 desc = heap_alloc_zero(sizeof(*desc));
815 if (!desc) return E_OUTOFMEMORY;
817 desc->memid = prop_to_id(This->jsdisp, This->vars[index]);
818 desc->varkind = VAR_DISPATCH;
819 desc->elemdescVar.tdesc.vt = VT_VARIANT;
821 *ppVarDesc = desc;
822 return S_OK;
825 static HRESULT WINAPI ScriptTypeInfo_GetNames(ITypeInfo *iface, MEMBERID memid, BSTR *rgBstrNames,
826 UINT cMaxNames, UINT *pcNames)
828 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
829 struct typeinfo_func *func;
830 ITypeInfo *disp_typeinfo;
831 dispex_prop_t *var;
832 HRESULT hr;
833 UINT i = 0;
835 TRACE("(%p)->(%d %p %u %p)\n", This, memid, rgBstrNames, cMaxNames, pcNames);
837 if (!rgBstrNames || !pcNames) return E_INVALIDARG;
838 if (memid <= 0) return TYPE_E_ELEMENTNOTFOUND;
840 func = get_func_from_memid(This, memid);
841 if (!func)
843 var = get_var_from_memid(This, memid);
844 if (!var)
846 hr = get_dispatch_typeinfo(&disp_typeinfo);
847 if (FAILED(hr)) return hr;
849 return ITypeInfo_GetNames(disp_typeinfo, memid, rgBstrNames, cMaxNames, pcNames);
853 *pcNames = 0;
854 if (!cMaxNames) return S_OK;
856 rgBstrNames[0] = SysAllocString(func ? func->prop->name : var->name);
857 if (!rgBstrNames[0]) return E_OUTOFMEMORY;
858 i++;
860 if (func)
862 unsigned num = min(cMaxNames, func->code->param_cnt + 1);
864 for (; i < num; i++)
866 if (!(rgBstrNames[i] = SysAllocString(func->code->params[i - 1])))
868 do SysFreeString(rgBstrNames[--i]); while (i);
869 return E_OUTOFMEMORY;
874 *pcNames = i;
875 return S_OK;
878 static HRESULT WINAPI ScriptTypeInfo_GetRefTypeOfImplType(ITypeInfo *iface, UINT index, HREFTYPE *pRefType)
880 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
882 TRACE("(%p)->(%u %p)\n", This, index, pRefType);
884 /* We only inherit from IDispatch */
885 if (!pRefType) return E_INVALIDARG;
886 if (index != 0) return TYPE_E_ELEMENTNOTFOUND;
888 *pRefType = 1;
889 return S_OK;
892 static HRESULT WINAPI ScriptTypeInfo_GetImplTypeFlags(ITypeInfo *iface, UINT index, INT *pImplTypeFlags)
894 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
896 TRACE("(%p)->(%u %p)\n", This, index, pImplTypeFlags);
898 if (!pImplTypeFlags) return E_INVALIDARG;
899 if (index != 0) return TYPE_E_ELEMENTNOTFOUND;
901 *pImplTypeFlags = 0;
902 return S_OK;
905 static HRESULT WINAPI ScriptTypeInfo_GetIDsOfNames(ITypeInfo *iface, LPOLESTR *rgszNames, UINT cNames,
906 MEMBERID *pMemId)
908 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
909 ITypeInfo *disp_typeinfo;
910 const WCHAR *name;
911 HRESULT hr = S_OK;
912 int i, j, arg;
914 TRACE("(%p)->(%p %u %p)\n", This, rgszNames, cNames, pMemId);
916 if (!rgszNames || !cNames || !pMemId) return E_INVALIDARG;
918 for (i = 0; i < cNames; i++) pMemId[i] = MEMBERID_NIL;
919 name = rgszNames[0];
921 for (i = 0; i < This->num_funcs; i++)
923 struct typeinfo_func *func = &This->funcs[i];
925 if (wcsicmp(name, func->prop->name)) continue;
926 pMemId[0] = prop_to_id(This->jsdisp, func->prop);
928 for (j = 1; j < cNames; j++)
930 name = rgszNames[j];
931 for (arg = func->code->param_cnt; --arg >= 0;)
932 if (!wcsicmp(name, func->code->params[arg]))
933 break;
934 if (arg >= 0)
935 pMemId[j] = arg;
936 else
937 hr = DISP_E_UNKNOWNNAME;
939 return hr;
942 for (i = 0; i < This->num_vars; i++)
944 dispex_prop_t *var = This->vars[i];
946 if (wcsicmp(name, var->name)) continue;
947 pMemId[0] = prop_to_id(This->jsdisp, var);
948 return S_OK;
951 /* Look into the inherited IDispatch */
952 hr = get_dispatch_typeinfo(&disp_typeinfo);
953 if (FAILED(hr)) return hr;
955 return ITypeInfo_GetIDsOfNames(disp_typeinfo, rgszNames, cNames, pMemId);
958 static HRESULT WINAPI ScriptTypeInfo_Invoke(ITypeInfo *iface, PVOID pvInstance, MEMBERID memid, WORD wFlags,
959 DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
961 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
962 ITypeInfo *disp_typeinfo;
963 IDispatch *disp;
964 HRESULT hr;
966 TRACE("(%p)->(%p %d %d %p %p %p %p)\n", This, pvInstance, memid, wFlags,
967 pDispParams, pVarResult, pExcepInfo, puArgErr);
969 if (!pvInstance) return E_INVALIDARG;
970 if (memid <= 0) return TYPE_E_ELEMENTNOTFOUND;
972 if (!get_func_from_memid(This, memid) && !get_var_from_memid(This, memid))
974 hr = get_dispatch_typeinfo(&disp_typeinfo);
975 if (FAILED(hr)) return hr;
977 return ITypeInfo_Invoke(disp_typeinfo, pvInstance, memid, wFlags, pDispParams,
978 pVarResult, pExcepInfo, puArgErr);
981 hr = IUnknown_QueryInterface((IUnknown*)pvInstance, &IID_IDispatch, (void**)&disp);
982 if (FAILED(hr)) return hr;
984 hr = IDispatch_Invoke(disp, memid, &IID_NULL, LOCALE_USER_DEFAULT, wFlags,
985 pDispParams, pVarResult, pExcepInfo, puArgErr);
986 IDispatch_Release(disp);
988 return hr;
991 static HRESULT WINAPI ScriptTypeInfo_GetDocumentation(ITypeInfo *iface, MEMBERID memid, BSTR *pBstrName,
992 BSTR *pBstrDocString, DWORD *pdwHelpContext, BSTR *pBstrHelpFile)
994 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
995 struct typeinfo_func *func;
996 ITypeInfo *disp_typeinfo;
997 dispex_prop_t *var;
998 HRESULT hr;
1000 TRACE("(%p)->(%d %p %p %p %p)\n", This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
1002 if (pBstrDocString) *pBstrDocString = NULL;
1003 if (pdwHelpContext) *pdwHelpContext = 0;
1004 if (pBstrHelpFile) *pBstrHelpFile = NULL;
1006 if (memid == MEMBERID_NIL)
1008 if (pBstrName && !(*pBstrName = SysAllocString(L"JScriptTypeInfo")))
1009 return E_OUTOFMEMORY;
1010 if (pBstrDocString &&
1011 !(*pBstrDocString = SysAllocString(L"JScript Type Info")))
1013 if (pBstrName) SysFreeString(*pBstrName);
1014 return E_OUTOFMEMORY;
1016 return S_OK;
1018 if (memid <= 0) return TYPE_E_ELEMENTNOTFOUND;
1020 func = get_func_from_memid(This, memid);
1021 if (!func)
1023 var = get_var_from_memid(This, memid);
1024 if (!var)
1026 hr = get_dispatch_typeinfo(&disp_typeinfo);
1027 if (FAILED(hr)) return hr;
1029 return ITypeInfo_GetDocumentation(disp_typeinfo, memid, pBstrName, pBstrDocString,
1030 pdwHelpContext, pBstrHelpFile);
1034 if (pBstrName)
1036 *pBstrName = SysAllocString(func ? func->prop->name : var->name);
1038 if (!*pBstrName)
1039 return E_OUTOFMEMORY;
1041 return S_OK;
1044 static HRESULT WINAPI ScriptTypeInfo_GetDllEntry(ITypeInfo *iface, MEMBERID memid, INVOKEKIND invKind,
1045 BSTR *pBstrDllName, BSTR *pBstrName, WORD *pwOrdinal)
1047 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1048 ITypeInfo *disp_typeinfo;
1049 HRESULT hr;
1051 TRACE("(%p)->(%d %d %p %p %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
1053 if (pBstrDllName) *pBstrDllName = NULL;
1054 if (pBstrName) *pBstrName = NULL;
1055 if (pwOrdinal) *pwOrdinal = 0;
1057 if (!get_func_from_memid(This, memid) && !get_var_from_memid(This, memid))
1059 hr = get_dispatch_typeinfo(&disp_typeinfo);
1060 if (FAILED(hr)) return hr;
1062 return ITypeInfo_GetDllEntry(disp_typeinfo, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
1064 return TYPE_E_BADMODULEKIND;
1067 static HRESULT WINAPI ScriptTypeInfo_GetRefTypeInfo(ITypeInfo *iface, HREFTYPE hRefType, ITypeInfo **ppTInfo)
1069 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1070 HRESULT hr;
1072 TRACE("(%p)->(%x %p)\n", This, hRefType, ppTInfo);
1074 if (!ppTInfo || (INT)hRefType < 0) return E_INVALIDARG;
1076 if (hRefType & ~3) return E_FAIL;
1077 if (hRefType & 1)
1079 hr = get_dispatch_typeinfo(ppTInfo);
1080 if (FAILED(hr)) return hr;
1082 else
1083 *ppTInfo = iface;
1085 ITypeInfo_AddRef(*ppTInfo);
1086 return S_OK;
1089 static HRESULT WINAPI ScriptTypeInfo_AddressOfMember(ITypeInfo *iface, MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
1091 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1092 ITypeInfo *disp_typeinfo;
1093 HRESULT hr;
1095 TRACE("(%p)->(%d %d %p)\n", This, memid, invKind, ppv);
1097 if (!ppv) return E_INVALIDARG;
1098 *ppv = NULL;
1100 if (!get_func_from_memid(This, memid) && !get_var_from_memid(This, memid))
1102 hr = get_dispatch_typeinfo(&disp_typeinfo);
1103 if (FAILED(hr)) return hr;
1105 return ITypeInfo_AddressOfMember(disp_typeinfo, memid, invKind, ppv);
1107 return TYPE_E_BADMODULEKIND;
1110 static HRESULT WINAPI ScriptTypeInfo_CreateInstance(ITypeInfo *iface, IUnknown *pUnkOuter, REFIID riid, PVOID *ppvObj)
1112 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1114 TRACE("(%p)->(%p %s %p)\n", This, pUnkOuter, debugstr_guid(riid), ppvObj);
1116 if (!ppvObj) return E_INVALIDARG;
1118 *ppvObj = NULL;
1119 return TYPE_E_BADMODULEKIND;
1122 static HRESULT WINAPI ScriptTypeInfo_GetMops(ITypeInfo *iface, MEMBERID memid, BSTR *pBstrMops)
1124 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1125 ITypeInfo *disp_typeinfo;
1126 HRESULT hr;
1128 TRACE("(%p)->(%d %p)\n", This, memid, pBstrMops);
1130 if (!pBstrMops) return E_INVALIDARG;
1132 if (!get_func_from_memid(This, memid) && !get_var_from_memid(This, memid))
1134 hr = get_dispatch_typeinfo(&disp_typeinfo);
1135 if (FAILED(hr)) return hr;
1137 return ITypeInfo_GetMops(disp_typeinfo, memid, pBstrMops);
1140 *pBstrMops = NULL;
1141 return S_OK;
1144 static HRESULT WINAPI ScriptTypeInfo_GetContainingTypeLib(ITypeInfo *iface, ITypeLib **ppTLib, UINT *pIndex)
1146 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1148 FIXME("(%p)->(%p %p)\n", This, ppTLib, pIndex);
1150 return E_NOTIMPL;
1153 static void WINAPI ScriptTypeInfo_ReleaseTypeAttr(ITypeInfo *iface, TYPEATTR *pTypeAttr)
1155 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1157 TRACE("(%p)->(%p)\n", This, pTypeAttr);
1159 heap_free(pTypeAttr);
1162 static void WINAPI ScriptTypeInfo_ReleaseFuncDesc(ITypeInfo *iface, FUNCDESC *pFuncDesc)
1164 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1166 TRACE("(%p)->(%p)\n", This, pFuncDesc);
1168 heap_free(pFuncDesc);
1171 static void WINAPI ScriptTypeInfo_ReleaseVarDesc(ITypeInfo *iface, VARDESC *pVarDesc)
1173 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1175 TRACE("(%p)->(%p)\n", This, pVarDesc);
1177 heap_free(pVarDesc);
1180 static const ITypeInfoVtbl ScriptTypeInfoVtbl = {
1181 ScriptTypeInfo_QueryInterface,
1182 ScriptTypeInfo_AddRef,
1183 ScriptTypeInfo_Release,
1184 ScriptTypeInfo_GetTypeAttr,
1185 ScriptTypeInfo_GetTypeComp,
1186 ScriptTypeInfo_GetFuncDesc,
1187 ScriptTypeInfo_GetVarDesc,
1188 ScriptTypeInfo_GetNames,
1189 ScriptTypeInfo_GetRefTypeOfImplType,
1190 ScriptTypeInfo_GetImplTypeFlags,
1191 ScriptTypeInfo_GetIDsOfNames,
1192 ScriptTypeInfo_Invoke,
1193 ScriptTypeInfo_GetDocumentation,
1194 ScriptTypeInfo_GetDllEntry,
1195 ScriptTypeInfo_GetRefTypeInfo,
1196 ScriptTypeInfo_AddressOfMember,
1197 ScriptTypeInfo_CreateInstance,
1198 ScriptTypeInfo_GetMops,
1199 ScriptTypeInfo_GetContainingTypeLib,
1200 ScriptTypeInfo_ReleaseTypeAttr,
1201 ScriptTypeInfo_ReleaseFuncDesc,
1202 ScriptTypeInfo_ReleaseVarDesc
1205 static HRESULT WINAPI ScriptTypeComp_QueryInterface(ITypeComp *iface, REFIID riid, void **ppv)
1207 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1208 return ITypeInfo_QueryInterface(&This->ITypeInfo_iface, riid, ppv);
1211 static ULONG WINAPI ScriptTypeComp_AddRef(ITypeComp *iface)
1213 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1214 return ITypeInfo_AddRef(&This->ITypeInfo_iface);
1217 static ULONG WINAPI ScriptTypeComp_Release(ITypeComp *iface)
1219 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1220 return ITypeInfo_Release(&This->ITypeInfo_iface);
1223 static HRESULT WINAPI ScriptTypeComp_Bind(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal, WORD wFlags,
1224 ITypeInfo **ppTInfo, DESCKIND *pDescKind, BINDPTR *pBindPtr)
1226 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1227 UINT flags = wFlags ? wFlags : ~0;
1228 ITypeInfo *disp_typeinfo;
1229 ITypeComp *disp_typecomp;
1230 HRESULT hr;
1231 UINT i;
1233 TRACE("(%p)->(%s %08x %d %p %p %p)\n", This, debugstr_w(szName), lHashVal,
1234 wFlags, ppTInfo, pDescKind, pBindPtr);
1236 if (!szName || !ppTInfo || !pDescKind || !pBindPtr)
1237 return E_INVALIDARG;
1239 for (i = 0; i < This->num_funcs; i++)
1241 if (wcsicmp(szName, This->funcs[i].prop->name)) continue;
1242 if (!(flags & INVOKE_FUNC)) return TYPE_E_TYPEMISMATCH;
1244 hr = ITypeInfo_GetFuncDesc(&This->ITypeInfo_iface, i, &pBindPtr->lpfuncdesc);
1245 if (FAILED(hr)) return hr;
1247 *pDescKind = DESCKIND_FUNCDESC;
1248 *ppTInfo = &This->ITypeInfo_iface;
1249 ITypeInfo_AddRef(*ppTInfo);
1250 return S_OK;
1253 for (i = 0; i < This->num_vars; i++)
1255 if (wcsicmp(szName, This->vars[i]->name)) continue;
1256 if (!(flags & INVOKE_PROPERTYGET)) return TYPE_E_TYPEMISMATCH;
1258 hr = ITypeInfo_GetVarDesc(&This->ITypeInfo_iface, i, &pBindPtr->lpvardesc);
1259 if (FAILED(hr)) return hr;
1261 *pDescKind = DESCKIND_VARDESC;
1262 *ppTInfo = &This->ITypeInfo_iface;
1263 ITypeInfo_AddRef(*ppTInfo);
1264 return S_OK;
1267 /* Look into the inherited IDispatch */
1268 hr = get_dispatch_typeinfo(&disp_typeinfo);
1269 if (FAILED(hr)) return hr;
1271 hr = ITypeInfo_GetTypeComp(disp_typeinfo, &disp_typecomp);
1272 if (FAILED(hr)) return hr;
1274 hr = ITypeComp_Bind(disp_typecomp, szName, lHashVal, wFlags, ppTInfo, pDescKind, pBindPtr);
1275 ITypeComp_Release(disp_typecomp);
1276 return hr;
1279 static HRESULT WINAPI ScriptTypeComp_BindType(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal,
1280 ITypeInfo **ppTInfo, ITypeComp **ppTComp)
1282 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1283 ITypeInfo *disp_typeinfo;
1284 ITypeComp *disp_typecomp;
1285 HRESULT hr;
1287 TRACE("(%p)->(%s %08x %p %p)\n", This, debugstr_w(szName), lHashVal, ppTInfo, ppTComp);
1289 if (!szName || !ppTInfo || !ppTComp)
1290 return E_INVALIDARG;
1292 /* Look into the inherited IDispatch */
1293 hr = get_dispatch_typeinfo(&disp_typeinfo);
1294 if (FAILED(hr)) return hr;
1296 hr = ITypeInfo_GetTypeComp(disp_typeinfo, &disp_typecomp);
1297 if (FAILED(hr)) return hr;
1299 hr = ITypeComp_BindType(disp_typecomp, szName, lHashVal, ppTInfo, ppTComp);
1300 ITypeComp_Release(disp_typecomp);
1301 return hr;
1304 static const ITypeCompVtbl ScriptTypeCompVtbl = {
1305 ScriptTypeComp_QueryInterface,
1306 ScriptTypeComp_AddRef,
1307 ScriptTypeComp_Release,
1308 ScriptTypeComp_Bind,
1309 ScriptTypeComp_BindType
1312 static inline jsdisp_t *impl_from_IDispatchEx(IDispatchEx *iface)
1314 return CONTAINING_RECORD(iface, jsdisp_t, IDispatchEx_iface);
1317 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
1319 jsdisp_t *This = impl_from_IDispatchEx(iface);
1321 if(IsEqualGUID(&IID_IUnknown, riid)) {
1322 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
1323 *ppv = &This->IDispatchEx_iface;
1324 }else if(IsEqualGUID(&IID_IDispatch, riid)) {
1325 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
1326 *ppv = &This->IDispatchEx_iface;
1327 }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
1328 TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
1329 *ppv = &This->IDispatchEx_iface;
1330 }else {
1331 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
1332 *ppv = NULL;
1333 return E_NOINTERFACE;
1336 jsdisp_addref(This);
1337 return S_OK;
1340 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
1342 jsdisp_t *This = impl_from_IDispatchEx(iface);
1343 jsdisp_addref(This);
1344 return This->ref;
1347 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
1349 jsdisp_t *This = impl_from_IDispatchEx(iface);
1350 ULONG ref = --This->ref;
1351 TRACE("(%p) ref=%d\n", This, ref);
1352 if(!ref)
1353 jsdisp_free(This);
1354 return ref;
1357 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
1359 jsdisp_t *This = impl_from_IDispatchEx(iface);
1361 TRACE("(%p)->(%p)\n", This, pctinfo);
1363 *pctinfo = 1;
1364 return S_OK;
1367 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid,
1368 ITypeInfo **ppTInfo)
1370 jsdisp_t *This = impl_from_IDispatchEx(iface);
1371 dispex_prop_t *prop, *cur, *end, **typevar;
1372 UINT num_funcs = 0, num_vars = 0;
1373 struct typeinfo_func *typefunc;
1374 function_code_t *func_code;
1375 ScriptTypeInfo *typeinfo;
1376 unsigned pos;
1378 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
1380 if (iTInfo != 0) return DISP_E_BADINDEX;
1382 for (prop = This->props, end = prop + This->prop_cnt; prop != end; prop++)
1384 if (!prop->name || prop->type != PROP_JSVAL || !(prop->flags & PROPF_ENUMERABLE))
1385 continue;
1387 /* If two identifiers differ only by case, the TypeInfo fails */
1388 pos = This->props[get_props_idx(This, prop->hash)].bucket_head;
1389 while (pos)
1391 cur = This->props + pos;
1393 if (prop->hash == cur->hash && prop != cur &&
1394 cur->type == PROP_JSVAL && (cur->flags & PROPF_ENUMERABLE) &&
1395 !wcsicmp(prop->name, cur->name))
1397 return TYPE_E_AMBIGUOUSNAME;
1399 pos = cur->bucket_next;
1402 if (is_function_prop(prop))
1404 if (Function_get_code(as_jsdisp(get_object(prop->u.val))))
1405 num_funcs++;
1407 else num_vars++;
1410 if (!(typeinfo = heap_alloc(sizeof(*typeinfo))))
1411 return E_OUTOFMEMORY;
1413 typeinfo->ITypeInfo_iface.lpVtbl = &ScriptTypeInfoVtbl;
1414 typeinfo->ITypeComp_iface.lpVtbl = &ScriptTypeCompVtbl;
1415 typeinfo->ref = 1;
1416 typeinfo->num_vars = num_vars;
1417 typeinfo->num_funcs = num_funcs;
1418 typeinfo->jsdisp = This;
1420 typeinfo->funcs = heap_alloc(sizeof(*typeinfo->funcs) * num_funcs);
1421 if (!typeinfo->funcs)
1423 heap_free(typeinfo);
1424 return E_OUTOFMEMORY;
1427 typeinfo->vars = heap_alloc(sizeof(*typeinfo->vars) * num_vars);
1428 if (!typeinfo->vars)
1430 heap_free(typeinfo->funcs);
1431 heap_free(typeinfo);
1432 return E_OUTOFMEMORY;
1435 typefunc = typeinfo->funcs;
1436 typevar = typeinfo->vars;
1437 for (prop = This->props; prop != end; prop++)
1439 if (!prop->name || prop->type != PROP_JSVAL || !(prop->flags & PROPF_ENUMERABLE))
1440 continue;
1442 if (is_function_prop(prop))
1444 func_code = Function_get_code(as_jsdisp(get_object(prop->u.val)));
1445 if (!func_code) continue;
1447 typefunc->prop = prop;
1448 typefunc->code = func_code;
1449 typefunc++;
1451 /* The function may be deleted, so keep a ref */
1452 bytecode_addref(func_code->bytecode);
1454 else
1455 *typevar++ = prop;
1458 /* Keep a ref to the props and their names */
1459 IDispatchEx_AddRef(&This->IDispatchEx_iface);
1461 *ppTInfo = &typeinfo->ITypeInfo_iface;
1462 return S_OK;
1465 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
1466 LPOLESTR *rgszNames, UINT cNames, LCID lcid,
1467 DISPID *rgDispId)
1469 jsdisp_t *This = impl_from_IDispatchEx(iface);
1470 UINT i;
1471 HRESULT hres;
1473 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1474 lcid, rgDispId);
1476 for(i=0; i < cNames; i++) {
1477 hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[i], 0, rgDispId+i);
1478 if(FAILED(hres))
1479 return hres;
1482 return S_OK;
1485 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
1486 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
1487 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1489 jsdisp_t *This = impl_from_IDispatchEx(iface);
1491 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1492 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1494 return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags,
1495 pDispParams, pVarResult, pExcepInfo, NULL);
1498 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
1500 jsdisp_t *This = impl_from_IDispatchEx(iface);
1502 TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
1504 if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) {
1505 FIXME("Unsupported grfdex %x\n", grfdex);
1506 return E_NOTIMPL;
1509 return jsdisp_get_id(This, bstrName, grfdex, pid);
1512 static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
1513 VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
1515 jsdisp_t *This = impl_from_IDispatchEx(iface);
1516 dispex_prop_t *prop;
1517 jsexcept_t ei;
1518 HRESULT hres;
1520 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
1522 if(pvarRes)
1523 V_VT(pvarRes) = VT_EMPTY;
1525 prop = get_prop(This, id);
1526 if(!prop || prop->type == PROP_DELETED) {
1527 TRACE("invalid id\n");
1528 return DISP_E_MEMBERNOTFOUND;
1531 enter_script(This->ctx, &ei);
1533 switch(wFlags) {
1534 case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
1535 wFlags = DISPATCH_METHOD;
1536 /* fall through */
1537 case DISPATCH_METHOD:
1538 case DISPATCH_CONSTRUCT: {
1539 jsval_t *argv, buf[6], r;
1540 unsigned argc;
1542 hres = convert_params(pdp, buf, &argc, &argv);
1543 if(FAILED(hres))
1544 break;
1546 hres = invoke_prop_func(This, get_this(pdp), prop, wFlags, argc, argv, pvarRes ? &r : NULL, pspCaller);
1547 if(argv != buf)
1548 heap_free(argv);
1549 if(SUCCEEDED(hres) && pvarRes) {
1550 hres = jsval_to_variant(r, pvarRes);
1551 jsval_release(r);
1553 break;
1555 case DISPATCH_PROPERTYGET: {
1556 jsval_t r;
1558 hres = prop_get(This, prop, &r);
1559 if(SUCCEEDED(hres)) {
1560 hres = jsval_to_variant(r, pvarRes);
1561 jsval_release(r);
1563 break;
1565 case DISPATCH_PROPERTYPUT: {
1566 jsval_t val;
1567 DWORD i;
1569 for(i=0; i < pdp->cNamedArgs; i++) {
1570 if(pdp->rgdispidNamedArgs[i] == DISPID_PROPERTYPUT)
1571 break;
1574 if(i == pdp->cNamedArgs) {
1575 TRACE("no value to set\n");
1576 hres = DISP_E_PARAMNOTOPTIONAL;
1577 break;
1580 hres = variant_to_jsval(pdp->rgvarg+i, &val);
1581 if(FAILED(hres))
1582 break;
1584 hres = prop_put(This, prop, val);
1585 jsval_release(val);
1586 break;
1588 default:
1589 FIXME("Unimplemented flags %x\n", wFlags);
1590 hres = E_INVALIDARG;
1591 break;
1594 return leave_script(This->ctx, hres);
1597 static HRESULT delete_prop(dispex_prop_t *prop, BOOL *ret)
1599 if(!(prop->flags & PROPF_CONFIGURABLE)) {
1600 *ret = FALSE;
1601 return S_OK;
1604 *ret = TRUE; /* FIXME: not exactly right */
1606 if(prop->type == PROP_JSVAL) {
1607 jsval_release(prop->u.val);
1608 prop->type = PROP_DELETED;
1610 if(prop->type == PROP_ACCESSOR)
1611 FIXME("not supported on accessor property\n");
1612 return S_OK;
1615 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
1617 jsdisp_t *This = impl_from_IDispatchEx(iface);
1618 dispex_prop_t *prop;
1619 BOOL b;
1620 HRESULT hres;
1622 TRACE("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex);
1624 if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK))
1625 FIXME("Unsupported grfdex %x\n", grfdex);
1627 hres = find_prop_name(This, string_hash(bstrName), bstrName, &prop);
1628 if(FAILED(hres))
1629 return hres;
1630 if(!prop) {
1631 TRACE("not found\n");
1632 return S_OK;
1635 return delete_prop(prop, &b);
1638 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
1640 jsdisp_t *This = impl_from_IDispatchEx(iface);
1641 dispex_prop_t *prop;
1642 BOOL b;
1644 TRACE("(%p)->(%x)\n", This, id);
1646 prop = get_prop(This, id);
1647 if(!prop) {
1648 WARN("invalid id\n");
1649 return DISP_E_MEMBERNOTFOUND;
1652 return delete_prop(prop, &b);
1655 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
1657 jsdisp_t *This = impl_from_IDispatchEx(iface);
1658 FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex);
1659 return E_NOTIMPL;
1662 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
1664 jsdisp_t *This = impl_from_IDispatchEx(iface);
1665 dispex_prop_t *prop;
1667 TRACE("(%p)->(%x %p)\n", This, id, pbstrName);
1669 prop = get_prop(This, id);
1670 if(!prop || !prop->name || prop->type == PROP_DELETED)
1671 return DISP_E_MEMBERNOTFOUND;
1673 *pbstrName = SysAllocString(prop->name);
1674 if(!*pbstrName)
1675 return E_OUTOFMEMORY;
1677 return S_OK;
1680 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
1682 jsdisp_t *This = impl_from_IDispatchEx(iface);
1683 HRESULT hres;
1685 TRACE("(%p)->(%x %x %p)\n", This, grfdex, id, pid);
1687 hres = jsdisp_next_prop(This, id, FALSE, pid);
1688 if(hres == S_FALSE)
1689 *pid = DISPID_STARTENUM;
1690 return hres;
1693 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
1695 jsdisp_t *This = impl_from_IDispatchEx(iface);
1696 FIXME("(%p)->(%p)\n", This, ppunk);
1697 return E_NOTIMPL;
1700 static IDispatchExVtbl DispatchExVtbl = {
1701 DispatchEx_QueryInterface,
1702 DispatchEx_AddRef,
1703 DispatchEx_Release,
1704 DispatchEx_GetTypeInfoCount,
1705 DispatchEx_GetTypeInfo,
1706 DispatchEx_GetIDsOfNames,
1707 DispatchEx_Invoke,
1708 DispatchEx_GetDispID,
1709 DispatchEx_InvokeEx,
1710 DispatchEx_DeleteMemberByName,
1711 DispatchEx_DeleteMemberByDispID,
1712 DispatchEx_GetMemberProperties,
1713 DispatchEx_GetMemberName,
1714 DispatchEx_GetNextDispID,
1715 DispatchEx_GetNameSpaceParent
1718 jsdisp_t *as_jsdisp(IDispatch *disp)
1720 assert(disp->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl);
1721 return impl_from_IDispatchEx((IDispatchEx*)disp);
1724 jsdisp_t *to_jsdisp(IDispatch *disp)
1726 return disp->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl ? impl_from_IDispatchEx((IDispatchEx*)disp) : NULL;
1729 HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype)
1731 TRACE("%p (%p)\n", dispex, prototype);
1733 dispex->IDispatchEx_iface.lpVtbl = &DispatchExVtbl;
1734 dispex->ref = 1;
1735 dispex->builtin_info = builtin_info;
1737 dispex->props = heap_alloc_zero(sizeof(dispex_prop_t)*(dispex->buf_size=4));
1738 if(!dispex->props)
1739 return E_OUTOFMEMORY;
1741 dispex->prototype = prototype;
1742 if(prototype)
1743 jsdisp_addref(prototype);
1745 dispex->prop_cnt = 1;
1746 if(builtin_info->value_prop.invoke || builtin_info->value_prop.getter) {
1747 dispex->props[0].type = PROP_BUILTIN;
1748 dispex->props[0].u.p = &builtin_info->value_prop;
1749 }else {
1750 dispex->props[0].type = PROP_DELETED;
1753 script_addref(ctx);
1754 dispex->ctx = ctx;
1756 return S_OK;
1759 static const builtin_info_t dispex_info = {
1760 JSCLASS_NONE,
1761 {NULL, NULL, 0},
1762 0, NULL,
1763 NULL,
1764 NULL
1767 HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype, jsdisp_t **dispex)
1769 jsdisp_t *ret;
1770 HRESULT hres;
1772 ret = heap_alloc_zero(sizeof(jsdisp_t));
1773 if(!ret)
1774 return E_OUTOFMEMORY;
1776 hres = init_dispex(ret, ctx, builtin_info ? builtin_info : &dispex_info, prototype);
1777 if(FAILED(hres)) {
1778 heap_free(ret);
1779 return hres;
1782 *dispex = ret;
1783 return S_OK;
1786 void jsdisp_free(jsdisp_t *obj)
1788 dispex_prop_t *prop;
1790 TRACE("(%p)\n", obj);
1792 for(prop = obj->props; prop < obj->props+obj->prop_cnt; prop++) {
1793 switch(prop->type) {
1794 case PROP_JSVAL:
1795 jsval_release(prop->u.val);
1796 break;
1797 case PROP_ACCESSOR:
1798 if(prop->u.accessor.getter)
1799 jsdisp_release(prop->u.accessor.getter);
1800 if(prop->u.accessor.setter)
1801 jsdisp_release(prop->u.accessor.setter);
1802 break;
1803 default:
1804 break;
1806 heap_free(prop->name);
1808 heap_free(obj->props);
1809 script_release(obj->ctx);
1810 if(obj->prototype)
1811 jsdisp_release(obj->prototype);
1813 if(obj->builtin_info->destructor)
1814 obj->builtin_info->destructor(obj);
1815 else
1816 heap_free(obj);
1819 #ifdef TRACE_REFCNT
1821 jsdisp_t *jsdisp_addref(jsdisp_t *jsdisp)
1823 ULONG ref = ++jsdisp->ref;
1824 TRACE("(%p) ref=%d\n", jsdisp, ref);
1825 return jsdisp;
1828 void jsdisp_release(jsdisp_t *jsdisp)
1830 ULONG ref = --jsdisp->ref;
1832 TRACE("(%p) ref=%d\n", jsdisp, ref);
1834 if(!ref)
1835 jsdisp_free(jsdisp);
1838 #endif
1840 HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *constr)
1842 jsdisp_t *prot = NULL;
1843 dispex_prop_t *prop;
1844 HRESULT hres;
1846 hres = find_prop_name_prot(constr, string_hash(L"prototype"), L"prototype", &prop);
1847 if(SUCCEEDED(hres) && prop && prop->type!=PROP_DELETED) {
1848 jsval_t val;
1850 hres = prop_get(constr, prop, &val);
1851 if(FAILED(hres)) {
1852 ERR("Could not get prototype\n");
1853 return hres;
1856 if(is_object_instance(val))
1857 prot = iface_to_jsdisp(get_object(val));
1858 jsval_release(val);
1861 hres = init_dispex(dispex, ctx, builtin_info, prot);
1863 if(prot)
1864 jsdisp_release(prot);
1865 return hres;
1868 jsdisp_t *iface_to_jsdisp(IDispatch *iface)
1870 return iface->lpVtbl == (const IDispatchVtbl*)&DispatchExVtbl
1871 ? jsdisp_addref( impl_from_IDispatchEx((IDispatchEx*)iface))
1872 : NULL;
1875 HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID *id)
1877 dispex_prop_t *prop;
1878 HRESULT hres;
1880 if(flags & fdexNameEnsure)
1881 hres = ensure_prop_name(jsdisp, name, PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE,
1882 &prop);
1883 else
1884 hres = find_prop_name_prot(jsdisp, string_hash(name), name, &prop);
1885 if(FAILED(hres))
1886 return hres;
1888 if(prop && prop->type!=PROP_DELETED) {
1889 *id = prop_to_id(jsdisp, prop);
1890 return S_OK;
1893 TRACE("not found %s\n", debugstr_w(name));
1894 *id = DISPID_UNKNOWN;
1895 return DISP_E_UNKNOWNNAME;
1898 HRESULT jsdisp_call_value(jsdisp_t *jsfunc, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1900 HRESULT hres;
1902 assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT|DISPATCH_JSCRIPT_INTERNAL_MASK)));
1904 if(is_class(jsfunc, JSCLASS_FUNCTION)) {
1905 hres = Function_invoke(jsfunc, jsthis, flags, argc, argv, r);
1906 }else {
1907 vdisp_t vdisp;
1909 if(!jsfunc->builtin_info->value_prop.invoke) {
1910 WARN("Not a function\n");
1911 return JS_E_FUNCTION_EXPECTED;
1914 set_disp(&vdisp, jsthis);
1915 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
1916 hres = jsfunc->builtin_info->value_prop.invoke(jsfunc->ctx, &vdisp, flags, argc, argv, r);
1917 vdisp_release(&vdisp);
1919 return hres;
1922 HRESULT jsdisp_call(jsdisp_t *disp, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1924 dispex_prop_t *prop;
1926 prop = get_prop(disp, id);
1927 if(!prop)
1928 return DISP_E_MEMBERNOTFOUND;
1930 return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, NULL);
1933 HRESULT jsdisp_call_name(jsdisp_t *disp, const WCHAR *name, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1935 dispex_prop_t *prop;
1936 HRESULT hres;
1938 hres = find_prop_name_prot(disp, string_hash(name), name, &prop);
1939 if(FAILED(hres))
1940 return hres;
1942 return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, NULL);
1945 static HRESULT disp_invoke(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, DISPPARAMS *params, VARIANT *r)
1947 IDispatchEx *dispex;
1948 EXCEPINFO ei;
1949 HRESULT hres;
1951 memset(&ei, 0, sizeof(ei));
1952 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1953 if(SUCCEEDED(hres)) {
1954 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, params, r, &ei, &ctx->jscaller->IServiceProvider_iface);
1955 IDispatchEx_Release(dispex);
1956 }else {
1957 UINT err = 0;
1959 if(flags == DISPATCH_CONSTRUCT) {
1960 WARN("IDispatch cannot be constructor\n");
1961 return DISP_E_MEMBERNOTFOUND;
1964 if(params->cNamedArgs == 1 && params->rgdispidNamedArgs[0] == DISPID_THIS) {
1965 params->cNamedArgs = 0;
1966 params->rgdispidNamedArgs = NULL;
1967 params->cArgs--;
1968 params->rgvarg++;
1971 TRACE("using IDispatch\n");
1972 hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, params, r, &ei, &err);
1975 if(hres == DISP_E_EXCEPTION) {
1976 TRACE("DISP_E_EXCEPTION: %08x %s %s\n", ei.scode, debugstr_w(ei.bstrSource), debugstr_w(ei.bstrDescription));
1977 reset_ei(ctx->ei);
1978 ctx->ei->error = (SUCCEEDED(ei.scode) || ei.scode == DISP_E_EXCEPTION) ? E_FAIL : ei.scode;
1979 if(ei.bstrSource)
1980 ctx->ei->source = jsstr_alloc_len(ei.bstrSource, SysStringLen(ei.bstrSource));
1981 if(ei.bstrDescription)
1982 ctx->ei->message = jsstr_alloc_len(ei.bstrDescription, SysStringLen(ei.bstrDescription));
1983 SysFreeString(ei.bstrSource);
1984 SysFreeString(ei.bstrDescription);
1985 SysFreeString(ei.bstrHelpFile);
1988 return hres;
1991 HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *ret)
1993 VARIANT buf[6], retv;
1994 jsdisp_t *jsdisp;
1995 DISPPARAMS dp;
1996 unsigned i;
1997 HRESULT hres;
1999 jsdisp = iface_to_jsdisp(disp);
2000 if(jsdisp && jsdisp->ctx == ctx) {
2001 if(flags & DISPATCH_PROPERTYPUT) {
2002 FIXME("disp_call(propput) on builtin object\n");
2003 return E_FAIL;
2006 if(ctx != jsdisp->ctx)
2007 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
2008 hres = jsdisp_call(jsdisp, id, flags, argc, argv, ret);
2009 jsdisp_release(jsdisp);
2010 return hres;
2013 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
2014 if(ret && argc)
2015 flags |= DISPATCH_PROPERTYGET;
2017 dp.cArgs = argc;
2019 if(flags & DISPATCH_PROPERTYPUT) {
2020 static DISPID propput_dispid = DISPID_PROPERTYPUT;
2022 dp.cNamedArgs = 1;
2023 dp.rgdispidNamedArgs = &propput_dispid;
2024 }else {
2025 dp.cNamedArgs = 0;
2026 dp.rgdispidNamedArgs = NULL;
2029 if(dp.cArgs > ARRAY_SIZE(buf)) {
2030 dp.rgvarg = heap_alloc(argc*sizeof(VARIANT));
2031 if(!dp.rgvarg)
2032 return E_OUTOFMEMORY;
2033 }else {
2034 dp.rgvarg = buf;
2037 for(i=0; i<argc; i++) {
2038 hres = jsval_to_variant(argv[i], dp.rgvarg+argc-i-1);
2039 if(FAILED(hres)) {
2040 while(i--)
2041 VariantClear(dp.rgvarg+argc-i-1);
2042 if(dp.rgvarg != buf)
2043 heap_free(dp.rgvarg);
2044 return hres;
2048 V_VT(&retv) = VT_EMPTY;
2049 hres = disp_invoke(ctx, disp, id, flags, &dp, ret ? &retv : NULL);
2051 for(i=0; i<argc; i++)
2052 VariantClear(dp.rgvarg+argc-i-1);
2053 if(dp.rgvarg != buf)
2054 heap_free(dp.rgvarg);
2056 if(SUCCEEDED(hres) && ret)
2057 hres = variant_to_jsval(&retv, ret);
2058 VariantClear(&retv);
2059 return hres;
2062 HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, IDispatch *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2063 jsval_t *r)
2065 VARIANT buf[6], retv, *args = buf;
2066 jsdisp_t *jsdisp;
2067 DISPPARAMS dp;
2068 unsigned i;
2069 HRESULT hres = S_OK;
2071 static DISPID this_id = DISPID_THIS;
2073 assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT|DISPATCH_JSCRIPT_INTERNAL_MASK)));
2075 jsdisp = iface_to_jsdisp(disp);
2076 if(jsdisp && jsdisp->ctx == ctx) {
2077 if(ctx != jsdisp->ctx)
2078 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
2079 hres = jsdisp_call_value(jsdisp, jsthis, flags, argc, argv, r);
2080 jsdisp_release(jsdisp);
2081 return hres;
2084 flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK;
2085 if(r && argc && flags == DISPATCH_METHOD)
2086 flags |= DISPATCH_PROPERTYGET;
2088 if(jsthis) {
2089 dp.cArgs = argc + 1;
2090 dp.cNamedArgs = 1;
2091 dp.rgdispidNamedArgs = &this_id;
2092 }else {
2093 dp.cArgs = argc;
2094 dp.cNamedArgs = 0;
2095 dp.rgdispidNamedArgs = NULL;
2098 if(dp.cArgs > ARRAY_SIZE(buf) && !(args = heap_alloc(dp.cArgs * sizeof(VARIANT))))
2099 return E_OUTOFMEMORY;
2100 dp.rgvarg = args;
2102 if(jsthis) {
2103 V_VT(dp.rgvarg) = VT_DISPATCH;
2104 V_DISPATCH(dp.rgvarg) = jsthis;
2107 for(i=0; SUCCEEDED(hres) && i < argc; i++)
2108 hres = jsval_to_variant(argv[i], dp.rgvarg+dp.cArgs-i-1);
2110 if(SUCCEEDED(hres)) {
2111 V_VT(&retv) = VT_EMPTY;
2112 hres = disp_invoke(ctx, disp, DISPID_VALUE, flags, &dp, r ? &retv : NULL);
2115 for(i = 0; i < argc; i++)
2116 VariantClear(dp.rgvarg + dp.cArgs - i - 1);
2117 if(args != buf)
2118 heap_free(args);
2120 if(!r)
2121 return S_OK;
2123 hres = variant_to_jsval(&retv, r);
2124 VariantClear(&retv);
2125 return hres;
2128 HRESULT jsdisp_propput(jsdisp_t *obj, const WCHAR *name, DWORD flags, jsval_t val)
2130 dispex_prop_t *prop;
2131 HRESULT hres;
2133 hres = ensure_prop_name(obj, name, flags, &prop);
2134 if(FAILED(hres))
2135 return hres;
2137 return prop_put(obj, prop, val);
2140 HRESULT jsdisp_propput_name(jsdisp_t *obj, const WCHAR *name, jsval_t val)
2142 return jsdisp_propput(obj, name, PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE, val);
2145 HRESULT jsdisp_propput_idx(jsdisp_t *obj, DWORD idx, jsval_t val)
2147 WCHAR buf[12];
2149 swprintf(buf, ARRAY_SIZE(buf), L"%d", idx);
2150 return jsdisp_propput_name(obj, buf, val);
2153 HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val)
2155 jsdisp_t *jsdisp;
2156 HRESULT hres;
2158 jsdisp = iface_to_jsdisp(disp);
2159 if(jsdisp && jsdisp->ctx == ctx) {
2160 dispex_prop_t *prop;
2162 prop = get_prop(jsdisp, id);
2163 if(prop)
2164 hres = prop_put(jsdisp, prop, val);
2165 else
2166 hres = DISP_E_MEMBERNOTFOUND;
2168 jsdisp_release(jsdisp);
2169 }else {
2170 DISPID dispid = DISPID_PROPERTYPUT;
2171 DWORD flags = DISPATCH_PROPERTYPUT;
2172 VARIANT var;
2173 DISPPARAMS dp = {&var, &dispid, 1, 1};
2175 hres = jsval_to_variant(val, &var);
2176 if(FAILED(hres))
2177 return hres;
2179 if(V_VT(&var) == VT_DISPATCH)
2180 flags |= DISPATCH_PROPERTYPUTREF;
2182 hres = disp_invoke(ctx, disp, id, flags, &dp, NULL);
2183 VariantClear(&var);
2186 return hres;
2189 HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val)
2191 dispex_prop_t *prop;
2192 HRESULT hres;
2194 hres = find_prop_name_prot(obj, string_hash(name), name, &prop);
2195 if(FAILED(hres))
2196 return hres;
2198 if(!prop || prop->type==PROP_DELETED) {
2199 *val = jsval_undefined();
2200 return S_OK;
2203 return prop_get(obj, prop, val);
2206 HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r)
2208 WCHAR name[12];
2209 dispex_prop_t *prop;
2210 HRESULT hres;
2212 swprintf(name, ARRAY_SIZE(name), L"%d", idx);
2214 hres = find_prop_name_prot(obj, string_hash(name), name, &prop);
2215 if(FAILED(hres))
2216 return hres;
2218 if(!prop || prop->type==PROP_DELETED) {
2219 *r = jsval_undefined();
2220 return DISP_E_UNKNOWNNAME;
2223 return prop_get(obj, prop, r);
2226 HRESULT jsdisp_propget(jsdisp_t *jsdisp, DISPID id, jsval_t *val)
2228 dispex_prop_t *prop;
2230 prop = get_prop(jsdisp, id);
2231 if(!prop)
2232 return DISP_E_MEMBERNOTFOUND;
2234 return prop_get(jsdisp, prop, val);
2237 HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t *val)
2239 DISPPARAMS dp = {NULL,NULL,0,0};
2240 jsdisp_t *jsdisp;
2241 VARIANT var;
2242 HRESULT hres;
2244 jsdisp = iface_to_jsdisp(disp);
2245 if(jsdisp && jsdisp->ctx == ctx) {
2246 hres = jsdisp_propget(jsdisp, id, val);
2247 jsdisp_release(jsdisp);
2248 return hres;
2251 V_VT(&var) = VT_EMPTY;
2252 hres = disp_invoke(ctx, disp, id, INVOKE_PROPERTYGET, &dp, &var);
2253 if(SUCCEEDED(hres)) {
2254 hres = variant_to_jsval(&var, val);
2255 VariantClear(&var);
2257 return hres;
2260 HRESULT jsdisp_delete_idx(jsdisp_t *obj, DWORD idx)
2262 WCHAR buf[12];
2263 dispex_prop_t *prop;
2264 BOOL b;
2265 HRESULT hres;
2267 swprintf(buf, ARRAY_SIZE(buf), L"%d", idx);
2269 hres = find_prop_name(obj, string_hash(buf), buf, &prop);
2270 if(FAILED(hres) || !prop)
2271 return hres;
2273 return delete_prop(prop, &b);
2276 HRESULT disp_delete(IDispatch *disp, DISPID id, BOOL *ret)
2278 IDispatchEx *dispex;
2279 jsdisp_t *jsdisp;
2280 HRESULT hres;
2282 jsdisp = iface_to_jsdisp(disp);
2283 if(jsdisp) {
2284 dispex_prop_t *prop;
2286 prop = get_prop(jsdisp, id);
2287 if(prop)
2288 hres = delete_prop(prop, ret);
2289 else
2290 hres = DISP_E_MEMBERNOTFOUND;
2292 jsdisp_release(jsdisp);
2293 return hres;
2296 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
2297 if(FAILED(hres)) {
2298 *ret = FALSE;
2299 return S_OK;
2302 hres = IDispatchEx_DeleteMemberByDispID(dispex, id);
2303 IDispatchEx_Release(dispex);
2304 if(FAILED(hres))
2305 return hres;
2307 *ret = hres == S_OK;
2308 return S_OK;
2311 HRESULT jsdisp_next_prop(jsdisp_t *obj, DISPID id, BOOL own_only, DISPID *ret)
2313 dispex_prop_t *iter;
2314 HRESULT hres;
2316 if(id == DISPID_STARTENUM && !own_only) {
2317 hres = fill_protrefs(obj);
2318 if(FAILED(hres))
2319 return hres;
2322 if(id + 1 < 0 || id+1 >= obj->prop_cnt)
2323 return S_FALSE;
2325 for(iter = &obj->props[id + 1]; iter < obj->props + obj->prop_cnt; iter++) {
2326 if(!iter->name || iter->type == PROP_DELETED)
2327 continue;
2328 if(own_only && iter->type == PROP_PROTREF)
2329 continue;
2330 if(!(get_flags(obj, iter) & PROPF_ENUMERABLE))
2331 continue;
2332 *ret = prop_to_id(obj, iter);
2333 return S_OK;
2336 return S_FALSE;
2339 HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL *ret)
2341 IDispatchEx *dispex;
2342 jsdisp_t *jsdisp;
2343 BSTR bstr;
2344 HRESULT hres;
2346 jsdisp = iface_to_jsdisp(disp);
2347 if(jsdisp) {
2348 dispex_prop_t *prop;
2349 const WCHAR *ptr;
2351 ptr = jsstr_flatten(name);
2352 if(!ptr) {
2353 jsdisp_release(jsdisp);
2354 return E_OUTOFMEMORY;
2357 hres = find_prop_name(jsdisp, string_hash(ptr), ptr, &prop);
2358 if(prop) {
2359 hres = delete_prop(prop, ret);
2360 }else {
2361 *ret = TRUE;
2362 hres = S_OK;
2365 jsdisp_release(jsdisp);
2366 return hres;
2369 bstr = SysAllocStringLen(NULL, jsstr_length(name));
2370 if(!bstr)
2371 return E_OUTOFMEMORY;
2372 jsstr_flush(name, bstr);
2374 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
2375 if(SUCCEEDED(hres)) {
2376 hres = IDispatchEx_DeleteMemberByName(dispex, bstr, make_grfdex(ctx, fdexNameCaseSensitive));
2377 if(SUCCEEDED(hres))
2378 *ret = hres == S_OK;
2379 IDispatchEx_Release(dispex);
2380 }else {
2381 DISPID id;
2383 hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, &id);
2384 if(SUCCEEDED(hres)) {
2385 /* Property exists and we can't delete it from pure IDispatch interface, so return false. */
2386 *ret = FALSE;
2387 }else if(hres == DISP_E_UNKNOWNNAME) {
2388 /* Property doesn't exist, so nothing to delete */
2389 *ret = TRUE;
2390 hres = S_OK;
2394 SysFreeString(bstr);
2395 return hres;
2398 HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_only,
2399 property_desc_t *desc)
2401 dispex_prop_t *prop;
2402 HRESULT hres;
2404 hres = find_prop_name(obj, string_hash(name), name, &prop);
2405 if(FAILED(hres))
2406 return hres;
2408 if(!prop)
2409 return DISP_E_UNKNOWNNAME;
2411 memset(desc, 0, sizeof(*desc));
2413 switch(prop->type) {
2414 case PROP_BUILTIN:
2415 case PROP_JSVAL:
2416 desc->mask |= PROPF_WRITABLE;
2417 desc->explicit_value = TRUE;
2418 if(!flags_only) {
2419 hres = prop_get(obj, prop, &desc->value);
2420 if(FAILED(hres))
2421 return hres;
2423 break;
2424 case PROP_ACCESSOR:
2425 desc->explicit_getter = desc->explicit_setter = TRUE;
2426 if(!flags_only) {
2427 desc->getter = prop->u.accessor.getter
2428 ? jsdisp_addref(prop->u.accessor.getter) : NULL;
2429 desc->setter = prop->u.accessor.setter
2430 ? jsdisp_addref(prop->u.accessor.setter) : NULL;
2432 break;
2433 default:
2434 return DISP_E_UNKNOWNNAME;
2437 desc->flags = prop->flags & (PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE);
2438 desc->mask |= PROPF_ENUMERABLE | PROPF_CONFIGURABLE;
2439 return S_OK;
2442 HRESULT jsdisp_define_property(jsdisp_t *obj, const WCHAR *name, property_desc_t *desc)
2444 dispex_prop_t *prop;
2445 HRESULT hres;
2447 hres = find_prop_name(obj, string_hash(name), name, &prop);
2448 if(FAILED(hres))
2449 return hres;
2451 if(!prop && !(prop = alloc_prop(obj, name, PROP_DELETED, 0)))
2452 return E_OUTOFMEMORY;
2454 if(prop->type == PROP_DELETED || prop->type == PROP_PROTREF) {
2455 prop->flags = desc->flags;
2456 if(desc->explicit_getter || desc->explicit_setter) {
2457 prop->type = PROP_ACCESSOR;
2458 prop->u.accessor.getter = desc->getter ? jsdisp_addref(desc->getter) : NULL;
2459 prop->u.accessor.setter = desc->setter ? jsdisp_addref(desc->setter) : NULL;
2460 TRACE("%s = accessor { get: %p set: %p }\n", debugstr_w(name),
2461 prop->u.accessor.getter, prop->u.accessor.setter);
2462 }else {
2463 prop->type = PROP_JSVAL;
2464 if(desc->explicit_value) {
2465 hres = jsval_copy(desc->value, &prop->u.val);
2466 if(FAILED(hres))
2467 return hres;
2468 }else {
2469 prop->u.val = jsval_undefined();
2471 TRACE("%s = %s\n", debugstr_w(name), debugstr_jsval(prop->u.val));
2473 return S_OK;
2476 TRACE("existing prop %s prop flags %x desc flags %x desc mask %x\n", debugstr_w(name),
2477 prop->flags, desc->flags, desc->mask);
2479 if(!(prop->flags & PROPF_CONFIGURABLE)) {
2480 if(((desc->mask & PROPF_CONFIGURABLE) && (desc->flags & PROPF_CONFIGURABLE))
2481 || ((desc->mask & PROPF_ENUMERABLE)
2482 && ((desc->flags & PROPF_ENUMERABLE) != (prop->flags & PROPF_ENUMERABLE))))
2483 return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name);
2486 if(desc->explicit_value || (desc->mask & PROPF_WRITABLE)) {
2487 if(prop->type == PROP_ACCESSOR) {
2488 if(!(prop->flags & PROPF_CONFIGURABLE))
2489 return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name);
2490 if(prop->u.accessor.getter)
2491 jsdisp_release(prop->u.accessor.getter);
2492 if(prop->u.accessor.setter)
2493 jsdisp_release(prop->u.accessor.setter);
2495 prop->type = PROP_JSVAL;
2496 hres = jsval_copy(desc->value, &prop->u.val);
2497 if(FAILED(hres)) {
2498 prop->u.val = jsval_undefined();
2499 return hres;
2501 }else {
2502 if(!(prop->flags & PROPF_CONFIGURABLE) && !(prop->flags & PROPF_WRITABLE)) {
2503 if((desc->mask & PROPF_WRITABLE) && (desc->flags & PROPF_WRITABLE))
2504 return throw_error(obj->ctx, JS_E_NONWRITABLE_MODIFIED, name);
2505 if(desc->explicit_value) {
2506 if(prop->type == PROP_JSVAL) {
2507 BOOL eq;
2508 hres = jsval_strict_equal(desc->value, prop->u.val, &eq);
2509 if(FAILED(hres))
2510 return hres;
2511 if(!eq)
2512 return throw_error(obj->ctx, JS_E_NONWRITABLE_MODIFIED, name);
2513 }else {
2514 FIXME("redefinition of property type %d\n", prop->type);
2518 if(desc->explicit_value) {
2519 if(prop->type == PROP_JSVAL)
2520 jsval_release(prop->u.val);
2521 else
2522 prop->type = PROP_JSVAL;
2523 hres = jsval_copy(desc->value, &prop->u.val);
2524 if(FAILED(hres)) {
2525 prop->u.val = jsval_undefined();
2526 return hres;
2530 }else if(desc->explicit_getter || desc->explicit_setter) {
2531 if(prop->type != PROP_ACCESSOR) {
2532 if(!(prop->flags & PROPF_CONFIGURABLE))
2533 return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name);
2534 if(prop->type == PROP_JSVAL)
2535 jsval_release(prop->u.val);
2536 prop->type = PROP_ACCESSOR;
2537 prop->u.accessor.getter = prop->u.accessor.setter = NULL;
2538 }else if(!(prop->flags & PROPF_CONFIGURABLE)) {
2539 if((desc->explicit_getter && desc->getter != prop->u.accessor.getter)
2540 || (desc->explicit_setter && desc->setter != prop->u.accessor.setter))
2541 return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name);
2544 if(desc->explicit_getter) {
2545 if(prop->u.accessor.getter) {
2546 jsdisp_release(prop->u.accessor.getter);
2547 prop->u.accessor.getter = NULL;
2549 if(desc->getter)
2550 prop->u.accessor.getter = jsdisp_addref(desc->getter);
2552 if(desc->explicit_setter) {
2553 if(prop->u.accessor.setter) {
2554 jsdisp_release(prop->u.accessor.setter);
2555 prop->u.accessor.setter = NULL;
2557 if(desc->setter)
2558 prop->u.accessor.setter = jsdisp_addref(desc->setter);
2562 prop->flags = (prop->flags & ~desc->mask) | (desc->flags & desc->mask);
2563 return S_OK;
2566 HRESULT jsdisp_define_data_property(jsdisp_t *obj, const WCHAR *name, unsigned flags, jsval_t value)
2568 property_desc_t prop_desc = { flags, flags, TRUE };
2569 prop_desc.value = value;
2570 return jsdisp_define_property(obj, name, &prop_desc);
2573 HRESULT jsdisp_get_prop_name(jsdisp_t *obj, DISPID id, jsstr_t **r)
2575 dispex_prop_t *prop = get_prop(obj, id);
2577 if(!prop || !prop->name || prop->type == PROP_DELETED)
2578 return DISP_E_MEMBERNOTFOUND;
2580 *r = jsstr_alloc(prop->name);
2581 return *r ? S_OK : E_OUTOFMEMORY;