vbscript: Use VariantCopyInd in invoke_variant_prop.
[wine/multimedia.git] / dlls / vbscript / vbdisp.c
blob63825701f5f8fb49134c3a244075ceae523300c8
1 /*
2 * Copyright 2011 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 "vbscript.h"
23 #include "wine/debug.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
27 #define FDEX_VERSION_MASK 0xf0000000
29 static inline BOOL is_func_id(vbdisp_t *This, DISPID id)
31 return id < This->desc->func_cnt;
34 static BOOL get_func_id(vbdisp_t *This, const WCHAR *name, vbdisp_invoke_type_t invoke_type, BOOL search_private, DISPID *id)
36 unsigned i;
38 for(i = invoke_type == VBDISP_ANY ? 0 : 1; i < This->desc->func_cnt; i++) {
39 if(invoke_type == VBDISP_ANY) {
40 if(!search_private && !This->desc->funcs[i].is_public)
41 continue;
42 if(!i && !This->desc->funcs[0].name) /* default value may not exist */
43 continue;
44 }else {
45 if(!This->desc->funcs[i].entries[invoke_type]
46 || (!search_private && !This->desc->funcs[i].entries[invoke_type]->is_public))
47 continue;
50 if(!strcmpiW(This->desc->funcs[i].name, name)) {
51 *id = i;
52 return TRUE;
56 return FALSE;
59 HRESULT vbdisp_get_id(vbdisp_t *This, BSTR name, vbdisp_invoke_type_t invoke_type, BOOL search_private, DISPID *id)
61 unsigned i;
63 if(get_func_id(This, name, invoke_type, search_private, id))
64 return S_OK;
66 for(i=0; i < This->desc->prop_cnt; i++) {
67 if(!search_private && !This->desc->props[i].is_public)
68 continue;
70 if(!strcmpiW(This->desc->props[i].name, name)) {
71 *id = i + This->desc->func_cnt;
72 return S_OK;
76 if(This->desc->typeinfo) {
77 HRESULT hres;
79 hres = ITypeInfo_GetIDsOfNames(This->desc->typeinfo, &name, 1, id);
80 if(SUCCEEDED(hres))
81 return S_OK;
84 *id = -1;
85 return DISP_E_UNKNOWNNAME;
88 static VARIANT *get_propput_arg(const DISPPARAMS *dp)
90 unsigned i;
92 for(i=0; i < dp->cNamedArgs; i++) {
93 if(dp->rgdispidNamedArgs[i] == DISPID_PROPERTYPUT)
94 return dp->rgvarg+i;
97 return NULL;
100 static HRESULT invoke_variant_prop(VARIANT *v, WORD flags, DISPPARAMS *dp, VARIANT *res)
102 HRESULT hres;
104 switch(flags) {
105 case DISPATCH_PROPERTYGET|DISPATCH_METHOD:
106 case DISPATCH_PROPERTYGET:
107 if(dp->cArgs) {
108 WARN("called with arguments\n");
109 return DISP_E_MEMBERNOTFOUND; /* That's what tests show */
112 hres = VariantCopyInd(res, v);
113 break;
115 case DISPATCH_PROPERTYPUT: {
116 VARIANT *put_val;
118 put_val = get_propput_arg(dp);
119 if(!put_val) {
120 WARN("no value to set\n");
121 return DISP_E_PARAMNOTOPTIONAL;
124 if(arg_cnt(dp)) {
125 FIXME("Arguments not supported\n");
126 return E_NOTIMPL;
129 if(res)
130 V_VT(res) = VT_EMPTY;
132 hres = VariantCopyInd(v, put_val);
133 break;
136 default:
137 FIXME("unimplemented flags %x\n", flags);
138 return E_NOTIMPL;
141 return hres;
144 static HRESULT invoke_builtin(vbdisp_t *This, const builtin_prop_t *prop, WORD flags, DISPPARAMS *dp, VARIANT *res)
146 VARIANT args[8];
147 unsigned argn, i;
149 switch(flags) {
150 case DISPATCH_PROPERTYGET:
151 if(!(prop->flags & (BP_GET|BP_GETPUT))) {
152 FIXME("property does not support DISPATCH_PROPERTYGET\n");
153 return E_FAIL;
155 break;
156 case DISPATCH_PROPERTYGET|DISPATCH_METHOD:
157 if(!prop->proc && prop->flags == BP_GET) {
158 const int vt = prop->min_args, val = prop->max_args;
159 switch(vt) {
160 case VT_I2:
161 V_VT(res) = VT_I2;
162 V_I2(res) = val;
163 break;
164 case VT_I4:
165 V_VT(res) = VT_I4;
166 V_I4(res) = val;
167 break;
168 case VT_BSTR: {
169 const string_constant_t *str = (const string_constant_t*)prop->max_args;
170 BSTR ret;
172 ret = SysAllocStringLen(str->buf, str->len);
173 if(!ret)
174 return E_OUTOFMEMORY;
176 V_VT(res) = VT_BSTR;
177 V_BSTR(res) = ret;
178 break;
180 DEFAULT_UNREACHABLE;
182 return S_OK;
184 break;
185 case DISPATCH_METHOD:
186 if(prop->flags & (BP_GET|BP_GETPUT)) {
187 FIXME("Call on property\n");
188 return E_FAIL;
190 break;
191 case DISPATCH_PROPERTYPUT:
192 if(!(prop->flags & BP_GETPUT)) {
193 FIXME("property does not support DISPATCH_PROPERTYPUT\n");
194 return E_FAIL;
197 FIXME("call put\n");
198 return E_NOTIMPL;
199 default:
200 FIXME("unsupported flags %x\n", flags);
201 return E_NOTIMPL;
204 argn = arg_cnt(dp);
206 if(argn < prop->min_args || argn > (prop->max_args ? prop->max_args : prop->min_args)) {
207 FIXME("invalid number of arguments\n");
208 return E_FAIL;
211 assert(argn < sizeof(args)/sizeof(*args));
213 for(i=0; i < argn; i++) {
214 if(V_VT(dp->rgvarg+dp->cArgs-i-1) == (VT_BYREF|VT_VARIANT))
215 args[i] = *V_VARIANTREF(dp->rgvarg+dp->cArgs-i-1);
216 else
217 args[i] = dp->rgvarg[dp->cArgs-i-1];
220 return prop->proc(This, args, dp->cArgs, res);
223 static BOOL run_terminator(vbdisp_t *This)
225 DISPPARAMS dp = {0};
227 if(This->terminator_ran)
228 return TRUE;
229 This->terminator_ran = TRUE;
231 if(!This->desc->class_terminate_id)
232 return TRUE;
234 This->ref++;
235 exec_script(This->desc->ctx, This->desc->funcs[This->desc->class_terminate_id].entries[VBDISP_CALLGET],
236 This, &dp, NULL);
237 return !--This->ref;
240 static void clean_props(vbdisp_t *This)
242 unsigned i;
244 if(!This->desc)
245 return;
247 for(i=0; i < This->desc->array_cnt; i++) {
248 if(This->arrays[i]) {
249 SafeArrayDestroy(This->arrays[i]);
250 This->arrays[i] = NULL;
254 for(i=0; i < This->desc->prop_cnt; i++)
255 VariantClear(This->props+i);
258 static inline vbdisp_t *impl_from_IDispatchEx(IDispatchEx *iface)
260 return CONTAINING_RECORD(iface, vbdisp_t, IDispatchEx_iface);
263 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
265 vbdisp_t *This = impl_from_IDispatchEx(iface);
267 if(IsEqualGUID(&IID_IUnknown, riid)) {
268 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
269 *ppv = &This->IDispatchEx_iface;
270 }else if(IsEqualGUID(&IID_IDispatch, riid)) {
271 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
272 *ppv = &This->IDispatchEx_iface;
273 }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
274 TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
275 *ppv = &This->IDispatchEx_iface;
276 }else {
277 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
278 *ppv = NULL;
279 return E_NOINTERFACE;
282 IUnknown_AddRef((IUnknown*)*ppv);
283 return S_OK;
286 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
288 vbdisp_t *This = impl_from_IDispatchEx(iface);
289 LONG ref = InterlockedIncrement(&This->ref);
291 TRACE("(%p) ref=%d\n", This, ref);
293 return ref;
296 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
298 vbdisp_t *This = impl_from_IDispatchEx(iface);
299 LONG ref = InterlockedDecrement(&This->ref);
301 TRACE("(%p) ref=%d\n", This, ref);
303 if(!ref && run_terminator(This)) {
304 clean_props(This);
305 list_remove(&This->entry);
306 heap_free(This->arrays);
307 heap_free(This);
310 return ref;
313 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
315 vbdisp_t *This = impl_from_IDispatchEx(iface);
317 TRACE("(%p)->(%p)\n", This, pctinfo);
319 *pctinfo = 1;
320 return S_OK;
323 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid,
324 ITypeInfo **ppTInfo)
326 vbdisp_t *This = impl_from_IDispatchEx(iface);
327 FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
328 return E_NOTIMPL;
331 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
332 LPOLESTR *rgszNames, UINT cNames, LCID lcid,
333 DISPID *rgDispId)
335 vbdisp_t *This = impl_from_IDispatchEx(iface);
336 FIXME("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
337 lcid, rgDispId);
338 return E_NOTIMPL;
341 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
342 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
343 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
345 vbdisp_t *This = impl_from_IDispatchEx(iface);
346 FIXME("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
347 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
348 return E_NOTIMPL;
351 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
353 vbdisp_t *This = impl_from_IDispatchEx(iface);
355 TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
357 grfdex &= ~FDEX_VERSION_MASK;
359 if(!This->desc)
360 return E_UNEXPECTED;
362 /* Tests show that fdexNameCaseSensitive is ignored */
364 if(grfdex & ~(fdexNameEnsure|fdexNameCaseInsensitive|fdexNameCaseSensitive)) {
365 FIXME("unsupported flags %x\n", grfdex);
366 return E_NOTIMPL;
369 return vbdisp_get_id(This, bstrName, VBDISP_ANY, FALSE, pid);
372 static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
373 VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
375 vbdisp_t *This = impl_from_IDispatchEx(iface);
377 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
379 if(!This->desc)
380 return E_UNEXPECTED;
382 if(pvarRes)
383 V_VT(pvarRes) = VT_EMPTY;
385 if(id < 0)
386 return DISP_E_MEMBERNOTFOUND;
388 if(is_func_id(This, id)) {
389 function_t *func;
391 switch(wFlags) {
392 case DISPATCH_METHOD:
393 case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
394 func = This->desc->funcs[id].entries[VBDISP_CALLGET];
395 if(!func) {
396 FIXME("no invoke/getter\n");
397 return DISP_E_MEMBERNOTFOUND;
400 return exec_script(This->desc->ctx, func, This, pdp, pvarRes);
401 case DISPATCH_PROPERTYPUT: {
402 VARIANT *put_val;
403 DISPPARAMS dp = {NULL, NULL, 1, 0};
405 if(arg_cnt(pdp)) {
406 FIXME("arguments not implemented\n");
407 return E_NOTIMPL;
410 put_val = get_propput_arg(pdp);
411 if(!put_val) {
412 WARN("no value to set\n");
413 return DISP_E_PARAMNOTOPTIONAL;
416 dp.rgvarg = put_val;
417 func = This->desc->funcs[id].entries[V_VT(put_val) == VT_DISPATCH ? VBDISP_SET : VBDISP_LET];
418 if(!func) {
419 FIXME("no letter/setter\n");
420 return DISP_E_MEMBERNOTFOUND;
423 return exec_script(This->desc->ctx, func, This, &dp, NULL);
425 default:
426 FIXME("flags %x\n", wFlags);
427 return DISP_E_MEMBERNOTFOUND;
431 if(id < This->desc->prop_cnt + This->desc->func_cnt)
432 return invoke_variant_prop(This->props+(id-This->desc->func_cnt), wFlags, pdp, pvarRes);
434 if(This->desc->builtin_prop_cnt) {
435 unsigned min = 0, max = This->desc->builtin_prop_cnt-1, i;
437 while(min <= max) {
438 i = (min+max)/2;
439 if(This->desc->builtin_props[i].id == id)
440 return invoke_builtin(This, This->desc->builtin_props+i, wFlags, pdp, pvarRes);
441 if(This->desc->builtin_props[i].id < id)
442 min = i+1;
443 else
444 max = i-1;
448 return DISP_E_MEMBERNOTFOUND;
451 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
453 vbdisp_t *This = impl_from_IDispatchEx(iface);
454 FIXME("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex);
455 return E_NOTIMPL;
458 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
460 vbdisp_t *This = impl_from_IDispatchEx(iface);
461 FIXME("(%p)->(%x)\n", This, id);
462 return E_NOTIMPL;
465 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
467 vbdisp_t *This = impl_from_IDispatchEx(iface);
468 FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex);
469 return E_NOTIMPL;
472 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
474 vbdisp_t *This = impl_from_IDispatchEx(iface);
475 FIXME("(%p)->(%x %p)\n", This, id, pbstrName);
476 return E_NOTIMPL;
479 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
481 vbdisp_t *This = impl_from_IDispatchEx(iface);
482 FIXME("(%p)->(%x %x %p)\n", This, grfdex, id, pid);
483 return E_NOTIMPL;
486 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
488 vbdisp_t *This = impl_from_IDispatchEx(iface);
489 FIXME("(%p)->(%p)\n", This, ppunk);
490 return E_NOTIMPL;
493 static IDispatchExVtbl DispatchExVtbl = {
494 DispatchEx_QueryInterface,
495 DispatchEx_AddRef,
496 DispatchEx_Release,
497 DispatchEx_GetTypeInfoCount,
498 DispatchEx_GetTypeInfo,
499 DispatchEx_GetIDsOfNames,
500 DispatchEx_Invoke,
501 DispatchEx_GetDispID,
502 DispatchEx_InvokeEx,
503 DispatchEx_DeleteMemberByName,
504 DispatchEx_DeleteMemberByDispID,
505 DispatchEx_GetMemberProperties,
506 DispatchEx_GetMemberName,
507 DispatchEx_GetNextDispID,
508 DispatchEx_GetNameSpaceParent
511 static inline vbdisp_t *unsafe_impl_from_IDispatch(IDispatch *iface)
513 return iface->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl
514 ? CONTAINING_RECORD(iface, vbdisp_t, IDispatchEx_iface)
515 : NULL;
518 HRESULT create_vbdisp(const class_desc_t *desc, vbdisp_t **ret)
520 vbdisp_t *vbdisp;
521 HRESULT hres = S_OK;
523 vbdisp = heap_alloc_zero( FIELD_OFFSET( vbdisp_t, props[desc->prop_cnt] ));
524 if(!vbdisp)
525 return E_OUTOFMEMORY;
527 vbdisp->IDispatchEx_iface.lpVtbl = &DispatchExVtbl;
528 vbdisp->ref = 1;
529 vbdisp->desc = desc;
531 list_add_tail(&desc->ctx->objects, &vbdisp->entry);
533 if(desc->array_cnt) {
534 vbdisp->arrays = heap_alloc_zero(desc->array_cnt * sizeof(*vbdisp->arrays));
535 if(vbdisp->arrays) {
536 unsigned i, j;
538 for(i=0; i < desc->array_cnt; i++) {
539 if(!desc->array_descs[i].dim_cnt)
540 continue;
542 vbdisp->arrays[i] = SafeArrayCreate(VT_VARIANT, desc->array_descs[i].dim_cnt, desc->array_descs[i].bounds);
543 if(!vbdisp->arrays[i]) {
544 hres = E_OUTOFMEMORY;
545 break;
549 if(SUCCEEDED(hres)) {
550 for(i=0, j=0; i < desc->prop_cnt; i++) {
551 if(desc->props[i].is_array) {
552 V_VT(vbdisp->props+i) = VT_ARRAY|VT_BYREF|VT_VARIANT;
553 V_ARRAYREF(vbdisp->props+i) = vbdisp->arrays + j++;
557 }else {
558 hres = E_OUTOFMEMORY;
562 if(SUCCEEDED(hres) && desc->class_initialize_id) {
563 DISPPARAMS dp = {0};
564 hres = exec_script(desc->ctx, desc->funcs[desc->class_initialize_id].entries[VBDISP_CALLGET],
565 vbdisp, &dp, NULL);
568 if(FAILED(hres)) {
569 IDispatchEx_Release(&vbdisp->IDispatchEx_iface);
570 return hres;
573 *ret = vbdisp;
574 return S_OK;
577 static HRESULT Procedure_invoke(vbdisp_t *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
579 script_ctx_t *ctx = This->desc->ctx;
580 HRESULT hres;
582 TRACE("\n");
584 IActiveScriptSite_OnEnterScript(ctx->site);
585 hres = exec_script(ctx, This->desc->value_func, NULL, NULL, NULL);
586 IActiveScriptSite_OnLeaveScript(ctx->site);
588 return hres;
591 static const builtin_prop_t procedure_props[] = {
592 {DISPID_VALUE, Procedure_invoke, 0}
595 HRESULT create_procedure_disp(script_ctx_t *ctx, vbscode_t *code, IDispatch **ret)
597 class_desc_t *desc;
598 vbdisp_t *vbdisp;
599 HRESULT hres;
601 desc = heap_alloc_zero(sizeof(*desc));
602 if(!desc)
603 return E_OUTOFMEMORY;
605 desc->ctx = ctx;
606 desc->builtin_prop_cnt = sizeof(procedure_props)/sizeof(*procedure_props);
607 desc->builtin_props = procedure_props;
608 desc->value_func = &code->main_code;
610 hres = create_vbdisp(desc, &vbdisp);
611 if(FAILED(hres)) {
612 heap_free(desc);
613 return hres;
616 desc->next = ctx->procs;
617 ctx->procs = desc;
619 *ret = (IDispatch*)&vbdisp->IDispatchEx_iface;
620 return S_OK;
623 struct _ident_map_t {
624 const WCHAR *name;
625 BOOL is_var;
626 union {
627 dynamic_var_t *var;
628 function_t *func;
629 } u;
632 static inline DISPID ident_to_id(ScriptDisp *This, ident_map_t *ident)
634 return (ident-This->ident_map)+1;
637 static inline ident_map_t *id_to_ident(ScriptDisp *This, DISPID id)
639 return 0 < id && id <= This->ident_map_cnt ? This->ident_map+id-1 : NULL;
642 static ident_map_t *add_ident(ScriptDisp *This, const WCHAR *name)
644 ident_map_t *ret;
646 if(!This->ident_map_size) {
647 This->ident_map = heap_alloc(4 * sizeof(*This->ident_map));
648 if(!This->ident_map)
649 return NULL;
650 This->ident_map_size = 4;
651 }else if(This->ident_map_cnt == This->ident_map_size) {
652 ident_map_t *new_map;
654 new_map = heap_realloc(This->ident_map, 2*This->ident_map_size*sizeof(*new_map));
655 if(!new_map)
656 return NULL;
657 This->ident_map = new_map;
658 This->ident_map_size *= 2;
661 ret = This->ident_map + This->ident_map_cnt++;
662 ret->name = name;
663 return ret;
666 static inline ScriptDisp *ScriptDisp_from_IDispatchEx(IDispatchEx *iface)
668 return CONTAINING_RECORD(iface, ScriptDisp, IDispatchEx_iface);
671 static HRESULT WINAPI ScriptDisp_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
673 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
675 if(IsEqualGUID(&IID_IUnknown, riid)) {
676 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
677 *ppv = &This->IDispatchEx_iface;
678 }else if(IsEqualGUID(&IID_IDispatch, riid)) {
679 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
680 *ppv = &This->IDispatchEx_iface;
681 }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
682 TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
683 *ppv = &This->IDispatchEx_iface;
684 }else {
685 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
686 *ppv = NULL;
687 return E_NOINTERFACE;
690 IUnknown_AddRef((IUnknown*)*ppv);
691 return S_OK;
694 static ULONG WINAPI ScriptDisp_AddRef(IDispatchEx *iface)
696 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
697 LONG ref = InterlockedIncrement(&This->ref);
699 TRACE("(%p) ref=%d\n", This, ref);
701 return ref;
704 static ULONG WINAPI ScriptDisp_Release(IDispatchEx *iface)
706 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
707 LONG ref = InterlockedDecrement(&This->ref);
709 TRACE("(%p) ref=%d\n", This, ref);
711 if(!ref) {
712 assert(!This->ctx);
713 heap_free(This->ident_map);
714 heap_free(This);
717 return ref;
720 static HRESULT WINAPI ScriptDisp_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
722 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
724 TRACE("(%p)->(%p)\n", This, pctinfo);
726 *pctinfo = 1;
727 return S_OK;
730 static HRESULT WINAPI ScriptDisp_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid,
731 ITypeInfo **ppTInfo)
733 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
734 FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
735 return E_NOTIMPL;
738 static HRESULT WINAPI ScriptDisp_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
739 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
741 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
742 UINT i;
743 HRESULT hres;
745 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
746 lcid, rgDispId);
748 for(i=0; i < cNames; i++) {
749 hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[i], 0, rgDispId+i);
750 if(FAILED(hres))
751 return hres;
754 return S_OK;
757 static HRESULT WINAPI ScriptDisp_Invoke(IDispatchEx *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
758 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
760 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
762 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
763 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
765 return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags,
766 pDispParams, pVarResult, pExcepInfo, NULL);
769 static HRESULT WINAPI ScriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
771 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
772 dynamic_var_t *var;
773 ident_map_t *ident;
774 function_t *func;
776 TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
778 if(!This->ctx)
779 return E_UNEXPECTED;
781 for(ident = This->ident_map; ident < This->ident_map+This->ident_map_cnt; ident++) {
782 if(!strcmpiW(ident->name, bstrName)) {
783 *pid = ident_to_id(This, ident);
784 return S_OK;
788 for(var = This->ctx->global_vars; var; var = var->next) {
789 if(!strcmpiW(var->name, bstrName)) {
790 ident = add_ident(This, var->name);
791 if(!ident)
792 return E_OUTOFMEMORY;
794 ident->is_var = TRUE;
795 ident->u.var = var;
796 *pid = ident_to_id(This, ident);
797 return S_OK;
801 for(func = This->ctx->global_funcs; func; func = func->next) {
802 if(!strcmpiW(func->name, bstrName)) {
803 ident = add_ident(This, func->name);
804 if(!ident)
805 return E_OUTOFMEMORY;
807 ident->is_var = FALSE;
808 ident->u.func = func;
809 *pid = ident_to_id(This, ident);
810 return S_OK;
814 *pid = -1;
815 return DISP_E_UNKNOWNNAME;
818 static HRESULT WINAPI ScriptDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
819 VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
821 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
822 ident_map_t *ident;
823 HRESULT hres;
825 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
827 ident = id_to_ident(This, id);
828 if(!ident)
829 return DISP_E_MEMBERNOTFOUND;
831 if(ident->is_var) {
832 if(ident->u.var->is_const) {
833 FIXME("const not supported\n");
834 return E_NOTIMPL;
837 return invoke_variant_prop(&ident->u.var->v, wFlags, pdp, pvarRes);
840 switch(wFlags) {
841 case DISPATCH_METHOD:
842 case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
843 IActiveScriptSite_OnEnterScript(This->ctx->site);
844 hres = exec_script(This->ctx, ident->u.func, NULL, pdp, pvarRes);
845 IActiveScriptSite_OnLeaveScript(This->ctx->site);
846 break;
847 default:
848 FIXME("Unsupported flags %x\n", wFlags);
849 hres = E_NOTIMPL;
852 return hres;
855 static HRESULT WINAPI ScriptDisp_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
857 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
858 FIXME("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex);
859 return E_NOTIMPL;
862 static HRESULT WINAPI ScriptDisp_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
864 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
865 FIXME("(%p)->(%x)\n", This, id);
866 return E_NOTIMPL;
869 static HRESULT WINAPI ScriptDisp_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
871 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
872 FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex);
873 return E_NOTIMPL;
876 static HRESULT WINAPI ScriptDisp_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
878 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
879 FIXME("(%p)->(%x %p)\n", This, id, pbstrName);
880 return E_NOTIMPL;
883 static HRESULT WINAPI ScriptDisp_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
885 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
886 FIXME("(%p)->(%x %x %p)\n", This, grfdex, id, pid);
887 return E_NOTIMPL;
890 static HRESULT WINAPI ScriptDisp_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
892 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
893 FIXME("(%p)->(%p)\n", This, ppunk);
894 return E_NOTIMPL;
897 static IDispatchExVtbl ScriptDispVtbl = {
898 ScriptDisp_QueryInterface,
899 ScriptDisp_AddRef,
900 ScriptDisp_Release,
901 ScriptDisp_GetTypeInfoCount,
902 ScriptDisp_GetTypeInfo,
903 ScriptDisp_GetIDsOfNames,
904 ScriptDisp_Invoke,
905 ScriptDisp_GetDispID,
906 ScriptDisp_InvokeEx,
907 ScriptDisp_DeleteMemberByName,
908 ScriptDisp_DeleteMemberByDispID,
909 ScriptDisp_GetMemberProperties,
910 ScriptDisp_GetMemberName,
911 ScriptDisp_GetNextDispID,
912 ScriptDisp_GetNameSpaceParent
915 HRESULT create_script_disp(script_ctx_t *ctx, ScriptDisp **ret)
917 ScriptDisp *script_disp;
919 script_disp = heap_alloc_zero(sizeof(*script_disp));
920 if(!script_disp)
921 return E_OUTOFMEMORY;
923 script_disp->IDispatchEx_iface.lpVtbl = &ScriptDispVtbl;
924 script_disp->ref = 1;
925 script_disp->ctx = ctx;
927 *ret = script_disp;
928 return S_OK;
931 void collect_objects(script_ctx_t *ctx)
933 vbdisp_t *iter, *iter2;
935 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &ctx->objects, vbdisp_t, entry)
936 run_terminator(iter);
938 while(!list_empty(&ctx->objects)) {
939 iter = LIST_ENTRY(list_head(&ctx->objects), vbdisp_t, entry);
941 IDispatchEx_AddRef(&iter->IDispatchEx_iface);
942 clean_props(iter);
943 iter->desc = NULL;
944 list_remove(&iter->entry);
945 list_init(&iter->entry);
946 IDispatchEx_Release(&iter->IDispatchEx_iface);
950 HRESULT disp_get_id(IDispatch *disp, BSTR name, vbdisp_invoke_type_t invoke_type, BOOL search_private, DISPID *id)
952 IDispatchEx *dispex;
953 vbdisp_t *vbdisp;
954 HRESULT hres;
956 vbdisp = unsafe_impl_from_IDispatch(disp);
957 if(vbdisp)
958 return vbdisp_get_id(vbdisp, name, invoke_type, search_private, id);
960 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
961 if(FAILED(hres)) {
962 TRACE("using IDispatch\n");
963 return IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, id);
966 hres = IDispatchEx_GetDispID(dispex, name, fdexNameCaseInsensitive, id);
967 IDispatchEx_Release(dispex);
968 return hres;
971 HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, DISPPARAMS *dp, VARIANT *retv)
973 const WORD flags = DISPATCH_METHOD|(retv ? DISPATCH_PROPERTYGET : 0);
974 IDispatchEx *dispex;
975 EXCEPINFO ei;
976 HRESULT hres;
978 memset(&ei, 0, sizeof(ei));
979 if(retv)
980 V_VT(retv) = VT_EMPTY;
982 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
983 if(FAILED(hres)) {
984 UINT err = 0;
986 TRACE("using IDispatch\n");
987 return IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, dp, retv, &ei, &err);
990 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, dp, retv, &ei, NULL /* CALLER_FIXME */);
991 IDispatchEx_Release(dispex);
992 return hres;
995 HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, DISPPARAMS *dp)
997 IDispatchEx *dispex;
998 EXCEPINFO ei = {0};
999 HRESULT hres;
1001 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1002 if(SUCCEEDED(hres)) {
1003 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, DISPATCH_PROPERTYPUT, dp, NULL, &ei, NULL /* FIXME! */);
1004 IDispatchEx_Release(dispex);
1005 }else {
1006 ULONG err = 0;
1008 TRACE("using IDispatch\n");
1009 hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, DISPATCH_PROPERTYPUT, dp, NULL, &ei, &err);
1012 return hres;