d3d8: Get rid of the format switching code in d3d8_device_CopyRects().
[wine.git] / dlls / vbscript / vbdisp.c
blob99f975a57d4d4ae6865bb65ea81566367004e867
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);
347 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
348 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
350 return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, NULL);
353 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
355 vbdisp_t *This = impl_from_IDispatchEx(iface);
357 TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
359 grfdex &= ~FDEX_VERSION_MASK;
361 if(!This->desc)
362 return E_UNEXPECTED;
364 /* Tests show that fdexNameCaseSensitive is ignored */
366 if(grfdex & ~(fdexNameEnsure|fdexNameCaseInsensitive|fdexNameCaseSensitive)) {
367 FIXME("unsupported flags %x\n", grfdex);
368 return E_NOTIMPL;
371 return vbdisp_get_id(This, bstrName, VBDISP_ANY, FALSE, pid);
374 static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
375 VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
377 vbdisp_t *This = impl_from_IDispatchEx(iface);
379 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
381 if(!This->desc)
382 return E_UNEXPECTED;
384 if(pvarRes)
385 V_VT(pvarRes) = VT_EMPTY;
387 if(id < 0)
388 return DISP_E_MEMBERNOTFOUND;
390 if(is_func_id(This, id)) {
391 function_t *func;
393 switch(wFlags) {
394 case DISPATCH_PROPERTYGET:
395 func = This->desc->funcs[id].entries[VBDISP_CALLGET];
396 if(!func || (func->type != FUNC_PROPGET && func->type != FUNC_DEFGET)) {
397 WARN("no getter\n");
398 return DISP_E_MEMBERNOTFOUND;
401 return exec_script(This->desc->ctx, func, This, pdp, pvarRes);
403 case DISPATCH_METHOD:
404 case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
405 func = This->desc->funcs[id].entries[VBDISP_CALLGET];
406 if(!func) {
407 FIXME("no invoke/getter\n");
408 return DISP_E_MEMBERNOTFOUND;
411 return exec_script(This->desc->ctx, func, This, pdp, pvarRes);
412 case DISPATCH_PROPERTYPUT: {
413 VARIANT *put_val;
414 DISPPARAMS dp = {NULL, NULL, 1, 0};
416 if(arg_cnt(pdp)) {
417 FIXME("arguments not implemented\n");
418 return E_NOTIMPL;
421 put_val = get_propput_arg(pdp);
422 if(!put_val) {
423 WARN("no value to set\n");
424 return DISP_E_PARAMNOTOPTIONAL;
427 dp.rgvarg = put_val;
428 func = This->desc->funcs[id].entries[V_VT(put_val) == VT_DISPATCH ? VBDISP_SET : VBDISP_LET];
429 if(!func) {
430 FIXME("no letter/setter\n");
431 return DISP_E_MEMBERNOTFOUND;
434 return exec_script(This->desc->ctx, func, This, &dp, NULL);
436 default:
437 FIXME("flags %x\n", wFlags);
438 return DISP_E_MEMBERNOTFOUND;
442 if(id < This->desc->prop_cnt + This->desc->func_cnt)
443 return invoke_variant_prop(This->props+(id-This->desc->func_cnt), wFlags, pdp, pvarRes);
445 if(This->desc->builtin_prop_cnt) {
446 unsigned min = 0, max = This->desc->builtin_prop_cnt-1, i;
448 while(min <= max) {
449 i = (min+max)/2;
450 if(This->desc->builtin_props[i].id == id)
451 return invoke_builtin(This, This->desc->builtin_props+i, wFlags, pdp, pvarRes);
452 if(This->desc->builtin_props[i].id < id)
453 min = i+1;
454 else
455 max = i-1;
459 return DISP_E_MEMBERNOTFOUND;
462 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
464 vbdisp_t *This = impl_from_IDispatchEx(iface);
465 FIXME("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex);
466 return E_NOTIMPL;
469 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
471 vbdisp_t *This = impl_from_IDispatchEx(iface);
472 FIXME("(%p)->(%x)\n", This, id);
473 return E_NOTIMPL;
476 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
478 vbdisp_t *This = impl_from_IDispatchEx(iface);
479 FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex);
480 return E_NOTIMPL;
483 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
485 vbdisp_t *This = impl_from_IDispatchEx(iface);
486 FIXME("(%p)->(%x %p)\n", This, id, pbstrName);
487 return E_NOTIMPL;
490 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
492 vbdisp_t *This = impl_from_IDispatchEx(iface);
493 FIXME("(%p)->(%x %x %p)\n", This, grfdex, id, pid);
494 return E_NOTIMPL;
497 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
499 vbdisp_t *This = impl_from_IDispatchEx(iface);
500 FIXME("(%p)->(%p)\n", This, ppunk);
501 return E_NOTIMPL;
504 static IDispatchExVtbl DispatchExVtbl = {
505 DispatchEx_QueryInterface,
506 DispatchEx_AddRef,
507 DispatchEx_Release,
508 DispatchEx_GetTypeInfoCount,
509 DispatchEx_GetTypeInfo,
510 DispatchEx_GetIDsOfNames,
511 DispatchEx_Invoke,
512 DispatchEx_GetDispID,
513 DispatchEx_InvokeEx,
514 DispatchEx_DeleteMemberByName,
515 DispatchEx_DeleteMemberByDispID,
516 DispatchEx_GetMemberProperties,
517 DispatchEx_GetMemberName,
518 DispatchEx_GetNextDispID,
519 DispatchEx_GetNameSpaceParent
522 static inline vbdisp_t *unsafe_impl_from_IDispatch(IDispatch *iface)
524 return iface->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl
525 ? CONTAINING_RECORD(iface, vbdisp_t, IDispatchEx_iface)
526 : NULL;
529 HRESULT create_vbdisp(const class_desc_t *desc, vbdisp_t **ret)
531 vbdisp_t *vbdisp;
532 HRESULT hres = S_OK;
534 vbdisp = heap_alloc_zero( FIELD_OFFSET( vbdisp_t, props[desc->prop_cnt] ));
535 if(!vbdisp)
536 return E_OUTOFMEMORY;
538 vbdisp->IDispatchEx_iface.lpVtbl = &DispatchExVtbl;
539 vbdisp->ref = 1;
540 vbdisp->desc = desc;
542 list_add_tail(&desc->ctx->objects, &vbdisp->entry);
544 if(desc->array_cnt) {
545 vbdisp->arrays = heap_alloc_zero(desc->array_cnt * sizeof(*vbdisp->arrays));
546 if(vbdisp->arrays) {
547 unsigned i, j;
549 for(i=0; i < desc->array_cnt; i++) {
550 if(!desc->array_descs[i].dim_cnt)
551 continue;
553 vbdisp->arrays[i] = SafeArrayCreate(VT_VARIANT, desc->array_descs[i].dim_cnt, desc->array_descs[i].bounds);
554 if(!vbdisp->arrays[i]) {
555 hres = E_OUTOFMEMORY;
556 break;
560 if(SUCCEEDED(hres)) {
561 for(i=0, j=0; i < desc->prop_cnt; i++) {
562 if(desc->props[i].is_array) {
563 V_VT(vbdisp->props+i) = VT_ARRAY|VT_BYREF|VT_VARIANT;
564 V_ARRAYREF(vbdisp->props+i) = vbdisp->arrays + j++;
568 }else {
569 hres = E_OUTOFMEMORY;
573 if(SUCCEEDED(hres) && desc->class_initialize_id) {
574 DISPPARAMS dp = {0};
575 hres = exec_script(desc->ctx, desc->funcs[desc->class_initialize_id].entries[VBDISP_CALLGET],
576 vbdisp, &dp, NULL);
579 if(FAILED(hres)) {
580 IDispatchEx_Release(&vbdisp->IDispatchEx_iface);
581 return hres;
584 *ret = vbdisp;
585 return S_OK;
588 static HRESULT Procedure_invoke(vbdisp_t *This, VARIANT *args, unsigned args_cnt, VARIANT *res)
590 script_ctx_t *ctx = This->desc->ctx;
591 HRESULT hres;
593 TRACE("\n");
595 IActiveScriptSite_OnEnterScript(ctx->site);
596 hres = exec_script(ctx, This->desc->value_func, NULL, NULL, NULL);
597 IActiveScriptSite_OnLeaveScript(ctx->site);
599 return hres;
602 static const builtin_prop_t procedure_props[] = {
603 {DISPID_VALUE, Procedure_invoke, 0}
606 HRESULT create_procedure_disp(script_ctx_t *ctx, vbscode_t *code, IDispatch **ret)
608 class_desc_t *desc;
609 vbdisp_t *vbdisp;
610 HRESULT hres;
612 desc = heap_alloc_zero(sizeof(*desc));
613 if(!desc)
614 return E_OUTOFMEMORY;
616 desc->ctx = ctx;
617 desc->builtin_prop_cnt = sizeof(procedure_props)/sizeof(*procedure_props);
618 desc->builtin_props = procedure_props;
619 desc->value_func = &code->main_code;
621 hres = create_vbdisp(desc, &vbdisp);
622 if(FAILED(hres)) {
623 heap_free(desc);
624 return hres;
627 desc->next = ctx->procs;
628 ctx->procs = desc;
630 *ret = (IDispatch*)&vbdisp->IDispatchEx_iface;
631 return S_OK;
634 struct _ident_map_t {
635 const WCHAR *name;
636 BOOL is_var;
637 union {
638 dynamic_var_t *var;
639 function_t *func;
640 } u;
643 static inline DISPID ident_to_id(ScriptDisp *This, ident_map_t *ident)
645 return (ident-This->ident_map)+1;
648 static inline ident_map_t *id_to_ident(ScriptDisp *This, DISPID id)
650 return 0 < id && id <= This->ident_map_cnt ? This->ident_map+id-1 : NULL;
653 static ident_map_t *add_ident(ScriptDisp *This, const WCHAR *name)
655 ident_map_t *ret;
657 if(!This->ident_map_size) {
658 This->ident_map = heap_alloc(4 * sizeof(*This->ident_map));
659 if(!This->ident_map)
660 return NULL;
661 This->ident_map_size = 4;
662 }else if(This->ident_map_cnt == This->ident_map_size) {
663 ident_map_t *new_map;
665 new_map = heap_realloc(This->ident_map, 2*This->ident_map_size*sizeof(*new_map));
666 if(!new_map)
667 return NULL;
668 This->ident_map = new_map;
669 This->ident_map_size *= 2;
672 ret = This->ident_map + This->ident_map_cnt++;
673 ret->name = name;
674 return ret;
677 static inline ScriptDisp *ScriptDisp_from_IDispatchEx(IDispatchEx *iface)
679 return CONTAINING_RECORD(iface, ScriptDisp, IDispatchEx_iface);
682 static HRESULT WINAPI ScriptDisp_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
684 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
686 if(IsEqualGUID(&IID_IUnknown, riid)) {
687 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
688 *ppv = &This->IDispatchEx_iface;
689 }else if(IsEqualGUID(&IID_IDispatch, riid)) {
690 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
691 *ppv = &This->IDispatchEx_iface;
692 }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
693 TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
694 *ppv = &This->IDispatchEx_iface;
695 }else {
696 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
697 *ppv = NULL;
698 return E_NOINTERFACE;
701 IUnknown_AddRef((IUnknown*)*ppv);
702 return S_OK;
705 static ULONG WINAPI ScriptDisp_AddRef(IDispatchEx *iface)
707 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
708 LONG ref = InterlockedIncrement(&This->ref);
710 TRACE("(%p) ref=%d\n", This, ref);
712 return ref;
715 static ULONG WINAPI ScriptDisp_Release(IDispatchEx *iface)
717 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
718 LONG ref = InterlockedDecrement(&This->ref);
720 TRACE("(%p) ref=%d\n", This, ref);
722 if(!ref) {
723 assert(!This->ctx);
724 heap_free(This->ident_map);
725 heap_free(This);
728 return ref;
731 static HRESULT WINAPI ScriptDisp_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
733 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
735 TRACE("(%p)->(%p)\n", This, pctinfo);
737 *pctinfo = 1;
738 return S_OK;
741 static HRESULT WINAPI ScriptDisp_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid,
742 ITypeInfo **ppTInfo)
744 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
745 FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
746 return E_NOTIMPL;
749 static HRESULT WINAPI ScriptDisp_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
750 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
752 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
753 UINT i;
754 HRESULT hres;
756 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
757 lcid, rgDispId);
759 for(i=0; i < cNames; i++) {
760 hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[i], 0, rgDispId+i);
761 if(FAILED(hres))
762 return hres;
765 return S_OK;
768 static HRESULT WINAPI ScriptDisp_Invoke(IDispatchEx *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
769 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
771 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
773 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
774 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
776 return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags,
777 pDispParams, pVarResult, pExcepInfo, NULL);
780 static HRESULT WINAPI ScriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
782 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
783 dynamic_var_t *var;
784 ident_map_t *ident;
785 function_t *func;
787 TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
789 if(!This->ctx)
790 return E_UNEXPECTED;
792 for(ident = This->ident_map; ident < This->ident_map+This->ident_map_cnt; ident++) {
793 if(!strcmpiW(ident->name, bstrName)) {
794 *pid = ident_to_id(This, ident);
795 return S_OK;
799 for(var = This->ctx->global_vars; var; var = var->next) {
800 if(!strcmpiW(var->name, bstrName)) {
801 ident = add_ident(This, var->name);
802 if(!ident)
803 return E_OUTOFMEMORY;
805 ident->is_var = TRUE;
806 ident->u.var = var;
807 *pid = ident_to_id(This, ident);
808 return S_OK;
812 for(func = This->ctx->global_funcs; func; func = func->next) {
813 if(!strcmpiW(func->name, bstrName)) {
814 ident = add_ident(This, func->name);
815 if(!ident)
816 return E_OUTOFMEMORY;
818 ident->is_var = FALSE;
819 ident->u.func = func;
820 *pid = ident_to_id(This, ident);
821 return S_OK;
825 *pid = -1;
826 return DISP_E_UNKNOWNNAME;
829 static HRESULT WINAPI ScriptDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
830 VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
832 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
833 ident_map_t *ident;
834 HRESULT hres;
836 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
838 ident = id_to_ident(This, id);
839 if(!ident)
840 return DISP_E_MEMBERNOTFOUND;
842 if(ident->is_var) {
843 if(ident->u.var->is_const) {
844 FIXME("const not supported\n");
845 return E_NOTIMPL;
848 return invoke_variant_prop(&ident->u.var->v, wFlags, pdp, pvarRes);
851 switch(wFlags) {
852 case DISPATCH_METHOD:
853 case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
854 IActiveScriptSite_OnEnterScript(This->ctx->site);
855 hres = exec_script(This->ctx, ident->u.func, NULL, pdp, pvarRes);
856 IActiveScriptSite_OnLeaveScript(This->ctx->site);
857 break;
858 default:
859 FIXME("Unsupported flags %x\n", wFlags);
860 hres = E_NOTIMPL;
863 return hres;
866 static HRESULT WINAPI ScriptDisp_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
868 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
869 FIXME("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex);
870 return E_NOTIMPL;
873 static HRESULT WINAPI ScriptDisp_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
875 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
876 FIXME("(%p)->(%x)\n", This, id);
877 return E_NOTIMPL;
880 static HRESULT WINAPI ScriptDisp_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
882 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
883 FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex);
884 return E_NOTIMPL;
887 static HRESULT WINAPI ScriptDisp_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
889 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
890 FIXME("(%p)->(%x %p)\n", This, id, pbstrName);
891 return E_NOTIMPL;
894 static HRESULT WINAPI ScriptDisp_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
896 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
897 FIXME("(%p)->(%x %x %p)\n", This, grfdex, id, pid);
898 return E_NOTIMPL;
901 static HRESULT WINAPI ScriptDisp_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
903 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
904 FIXME("(%p)->(%p)\n", This, ppunk);
905 return E_NOTIMPL;
908 static IDispatchExVtbl ScriptDispVtbl = {
909 ScriptDisp_QueryInterface,
910 ScriptDisp_AddRef,
911 ScriptDisp_Release,
912 ScriptDisp_GetTypeInfoCount,
913 ScriptDisp_GetTypeInfo,
914 ScriptDisp_GetIDsOfNames,
915 ScriptDisp_Invoke,
916 ScriptDisp_GetDispID,
917 ScriptDisp_InvokeEx,
918 ScriptDisp_DeleteMemberByName,
919 ScriptDisp_DeleteMemberByDispID,
920 ScriptDisp_GetMemberProperties,
921 ScriptDisp_GetMemberName,
922 ScriptDisp_GetNextDispID,
923 ScriptDisp_GetNameSpaceParent
926 HRESULT create_script_disp(script_ctx_t *ctx, ScriptDisp **ret)
928 ScriptDisp *script_disp;
930 script_disp = heap_alloc_zero(sizeof(*script_disp));
931 if(!script_disp)
932 return E_OUTOFMEMORY;
934 script_disp->IDispatchEx_iface.lpVtbl = &ScriptDispVtbl;
935 script_disp->ref = 1;
936 script_disp->ctx = ctx;
938 *ret = script_disp;
939 return S_OK;
942 void collect_objects(script_ctx_t *ctx)
944 vbdisp_t *iter, *iter2;
946 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &ctx->objects, vbdisp_t, entry)
947 run_terminator(iter);
949 while(!list_empty(&ctx->objects)) {
950 iter = LIST_ENTRY(list_head(&ctx->objects), vbdisp_t, entry);
952 IDispatchEx_AddRef(&iter->IDispatchEx_iface);
953 clean_props(iter);
954 iter->desc = NULL;
955 list_remove(&iter->entry);
956 list_init(&iter->entry);
957 IDispatchEx_Release(&iter->IDispatchEx_iface);
961 HRESULT disp_get_id(IDispatch *disp, BSTR name, vbdisp_invoke_type_t invoke_type, BOOL search_private, DISPID *id)
963 IDispatchEx *dispex;
964 vbdisp_t *vbdisp;
965 HRESULT hres;
967 vbdisp = unsafe_impl_from_IDispatch(disp);
968 if(vbdisp)
969 return vbdisp_get_id(vbdisp, name, invoke_type, search_private, id);
971 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
972 if(FAILED(hres)) {
973 TRACE("using IDispatch\n");
974 return IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, id);
977 hres = IDispatchEx_GetDispID(dispex, name, fdexNameCaseInsensitive, id);
978 IDispatchEx_Release(dispex);
979 return hres;
982 #define RPC_E_SERVER_UNAVAILABLE 0x800706ba
984 HRESULT map_hres(HRESULT hres)
986 if(SUCCEEDED(hres) || HRESULT_FACILITY(hres) == FACILITY_VBS)
987 return hres;
989 switch(hres) {
990 case E_NOTIMPL: return MAKE_VBSERROR(VBSE_ACTION_NOT_SUPPORTED);
991 case E_NOINTERFACE: return MAKE_VBSERROR(VBSE_OLE_NOT_SUPPORTED);
992 case DISP_E_UNKNOWNINTERFACE: return MAKE_VBSERROR(VBSE_OLE_NO_PROP_OR_METHOD);
993 case DISP_E_MEMBERNOTFOUND: return MAKE_VBSERROR(VBSE_OLE_NO_PROP_OR_METHOD);
994 case DISP_E_PARAMNOTFOUND: return MAKE_VBSERROR(VBSE_NAMED_PARAM_NOT_FOUND);
995 case DISP_E_TYPEMISMATCH: return MAKE_VBSERROR(VBSE_TYPE_MISMATCH);
996 case DISP_E_UNKNOWNNAME: return MAKE_VBSERROR(VBSE_OLE_NO_PROP_OR_METHOD);
997 case DISP_E_NONAMEDARGS: return MAKE_VBSERROR(VBSE_NAMED_ARGS_NOT_SUPPORTED);
998 case DISP_E_BADVARTYPE: return MAKE_VBSERROR(VBSE_INVALID_TYPELIB_VARIABLE);
999 case DISP_E_OVERFLOW: return MAKE_VBSERROR(VBSE_OVERFLOW);
1000 case DISP_E_BADINDEX: return MAKE_VBSERROR(VBSE_OUT_OF_BOUNDS);
1001 case DISP_E_UNKNOWNLCID: return MAKE_VBSERROR(VBSE_LOCALE_SETTING_NOT_SUPPORTED);
1002 case DISP_E_ARRAYISLOCKED: return MAKE_VBSERROR(VBSE_ARRAY_LOCKED);
1003 case DISP_E_BADPARAMCOUNT: return MAKE_VBSERROR(VBSE_FUNC_ARITY_MISMATCH);
1004 case DISP_E_PARAMNOTOPTIONAL: return MAKE_VBSERROR(VBSE_PARAMETER_NOT_OPTIONAL);
1005 case DISP_E_NOTACOLLECTION: return MAKE_VBSERROR(VBSE_NOT_ENUM);
1006 case TYPE_E_DLLFUNCTIONNOTFOUND: return MAKE_VBSERROR(VBSE_INVALID_DLL_FUNCTION_NAME);
1007 case TYPE_E_TYPEMISMATCH: return MAKE_VBSERROR(VBSE_TYPE_MISMATCH);
1008 case TYPE_E_OUTOFBOUNDS: return MAKE_VBSERROR(VBSE_OUT_OF_BOUNDS);
1009 case TYPE_E_IOERROR: return MAKE_VBSERROR(VBSE_IO_ERROR);
1010 case TYPE_E_CANTCREATETMPFILE: return MAKE_VBSERROR(VBSE_CANT_CREATE_TMP_FILE);
1011 case STG_E_FILENOTFOUND: return MAKE_VBSERROR(VBSE_OLE_FILE_NOT_FOUND);
1012 case STG_E_PATHNOTFOUND: return MAKE_VBSERROR(VBSE_PATH_NOT_FOUND);
1013 case STG_E_TOOMANYOPENFILES: return MAKE_VBSERROR(VBSE_TOO_MANY_FILES);
1014 case STG_E_ACCESSDENIED: return MAKE_VBSERROR(VBSE_PERMISSION_DENIED);
1015 case STG_E_INSUFFICIENTMEMORY: return MAKE_VBSERROR(VBSE_OUT_OF_MEMORY);
1016 case STG_E_NOMOREFILES: return MAKE_VBSERROR(VBSE_TOO_MANY_FILES);
1017 case STG_E_DISKISWRITEPROTECTED: return MAKE_VBSERROR(VBSE_PERMISSION_DENIED);
1018 case STG_E_WRITEFAULT: return MAKE_VBSERROR(VBSE_IO_ERROR);
1019 case STG_E_READFAULT: return MAKE_VBSERROR(VBSE_IO_ERROR);
1020 case STG_E_SHAREVIOLATION: return MAKE_VBSERROR(VBSE_PATH_FILE_ACCESS);
1021 case STG_E_LOCKVIOLATION: return MAKE_VBSERROR(VBSE_PERMISSION_DENIED);
1022 case STG_E_FILEALREADYEXISTS: return MAKE_VBSERROR(VBSE_FILE_ALREADY_EXISTS);
1023 case STG_E_MEDIUMFULL: return MAKE_VBSERROR(VBSE_DISK_FULL);
1024 case STG_E_INVALIDNAME: return MAKE_VBSERROR(VBSE_FILE_NOT_FOUND);
1025 case STG_E_INUSE: return MAKE_VBSERROR(VBSE_PERMISSION_DENIED);
1026 case STG_E_NOTCURRENT: return MAKE_VBSERROR(VBSE_PERMISSION_DENIED);
1027 case STG_E_CANTSAVE: return MAKE_VBSERROR(VBSE_IO_ERROR);
1028 case REGDB_E_CLASSNOTREG: return MAKE_VBSERROR(VBSE_CANT_CREATE_OBJECT);
1029 case MK_E_UNAVAILABLE: return MAKE_VBSERROR(VBSE_CANT_CREATE_OBJECT);
1030 case MK_E_INVALIDEXTENSION: return MAKE_VBSERROR(VBSE_OLE_FILE_NOT_FOUND);
1031 case MK_E_CANTOPENFILE: return MAKE_VBSERROR(VBSE_OLE_FILE_NOT_FOUND);
1032 case CO_E_CLASSSTRING: return MAKE_VBSERROR(VBSE_CANT_CREATE_OBJECT);
1033 case CO_E_APPNOTFOUND: return MAKE_VBSERROR(VBSE_CANT_CREATE_OBJECT);
1034 case CO_E_APPDIDNTREG: return MAKE_VBSERROR(VBSE_CANT_CREATE_OBJECT);
1035 case E_ACCESSDENIED: return MAKE_VBSERROR(VBSE_PERMISSION_DENIED);
1036 case E_OUTOFMEMORY: return MAKE_VBSERROR(VBSE_OUT_OF_MEMORY);
1037 case E_INVALIDARG: return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
1038 case RPC_E_SERVER_UNAVAILABLE: return MAKE_VBSERROR(VBSE_SERVER_NOT_FOUND);
1039 case CO_E_SERVER_EXEC_FAILURE: return MAKE_VBSERROR(VBSE_CANT_CREATE_OBJECT);
1042 return hres;
1045 HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, DISPPARAMS *dp, VARIANT *retv)
1047 const WORD flags = DISPATCH_METHOD|(retv ? DISPATCH_PROPERTYGET : 0);
1048 IDispatchEx *dispex;
1049 EXCEPINFO ei;
1050 HRESULT hres;
1052 memset(&ei, 0, sizeof(ei));
1053 if(retv)
1054 V_VT(retv) = VT_EMPTY;
1056 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1057 if(FAILED(hres)) {
1058 UINT err = 0;
1060 TRACE("using IDispatch\n");
1061 return IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, dp, retv, &ei, &err);
1064 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, dp, retv, &ei, NULL /* CALLER_FIXME */);
1065 IDispatchEx_Release(dispex);
1066 return hres;
1069 HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, DISPPARAMS *dp)
1071 IDispatchEx *dispex;
1072 EXCEPINFO ei = {0};
1073 HRESULT hres;
1075 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1076 if(SUCCEEDED(hres)) {
1077 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, DISPATCH_PROPERTYPUT, dp, NULL, &ei, NULL /* FIXME! */);
1078 IDispatchEx_Release(dispex);
1079 }else {
1080 ULONG err = 0;
1082 TRACE("using IDispatch\n");
1083 hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, DISPATCH_PROPERTYPUT, dp, NULL, &ei, &err);
1086 return hres;