gdi32/tests: Mark tests failing randomly on Windows as flaky.
[wine.git] / dlls / vbscript / vbdisp.c
blob74da0a21fb0576e261054e2792acf33d6eede784
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 static const GUID GUID_VBScriptTypeInfo = {0xc59c6b12,0xf6c1,0x11cf,{0x88,0x35,0x00,0xa0,0xc9,0x11,0xe8,0xb2}};
29 #define DISPID_FUNCTION_MASK 0x20000000
30 #define FDEX_VERSION_MASK 0xf0000000
32 static inline BOOL is_func_id(vbdisp_t *This, DISPID id)
34 return id < This->desc->func_cnt;
37 static BOOL get_func_id(vbdisp_t *This, const WCHAR *name, vbdisp_invoke_type_t invoke_type, BOOL search_private, DISPID *id)
39 unsigned i;
41 for(i = 0; i < This->desc->func_cnt; i++) {
42 if(invoke_type == VBDISP_ANY) {
43 if(!search_private && !This->desc->funcs[i].is_public)
44 continue;
45 }else {
46 if(!This->desc->funcs[i].entries[invoke_type]
47 || (!search_private && !This->desc->funcs[i].entries[invoke_type]->is_public))
48 continue;
51 if(This->desc->funcs[i].name && !wcsicmp(This->desc->funcs[i].name, name)) {
52 *id = i;
53 return TRUE;
57 return FALSE;
60 HRESULT vbdisp_get_id(vbdisp_t *This, BSTR name, vbdisp_invoke_type_t invoke_type, BOOL search_private, DISPID *id)
62 unsigned i;
64 if(get_func_id(This, name, invoke_type, search_private, id))
65 return S_OK;
67 for(i=0; i < This->desc->prop_cnt; i++) {
68 if(!search_private && !This->desc->props[i].is_public)
69 continue;
71 if(!wcsicmp(This->desc->props[i].name, name)) {
72 *id = i + This->desc->func_cnt;
73 return S_OK;
77 *id = -1;
78 return DISP_E_UNKNOWNNAME;
81 static HRESULT get_propput_arg(script_ctx_t *ctx, const DISPPARAMS *dp, WORD flags, VARIANT *v, BOOL *is_owned)
83 unsigned i;
85 for(i=0; i < dp->cNamedArgs; i++) {
86 if(dp->rgdispidNamedArgs[i] == DISPID_PROPERTYPUT)
87 break;
89 if(i == dp->cNamedArgs) {
90 WARN("no value to set\n");
91 return DISP_E_PARAMNOTOPTIONAL;
94 *v = dp->rgvarg[i];
95 if(V_VT(v) == (VT_VARIANT|VT_BYREF))
96 *v = *V_VARIANTREF(v);
97 *is_owned = FALSE;
99 if(V_VT(v) == VT_DISPATCH) {
100 if(!(flags & DISPATCH_PROPERTYPUTREF)) {
101 HRESULT hres;
103 hres = get_disp_value(ctx, V_DISPATCH(v), v);
104 if(FAILED(hres))
105 return hres;
107 *is_owned = TRUE;
109 }else if(!(flags & DISPATCH_PROPERTYPUT)) {
110 WARN("%s can't be assigned without DISPATCH_PROPERTYPUT flag\n", debugstr_variant(v));
111 return DISP_E_EXCEPTION;
114 return S_OK;
117 static HRESULT invoke_variant_prop(script_ctx_t *ctx, VARIANT *v, WORD flags, DISPPARAMS *dp, VARIANT *res)
119 HRESULT hres;
121 switch(flags) {
122 case DISPATCH_PROPERTYGET|DISPATCH_METHOD:
123 case DISPATCH_PROPERTYGET:
124 if(dp->cArgs) {
125 WARN("called with arguments\n");
126 return DISP_E_MEMBERNOTFOUND; /* That's what tests show */
129 hres = VariantCopyInd(res, v);
130 break;
132 case DISPATCH_PROPERTYPUT:
133 case DISPATCH_PROPERTYPUTREF:
134 case DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF: {
135 VARIANT put_val;
136 BOOL own_val;
138 hres = get_propput_arg(ctx, dp, flags, &put_val, &own_val);
139 if(FAILED(hres))
140 return hres;
142 if(arg_cnt(dp)) {
143 FIXME("Arguments not supported\n");
144 return E_NOTIMPL;
147 if(res)
148 V_VT(res) = VT_EMPTY;
150 if(own_val)
151 *v = put_val;
152 else
153 hres = VariantCopyInd(v, &put_val);
154 break;
157 default:
158 FIXME("unimplemented flags %x\n", flags);
159 return E_NOTIMPL;
162 return hres;
165 static HRESULT invoke_vbdisp(vbdisp_t *This, DISPID id, DWORD flags, BOOL extern_caller, DISPPARAMS *params, VARIANT *res)
167 if(id < 0)
168 return DISP_E_MEMBERNOTFOUND;
170 if(is_func_id(This, id)) {
171 function_t *func;
173 TRACE("%p->%s\n", This, debugstr_w(This->desc->funcs[id].name));
175 switch(flags) {
176 case DISPATCH_PROPERTYGET:
177 func = This->desc->funcs[id].entries[VBDISP_CALLGET];
178 if(!func || func->type != FUNC_PROPGET) {
179 WARN("no getter\n");
180 return DISP_E_MEMBERNOTFOUND;
183 return exec_script(This->desc->ctx, extern_caller, func, This, params, res);
185 case DISPATCH_METHOD:
186 case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
187 func = This->desc->funcs[id].entries[VBDISP_CALLGET];
188 if(!func) {
189 FIXME("no invoke/getter\n");
190 return DISP_E_MEMBERNOTFOUND;
193 return exec_script(This->desc->ctx, extern_caller, func, This, params, res);
195 case DISPATCH_PROPERTYPUT:
196 case DISPATCH_PROPERTYPUTREF:
197 case DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF: {
198 DISPPARAMS dp = {NULL, NULL, 1, 0};
199 BOOL needs_release;
200 VARIANT buf[6];
201 HRESULT hres;
202 INT i;
204 dp.cArgs = arg_cnt(params) + 1;
205 if(dp.cArgs > ARRAY_SIZE(buf)) {
206 dp.rgvarg = heap_alloc(dp.cArgs*sizeof(VARIANT));
207 if(!dp.rgvarg)
208 return E_OUTOFMEMORY;
209 }else {
210 dp.rgvarg = buf;
213 hres = get_propput_arg(This->desc->ctx, params, flags, dp.rgvarg, &needs_release);
214 if(FAILED(hres)) {
215 if(dp.rgvarg != buf)
216 heap_free(dp.rgvarg);
217 return hres;
220 func = This->desc->funcs[id].entries[V_VT(dp.rgvarg) == VT_DISPATCH ? VBDISP_SET : VBDISP_LET];
221 if(!func) {
222 FIXME("no letter/setter\n");
223 if(dp.rgvarg != buf)
224 heap_free(dp.rgvarg);
225 return DISP_E_MEMBERNOTFOUND;
228 for(i=1; i < dp.cArgs; i++) {
229 dp.rgvarg[i]=params->rgvarg[params->cNamedArgs+i-1];
232 hres = exec_script(This->desc->ctx, extern_caller, func, This, &dp, NULL);
233 if(needs_release)
234 VariantClear(dp.rgvarg);
235 if(dp.rgvarg != buf)
236 heap_free(dp.rgvarg);
237 return hres;
239 default:
240 FIXME("flags %lx\n", flags);
241 return DISP_E_MEMBERNOTFOUND;
245 if(id >= This->desc->prop_cnt + This->desc->func_cnt)
246 return DISP_E_MEMBERNOTFOUND;
248 TRACE("%p->%s\n", This, debugstr_w(This->desc->props[id - This->desc->func_cnt].name));
249 return invoke_variant_prop(This->desc->ctx, This->props+(id-This->desc->func_cnt), flags, params, res);
252 static BOOL run_terminator(vbdisp_t *This)
254 DISPPARAMS dp = {0};
256 if(This->terminator_ran)
257 return TRUE;
258 This->terminator_ran = TRUE;
260 if(!This->desc->class_terminate_id)
261 return TRUE;
263 This->ref++;
264 exec_script(This->desc->ctx, FALSE, This->desc->funcs[This->desc->class_terminate_id].entries[VBDISP_CALLGET],
265 This, &dp, NULL);
266 return !--This->ref;
269 static void clean_props(vbdisp_t *This)
271 unsigned i;
273 if(!This->desc)
274 return;
276 for(i=0; i < This->desc->array_cnt; i++) {
277 if(This->arrays[i]) {
278 SafeArrayDestroy(This->arrays[i]);
279 This->arrays[i] = NULL;
283 for(i=0; i < This->desc->prop_cnt; i++)
284 VariantClear(This->props+i);
287 static inline vbdisp_t *impl_from_IDispatchEx(IDispatchEx *iface)
289 return CONTAINING_RECORD(iface, vbdisp_t, IDispatchEx_iface);
292 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
294 vbdisp_t *This = impl_from_IDispatchEx(iface);
296 if(IsEqualGUID(&IID_IUnknown, riid)) {
297 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
298 *ppv = &This->IDispatchEx_iface;
299 }else if(IsEqualGUID(&IID_IDispatch, riid)) {
300 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
301 *ppv = &This->IDispatchEx_iface;
302 }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
303 TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
304 *ppv = &This->IDispatchEx_iface;
305 }else {
306 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
307 *ppv = NULL;
308 return E_NOINTERFACE;
311 IUnknown_AddRef((IUnknown*)*ppv);
312 return S_OK;
315 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
317 vbdisp_t *This = impl_from_IDispatchEx(iface);
318 LONG ref = InterlockedIncrement(&This->ref);
320 TRACE("(%p) ref=%ld\n", This, ref);
322 return ref;
325 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
327 vbdisp_t *This = impl_from_IDispatchEx(iface);
328 LONG ref = InterlockedDecrement(&This->ref);
330 TRACE("(%p) ref=%ld\n", This, ref);
332 if(!ref && run_terminator(This)) {
333 clean_props(This);
334 list_remove(&This->entry);
335 heap_free(This->arrays);
336 heap_free(This);
339 return ref;
342 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
344 vbdisp_t *This = impl_from_IDispatchEx(iface);
346 TRACE("(%p)->(%p)\n", This, pctinfo);
348 *pctinfo = 1;
349 return S_OK;
352 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid,
353 ITypeInfo **ppTInfo)
355 vbdisp_t *This = impl_from_IDispatchEx(iface);
356 FIXME("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ppTInfo);
357 return E_NOTIMPL;
360 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
361 LPOLESTR *rgszNames, UINT cNames, LCID lcid,
362 DISPID *rgDispId)
364 vbdisp_t *This = impl_from_IDispatchEx(iface);
365 FIXME("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
366 lcid, rgDispId);
367 return E_NOTIMPL;
370 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
371 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
372 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
374 vbdisp_t *This = impl_from_IDispatchEx(iface);
376 TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
377 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
379 return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, NULL);
382 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
384 vbdisp_t *This = impl_from_IDispatchEx(iface);
386 TRACE("(%p)->(%s %lx %p)\n", This, debugstr_w(bstrName), grfdex, pid);
388 grfdex &= ~FDEX_VERSION_MASK;
390 if(!This->desc)
391 return E_UNEXPECTED;
393 /* Tests show that fdexNameCaseSensitive is ignored */
395 if(grfdex & ~(fdexNameEnsure|fdexNameCaseInsensitive|fdexNameCaseSensitive)) {
396 FIXME("unsupported flags %lx\n", grfdex);
397 return E_NOTIMPL;
400 return vbdisp_get_id(This, bstrName, VBDISP_ANY, FALSE, pid);
403 static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
404 VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
406 vbdisp_t *This = impl_from_IDispatchEx(iface);
408 TRACE("(%p)->(%lx %lx %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
410 if(!This->desc)
411 return E_UNEXPECTED;
413 if(pvarRes)
414 V_VT(pvarRes) = VT_EMPTY;
416 return invoke_vbdisp(This, id, wFlags, TRUE, pdp, pvarRes);
419 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
421 vbdisp_t *This = impl_from_IDispatchEx(iface);
422 FIXME("(%p)->(%s %lx)\n", This, debugstr_w(bstrName), grfdex);
423 return E_NOTIMPL;
426 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
428 vbdisp_t *This = impl_from_IDispatchEx(iface);
429 FIXME("(%p)->(%lx)\n", This, id);
430 return E_NOTIMPL;
433 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
435 vbdisp_t *This = impl_from_IDispatchEx(iface);
436 FIXME("(%p)->(%lx %lx %p)\n", This, id, grfdexFetch, pgrfdex);
437 return E_NOTIMPL;
440 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
442 vbdisp_t *This = impl_from_IDispatchEx(iface);
443 FIXME("(%p)->(%lx %p)\n", This, id, pbstrName);
444 return E_NOTIMPL;
447 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
449 vbdisp_t *This = impl_from_IDispatchEx(iface);
450 FIXME("(%p)->(%lx %lx %p)\n", This, grfdex, id, pid);
451 return E_NOTIMPL;
454 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
456 vbdisp_t *This = impl_from_IDispatchEx(iface);
457 FIXME("(%p)->(%p)\n", This, ppunk);
458 return E_NOTIMPL;
461 static IDispatchExVtbl DispatchExVtbl = {
462 DispatchEx_QueryInterface,
463 DispatchEx_AddRef,
464 DispatchEx_Release,
465 DispatchEx_GetTypeInfoCount,
466 DispatchEx_GetTypeInfo,
467 DispatchEx_GetIDsOfNames,
468 DispatchEx_Invoke,
469 DispatchEx_GetDispID,
470 DispatchEx_InvokeEx,
471 DispatchEx_DeleteMemberByName,
472 DispatchEx_DeleteMemberByDispID,
473 DispatchEx_GetMemberProperties,
474 DispatchEx_GetMemberName,
475 DispatchEx_GetNextDispID,
476 DispatchEx_GetNameSpaceParent
479 static inline vbdisp_t *unsafe_impl_from_IDispatch(IDispatch *iface)
481 return iface->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl
482 ? CONTAINING_RECORD(iface, vbdisp_t, IDispatchEx_iface)
483 : NULL;
486 HRESULT create_vbdisp(const class_desc_t *desc, vbdisp_t **ret)
488 vbdisp_t *vbdisp;
489 HRESULT hres = S_OK;
491 vbdisp = heap_alloc_zero( FIELD_OFFSET( vbdisp_t, props[desc->prop_cnt] ));
492 if(!vbdisp)
493 return E_OUTOFMEMORY;
495 vbdisp->IDispatchEx_iface.lpVtbl = &DispatchExVtbl;
496 vbdisp->ref = 1;
497 vbdisp->desc = desc;
499 list_add_tail(&desc->ctx->objects, &vbdisp->entry);
501 if(desc->array_cnt) {
502 vbdisp->arrays = heap_alloc_zero(desc->array_cnt * sizeof(*vbdisp->arrays));
503 if(vbdisp->arrays) {
504 unsigned i, j;
506 for(i=0; i < desc->array_cnt; i++) {
507 if(!desc->array_descs[i].dim_cnt)
508 continue;
510 vbdisp->arrays[i] = SafeArrayCreate(VT_VARIANT, desc->array_descs[i].dim_cnt, desc->array_descs[i].bounds);
511 if(!vbdisp->arrays[i]) {
512 hres = E_OUTOFMEMORY;
513 break;
517 if(SUCCEEDED(hres)) {
518 for(i=0, j=0; i < desc->prop_cnt; i++) {
519 if(desc->props[i].is_array) {
520 V_VT(vbdisp->props+i) = VT_ARRAY|VT_BYREF|VT_VARIANT;
521 V_ARRAYREF(vbdisp->props+i) = vbdisp->arrays + j++;
525 }else {
526 hres = E_OUTOFMEMORY;
530 if(SUCCEEDED(hres) && desc->class_initialize_id) {
531 DISPPARAMS dp = {0};
532 hres = exec_script(desc->ctx, FALSE, desc->funcs[desc->class_initialize_id].entries[VBDISP_CALLGET],
533 vbdisp, &dp, NULL);
536 if(FAILED(hres)) {
537 IDispatchEx_Release(&vbdisp->IDispatchEx_iface);
538 return hres;
541 *ret = vbdisp;
542 return S_OK;
545 struct typeinfo_func {
546 function_t *func;
547 MEMBERID memid;
550 typedef struct {
551 ITypeInfo ITypeInfo_iface;
552 ITypeComp ITypeComp_iface;
553 LONG ref;
555 UINT num_vars;
556 UINT num_funcs;
557 struct typeinfo_func *funcs;
559 ScriptDisp *disp;
560 } ScriptTypeInfo;
562 static function_t *get_func_from_memid(const ScriptTypeInfo *typeinfo, MEMBERID memid)
564 UINT a = 0, b = typeinfo->num_funcs;
566 if (!(memid & DISPID_FUNCTION_MASK)) return NULL;
568 while (a < b)
570 UINT i = (a + b - 1) / 2;
572 if (memid == typeinfo->funcs[i].memid)
573 return typeinfo->funcs[i].func;
574 else if (memid < typeinfo->funcs[i].memid)
575 b = i;
576 else
577 a = i + 1;
579 return NULL;
582 static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeInfo(ITypeInfo *iface)
584 return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeInfo_iface);
587 static inline ScriptTypeInfo *ScriptTypeInfo_from_ITypeComp(ITypeComp *iface)
589 return CONTAINING_RECORD(iface, ScriptTypeInfo, ITypeComp_iface);
592 static HRESULT WINAPI ScriptTypeInfo_QueryInterface(ITypeInfo *iface, REFIID riid, void **ppv)
594 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
596 if (IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_ITypeInfo, riid))
597 *ppv = &This->ITypeInfo_iface;
598 else if (IsEqualGUID(&IID_ITypeComp, riid))
599 *ppv = &This->ITypeComp_iface;
600 else
602 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
603 *ppv = NULL;
604 return E_NOINTERFACE;
607 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
608 IUnknown_AddRef((IUnknown*)*ppv);
609 return S_OK;
612 static ULONG WINAPI ScriptTypeInfo_AddRef(ITypeInfo *iface)
614 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
615 LONG ref = InterlockedIncrement(&This->ref);
617 TRACE("(%p) ref=%ld\n", This, ref);
619 return ref;
622 static ULONG WINAPI ScriptTypeInfo_Release(ITypeInfo *iface)
624 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
625 LONG ref = InterlockedDecrement(&This->ref);
626 UINT i;
628 TRACE("(%p) ref=%ld\n", This, ref);
630 if (!ref)
632 for (i = 0; i < This->num_funcs; i++)
633 release_vbscode(This->funcs[i].func->code_ctx);
635 IDispatchEx_Release(&This->disp->IDispatchEx_iface);
636 heap_free(This->funcs);
637 heap_free(This);
639 return ref;
642 static HRESULT WINAPI ScriptTypeInfo_GetTypeAttr(ITypeInfo *iface, TYPEATTR **ppTypeAttr)
644 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
645 TYPEATTR *attr;
647 TRACE("(%p)->(%p)\n", This, ppTypeAttr);
649 if (!ppTypeAttr) return E_INVALIDARG;
651 attr = heap_alloc_zero(sizeof(*attr));
652 if (!attr) return E_OUTOFMEMORY;
654 attr->guid = GUID_VBScriptTypeInfo;
655 attr->lcid = LOCALE_USER_DEFAULT;
656 attr->memidConstructor = MEMBERID_NIL;
657 attr->memidDestructor = MEMBERID_NIL;
658 attr->cbSizeInstance = 4;
659 attr->typekind = TKIND_DISPATCH;
660 attr->cFuncs = This->num_funcs;
661 attr->cVars = This->num_vars;
662 attr->cImplTypes = 1;
663 attr->cbSizeVft = sizeof(IDispatchVtbl);
664 attr->cbAlignment = 4;
665 attr->wTypeFlags = TYPEFLAG_FDISPATCHABLE;
666 attr->wMajorVerNum = VBSCRIPT_MAJOR_VERSION;
667 attr->wMinorVerNum = VBSCRIPT_MINOR_VERSION;
669 *ppTypeAttr = attr;
670 return S_OK;
673 static HRESULT WINAPI ScriptTypeInfo_GetTypeComp(ITypeInfo *iface, ITypeComp **ppTComp)
675 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
677 TRACE("(%p)->(%p)\n", This, ppTComp);
679 if (!ppTComp) return E_INVALIDARG;
681 *ppTComp = &This->ITypeComp_iface;
682 ITypeInfo_AddRef(iface);
683 return S_OK;
686 static HRESULT WINAPI ScriptTypeInfo_GetFuncDesc(ITypeInfo *iface, UINT index, FUNCDESC **ppFuncDesc)
688 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
689 function_t *func;
690 FUNCDESC *desc;
691 UINT i;
693 TRACE("(%p)->(%u %p)\n", This, index, ppFuncDesc);
695 if (!ppFuncDesc) return E_INVALIDARG;
696 if (index >= This->num_funcs) return TYPE_E_ELEMENTNOTFOUND;
697 func = This->funcs[index].func;
699 /* Store the parameter array after the FUNCDESC structure */
700 desc = heap_alloc_zero(sizeof(*desc) + sizeof(ELEMDESC) * func->arg_cnt);
701 if (!desc) return E_OUTOFMEMORY;
703 desc->memid = This->funcs[index].memid;
704 desc->funckind = FUNC_DISPATCH;
705 desc->invkind = INVOKE_FUNC;
706 desc->callconv = CC_STDCALL;
707 desc->cParams = func->arg_cnt;
708 desc->elemdescFunc.tdesc.vt = (func->type == FUNC_SUB) ? VT_VOID : VT_VARIANT;
710 if (func->arg_cnt) desc->lprgelemdescParam = (ELEMDESC*)(desc + 1);
711 for (i = 0; i < func->arg_cnt; i++)
712 desc->lprgelemdescParam[i].tdesc.vt = VT_VARIANT;
714 *ppFuncDesc = desc;
715 return S_OK;
718 static HRESULT WINAPI ScriptTypeInfo_GetVarDesc(ITypeInfo *iface, UINT index, VARDESC **ppVarDesc)
720 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
721 VARDESC *desc;
723 TRACE("(%p)->(%u %p)\n", This, index, ppVarDesc);
725 if (!ppVarDesc) return E_INVALIDARG;
726 if (index >= This->num_vars) return TYPE_E_ELEMENTNOTFOUND;
728 desc = heap_alloc_zero(sizeof(*desc));
729 if (!desc) return E_OUTOFMEMORY;
731 desc->memid = index + 1;
732 desc->varkind = VAR_DISPATCH;
733 desc->elemdescVar.tdesc.vt = VT_VARIANT;
735 *ppVarDesc = desc;
736 return S_OK;
739 static HRESULT WINAPI ScriptTypeInfo_GetNames(ITypeInfo *iface, MEMBERID memid, BSTR *rgBstrNames,
740 UINT cMaxNames, UINT *pcNames)
742 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
743 ITypeInfo *disp_typeinfo;
744 function_t *func;
745 HRESULT hr;
746 UINT i = 0;
748 TRACE("(%p)->(%ld %p %u %p)\n", This, memid, rgBstrNames, cMaxNames, pcNames);
750 if (!rgBstrNames || !pcNames) return E_INVALIDARG;
751 if (memid <= 0) return TYPE_E_ELEMENTNOTFOUND;
753 func = get_func_from_memid(This, memid);
754 if (!func && memid > This->num_vars)
756 hr = get_dispatch_typeinfo(&disp_typeinfo);
757 if (FAILED(hr)) return hr;
759 return ITypeInfo_GetNames(disp_typeinfo, memid, rgBstrNames, cMaxNames, pcNames);
762 *pcNames = 0;
763 if (!cMaxNames) return S_OK;
765 if (func)
767 UINT num = min(cMaxNames, func->arg_cnt + 1);
769 rgBstrNames[0] = SysAllocString(func->name);
770 if (!rgBstrNames[0]) return E_OUTOFMEMORY;
772 for (i = 1; i < num; i++)
774 if (!(rgBstrNames[i] = SysAllocString(func->args[i - 1].name)))
776 do SysFreeString(rgBstrNames[--i]); while (i);
777 return E_OUTOFMEMORY;
781 else
783 rgBstrNames[0] = SysAllocString(This->disp->global_vars[memid - 1]->name);
784 if (!rgBstrNames[0]) return E_OUTOFMEMORY;
785 i++;
788 *pcNames = i;
789 return S_OK;
792 static HRESULT WINAPI ScriptTypeInfo_GetRefTypeOfImplType(ITypeInfo *iface, UINT index, HREFTYPE *pRefType)
794 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
796 TRACE("(%p)->(%u %p)\n", This, index, pRefType);
798 /* We only inherit from IDispatch */
799 if (!pRefType) return E_INVALIDARG;
800 if (index != 0) return TYPE_E_ELEMENTNOTFOUND;
802 *pRefType = 1;
803 return S_OK;
806 static HRESULT WINAPI ScriptTypeInfo_GetImplTypeFlags(ITypeInfo *iface, UINT index, INT *pImplTypeFlags)
808 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
810 TRACE("(%p)->(%u %p)\n", This, index, pImplTypeFlags);
812 if (!pImplTypeFlags) return E_INVALIDARG;
813 if (index != 0) return TYPE_E_ELEMENTNOTFOUND;
815 *pImplTypeFlags = 0;
816 return S_OK;
819 static HRESULT WINAPI ScriptTypeInfo_GetIDsOfNames(ITypeInfo *iface, LPOLESTR *rgszNames, UINT cNames,
820 MEMBERID *pMemId)
822 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
823 ITypeInfo *disp_typeinfo;
824 const WCHAR *name;
825 HRESULT hr = S_OK;
826 int i, j, arg;
828 TRACE("(%p)->(%p %u %p)\n", This, rgszNames, cNames, pMemId);
830 if (!rgszNames || !cNames || !pMemId) return E_INVALIDARG;
832 for (i = 0; i < cNames; i++) pMemId[i] = MEMBERID_NIL;
833 name = rgszNames[0];
835 for (i = 0; i < This->num_funcs; i++)
837 function_t *func = This->funcs[i].func;
839 if (wcsicmp(name, func->name)) continue;
840 pMemId[0] = This->funcs[i].memid;
842 for (j = 1; j < cNames; j++)
844 name = rgszNames[j];
845 for (arg = func->arg_cnt; --arg >= 0;)
846 if (!wcsicmp(name, func->args[arg].name))
847 break;
848 if (arg >= 0)
849 pMemId[j] = arg;
850 else
851 hr = DISP_E_UNKNOWNNAME;
853 return hr;
856 for (i = 0; i < This->num_vars; i++)
858 if (wcsicmp(name, This->disp->global_vars[i]->name)) continue;
859 pMemId[0] = i + 1;
860 return S_OK;
863 /* Look into the inherited IDispatch */
864 hr = get_dispatch_typeinfo(&disp_typeinfo);
865 if (FAILED(hr)) return hr;
867 return ITypeInfo_GetIDsOfNames(disp_typeinfo, rgszNames, cNames, pMemId);
870 static HRESULT WINAPI ScriptTypeInfo_Invoke(ITypeInfo *iface, PVOID pvInstance, MEMBERID memid, WORD wFlags,
871 DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
873 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
874 ITypeInfo *disp_typeinfo;
875 IDispatch *disp;
876 HRESULT hr;
878 TRACE("(%p)->(%p %ld %d %p %p %p %p)\n", This, pvInstance, memid, wFlags,
879 pDispParams, pVarResult, pExcepInfo, puArgErr);
881 if (!pvInstance) return E_INVALIDARG;
882 if (memid <= 0) return TYPE_E_ELEMENTNOTFOUND;
884 if (!get_func_from_memid(This, memid) && memid > This->num_vars)
886 hr = get_dispatch_typeinfo(&disp_typeinfo);
887 if (FAILED(hr)) return hr;
889 return ITypeInfo_Invoke(disp_typeinfo, pvInstance, memid, wFlags, pDispParams,
890 pVarResult, pExcepInfo, puArgErr);
893 hr = IUnknown_QueryInterface((IUnknown*)pvInstance, &IID_IDispatch, (void**)&disp);
894 if (FAILED(hr)) return hr;
896 hr = IDispatch_Invoke(disp, memid, &IID_NULL, LOCALE_USER_DEFAULT, wFlags,
897 pDispParams, pVarResult, pExcepInfo, puArgErr);
898 IDispatch_Release(disp);
900 return hr;
903 static HRESULT WINAPI ScriptTypeInfo_GetDocumentation(ITypeInfo *iface, MEMBERID memid, BSTR *pBstrName,
904 BSTR *pBstrDocString, DWORD *pdwHelpContext, BSTR *pBstrHelpFile)
906 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
907 ITypeInfo *disp_typeinfo;
908 function_t *func;
909 HRESULT hr;
911 TRACE("(%p)->(%ld %p %p %p %p)\n", This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile);
913 if (pBstrDocString) *pBstrDocString = NULL;
914 if (pdwHelpContext) *pdwHelpContext = 0;
915 if (pBstrHelpFile) *pBstrHelpFile = NULL;
917 if (memid == MEMBERID_NIL)
919 if (pBstrName && !(*pBstrName = SysAllocString(L"VBScriptTypeInfo")))
920 return E_OUTOFMEMORY;
921 if (pBstrDocString &&
922 !(*pBstrDocString = SysAllocString(L"Visual Basic Scripting Type Info")))
924 if (pBstrName) SysFreeString(*pBstrName);
925 return E_OUTOFMEMORY;
927 return S_OK;
929 if (memid <= 0) return TYPE_E_ELEMENTNOTFOUND;
931 func = get_func_from_memid(This, memid);
932 if (!func && memid > This->num_vars)
934 hr = get_dispatch_typeinfo(&disp_typeinfo);
935 if (FAILED(hr)) return hr;
937 return ITypeInfo_GetDocumentation(disp_typeinfo, memid, pBstrName, pBstrDocString,
938 pdwHelpContext, pBstrHelpFile);
941 if (pBstrName)
943 *pBstrName = SysAllocString(func ? func->name : This->disp->global_vars[memid - 1]->name);
944 if (!*pBstrName) return E_OUTOFMEMORY;
946 return S_OK;
949 static HRESULT WINAPI ScriptTypeInfo_GetDllEntry(ITypeInfo *iface, MEMBERID memid, INVOKEKIND invKind,
950 BSTR *pBstrDllName, BSTR *pBstrName, WORD *pwOrdinal)
952 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
953 ITypeInfo *disp_typeinfo;
954 HRESULT hr;
956 TRACE("(%p)->(%ld %d %p %p %p)\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
958 if (pBstrDllName) *pBstrDllName = NULL;
959 if (pBstrName) *pBstrName = NULL;
960 if (pwOrdinal) *pwOrdinal = 0;
962 if (!get_func_from_memid(This, memid) && memid > This->num_vars)
964 hr = get_dispatch_typeinfo(&disp_typeinfo);
965 if (FAILED(hr)) return hr;
967 return ITypeInfo_GetDllEntry(disp_typeinfo, memid, invKind, pBstrDllName, pBstrName, pwOrdinal);
969 return TYPE_E_BADMODULEKIND;
972 static HRESULT WINAPI ScriptTypeInfo_GetRefTypeInfo(ITypeInfo *iface, HREFTYPE hRefType, ITypeInfo **ppTInfo)
974 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
975 HRESULT hr;
977 TRACE("(%p)->(%lx %p)\n", This, hRefType, ppTInfo);
979 if (!ppTInfo || (INT)hRefType < 0) return E_INVALIDARG;
981 if (hRefType & ~3) return E_FAIL;
982 if (hRefType & 1)
984 hr = get_dispatch_typeinfo(ppTInfo);
985 if (FAILED(hr)) return hr;
987 else
988 *ppTInfo = iface;
990 ITypeInfo_AddRef(*ppTInfo);
991 return S_OK;
994 static HRESULT WINAPI ScriptTypeInfo_AddressOfMember(ITypeInfo *iface, MEMBERID memid, INVOKEKIND invKind, PVOID *ppv)
996 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
997 ITypeInfo *disp_typeinfo;
998 HRESULT hr;
1000 TRACE("(%p)->(%ld %d %p)\n", This, memid, invKind, ppv);
1002 if (!ppv) return E_INVALIDARG;
1003 *ppv = NULL;
1005 if (!get_func_from_memid(This, memid) && memid > This->num_vars)
1007 hr = get_dispatch_typeinfo(&disp_typeinfo);
1008 if (FAILED(hr)) return hr;
1010 return ITypeInfo_AddressOfMember(disp_typeinfo, memid, invKind, ppv);
1012 return TYPE_E_BADMODULEKIND;
1015 static HRESULT WINAPI ScriptTypeInfo_CreateInstance(ITypeInfo *iface, IUnknown *pUnkOuter, REFIID riid, PVOID *ppvObj)
1017 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1019 TRACE("(%p)->(%p %s %p)\n", This, pUnkOuter, debugstr_guid(riid), ppvObj);
1021 if (!ppvObj) return E_INVALIDARG;
1023 *ppvObj = NULL;
1024 return TYPE_E_BADMODULEKIND;
1027 static HRESULT WINAPI ScriptTypeInfo_GetMops(ITypeInfo *iface, MEMBERID memid, BSTR *pBstrMops)
1029 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1030 ITypeInfo *disp_typeinfo;
1031 HRESULT hr;
1033 TRACE("(%p)->(%ld %p)\n", This, memid, pBstrMops);
1035 if (!pBstrMops) return E_INVALIDARG;
1037 if (!get_func_from_memid(This, memid) && memid > This->num_vars)
1039 hr = get_dispatch_typeinfo(&disp_typeinfo);
1040 if (FAILED(hr)) return hr;
1042 return ITypeInfo_GetMops(disp_typeinfo, memid, pBstrMops);
1045 *pBstrMops = NULL;
1046 return S_OK;
1049 static HRESULT WINAPI ScriptTypeInfo_GetContainingTypeLib(ITypeInfo *iface, ITypeLib **ppTLib, UINT *pIndex)
1051 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1053 FIXME("(%p)->(%p %p)\n", This, ppTLib, pIndex);
1055 return E_NOTIMPL;
1058 static void WINAPI ScriptTypeInfo_ReleaseTypeAttr(ITypeInfo *iface, TYPEATTR *pTypeAttr)
1060 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1062 TRACE("(%p)->(%p)\n", This, pTypeAttr);
1064 heap_free(pTypeAttr);
1067 static void WINAPI ScriptTypeInfo_ReleaseFuncDesc(ITypeInfo *iface, FUNCDESC *pFuncDesc)
1069 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1071 TRACE("(%p)->(%p)\n", This, pFuncDesc);
1073 heap_free(pFuncDesc);
1076 static void WINAPI ScriptTypeInfo_ReleaseVarDesc(ITypeInfo *iface, VARDESC *pVarDesc)
1078 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeInfo(iface);
1080 TRACE("(%p)->(%p)\n", This, pVarDesc);
1082 heap_free(pVarDesc);
1085 static const ITypeInfoVtbl ScriptTypeInfoVtbl = {
1086 ScriptTypeInfo_QueryInterface,
1087 ScriptTypeInfo_AddRef,
1088 ScriptTypeInfo_Release,
1089 ScriptTypeInfo_GetTypeAttr,
1090 ScriptTypeInfo_GetTypeComp,
1091 ScriptTypeInfo_GetFuncDesc,
1092 ScriptTypeInfo_GetVarDesc,
1093 ScriptTypeInfo_GetNames,
1094 ScriptTypeInfo_GetRefTypeOfImplType,
1095 ScriptTypeInfo_GetImplTypeFlags,
1096 ScriptTypeInfo_GetIDsOfNames,
1097 ScriptTypeInfo_Invoke,
1098 ScriptTypeInfo_GetDocumentation,
1099 ScriptTypeInfo_GetDllEntry,
1100 ScriptTypeInfo_GetRefTypeInfo,
1101 ScriptTypeInfo_AddressOfMember,
1102 ScriptTypeInfo_CreateInstance,
1103 ScriptTypeInfo_GetMops,
1104 ScriptTypeInfo_GetContainingTypeLib,
1105 ScriptTypeInfo_ReleaseTypeAttr,
1106 ScriptTypeInfo_ReleaseFuncDesc,
1107 ScriptTypeInfo_ReleaseVarDesc
1110 static HRESULT WINAPI ScriptTypeComp_QueryInterface(ITypeComp *iface, REFIID riid, void **ppv)
1112 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1113 return ITypeInfo_QueryInterface(&This->ITypeInfo_iface, riid, ppv);
1116 static ULONG WINAPI ScriptTypeComp_AddRef(ITypeComp *iface)
1118 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1119 return ITypeInfo_AddRef(&This->ITypeInfo_iface);
1122 static ULONG WINAPI ScriptTypeComp_Release(ITypeComp *iface)
1124 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1125 return ITypeInfo_Release(&This->ITypeInfo_iface);
1128 static HRESULT WINAPI ScriptTypeComp_Bind(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal, WORD wFlags,
1129 ITypeInfo **ppTInfo, DESCKIND *pDescKind, BINDPTR *pBindPtr)
1131 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1132 UINT flags = wFlags ? wFlags : ~0;
1133 ITypeInfo *disp_typeinfo;
1134 ITypeComp *disp_typecomp;
1135 HRESULT hr;
1136 UINT i;
1138 TRACE("(%p)->(%s %08lx %d %p %p %p)\n", This, debugstr_w(szName), lHashVal,
1139 wFlags, ppTInfo, pDescKind, pBindPtr);
1141 if (!szName || !ppTInfo || !pDescKind || !pBindPtr)
1142 return E_INVALIDARG;
1144 for (i = 0; i < This->num_funcs; i++)
1146 if (wcsicmp(szName, This->funcs[i].func->name)) continue;
1147 if (!(flags & INVOKE_FUNC)) return TYPE_E_TYPEMISMATCH;
1149 hr = ITypeInfo_GetFuncDesc(&This->ITypeInfo_iface, i, &pBindPtr->lpfuncdesc);
1150 if (FAILED(hr)) return hr;
1152 *pDescKind = DESCKIND_FUNCDESC;
1153 *ppTInfo = &This->ITypeInfo_iface;
1154 ITypeInfo_AddRef(*ppTInfo);
1155 return S_OK;
1158 for (i = 0; i < This->num_vars; i++)
1160 if (wcsicmp(szName, This->disp->global_vars[i]->name)) continue;
1161 if (!(flags & INVOKE_PROPERTYGET)) return TYPE_E_TYPEMISMATCH;
1163 hr = ITypeInfo_GetVarDesc(&This->ITypeInfo_iface, i, &pBindPtr->lpvardesc);
1164 if (FAILED(hr)) return hr;
1166 *pDescKind = DESCKIND_VARDESC;
1167 *ppTInfo = &This->ITypeInfo_iface;
1168 ITypeInfo_AddRef(*ppTInfo);
1169 return S_OK;
1172 /* Look into the inherited IDispatch */
1173 hr = get_dispatch_typeinfo(&disp_typeinfo);
1174 if (FAILED(hr)) return hr;
1176 hr = ITypeInfo_GetTypeComp(disp_typeinfo, &disp_typecomp);
1177 if (FAILED(hr)) return hr;
1179 hr = ITypeComp_Bind(disp_typecomp, szName, lHashVal, wFlags, ppTInfo, pDescKind, pBindPtr);
1180 ITypeComp_Release(disp_typecomp);
1181 return hr;
1184 static HRESULT WINAPI ScriptTypeComp_BindType(ITypeComp *iface, LPOLESTR szName, ULONG lHashVal,
1185 ITypeInfo **ppTInfo, ITypeComp **ppTComp)
1187 ScriptTypeInfo *This = ScriptTypeInfo_from_ITypeComp(iface);
1188 ITypeInfo *disp_typeinfo;
1189 ITypeComp *disp_typecomp;
1190 HRESULT hr;
1192 TRACE("(%p)->(%s %08lx %p %p)\n", This, debugstr_w(szName), lHashVal, ppTInfo, ppTComp);
1194 if (!szName || !ppTInfo || !ppTComp)
1195 return E_INVALIDARG;
1197 /* Look into the inherited IDispatch */
1198 hr = get_dispatch_typeinfo(&disp_typeinfo);
1199 if (FAILED(hr)) return hr;
1201 hr = ITypeInfo_GetTypeComp(disp_typeinfo, &disp_typecomp);
1202 if (FAILED(hr)) return hr;
1204 hr = ITypeComp_BindType(disp_typecomp, szName, lHashVal, ppTInfo, ppTComp);
1205 ITypeComp_Release(disp_typecomp);
1206 return hr;
1209 static const ITypeCompVtbl ScriptTypeCompVtbl = {
1210 ScriptTypeComp_QueryInterface,
1211 ScriptTypeComp_AddRef,
1212 ScriptTypeComp_Release,
1213 ScriptTypeComp_Bind,
1214 ScriptTypeComp_BindType
1217 static inline ScriptDisp *ScriptDisp_from_IDispatchEx(IDispatchEx *iface)
1219 return CONTAINING_RECORD(iface, ScriptDisp, IDispatchEx_iface);
1222 static HRESULT WINAPI ScriptDisp_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
1224 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
1226 if(IsEqualGUID(&IID_IUnknown, riid)) {
1227 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
1228 *ppv = &This->IDispatchEx_iface;
1229 }else if(IsEqualGUID(&IID_IDispatch, riid)) {
1230 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
1231 *ppv = &This->IDispatchEx_iface;
1232 }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
1233 TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
1234 *ppv = &This->IDispatchEx_iface;
1235 }else {
1236 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
1237 *ppv = NULL;
1238 return E_NOINTERFACE;
1241 IUnknown_AddRef((IUnknown*)*ppv);
1242 return S_OK;
1245 static ULONG WINAPI ScriptDisp_AddRef(IDispatchEx *iface)
1247 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
1248 LONG ref = InterlockedIncrement(&This->ref);
1250 TRACE("(%p) ref=%ld\n", This, ref);
1252 return ref;
1255 static ULONG WINAPI ScriptDisp_Release(IDispatchEx *iface)
1257 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
1258 LONG ref = InterlockedDecrement(&This->ref);
1259 unsigned i;
1261 TRACE("(%p) ref=%ld\n", This, ref);
1263 if(!ref) {
1264 assert(!This->ctx);
1266 for (i = 0; i < This->global_vars_cnt; i++)
1267 release_dynamic_var(This->global_vars[i]);
1269 heap_pool_free(&This->heap);
1270 heap_free(This->global_vars);
1271 heap_free(This->global_funcs);
1272 heap_free(This);
1275 return ref;
1278 static HRESULT WINAPI ScriptDisp_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
1280 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
1282 TRACE("(%p)->(%p)\n", This, pctinfo);
1284 *pctinfo = 1;
1285 return S_OK;
1288 static HRESULT WINAPI ScriptDisp_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid, ITypeInfo **ret)
1290 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
1291 ScriptTypeInfo *type_info;
1292 UINT num_funcs = 0;
1293 unsigned i, j;
1295 TRACE("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ret);
1297 if(iTInfo)
1298 return DISP_E_BADINDEX;
1300 if(!(type_info = heap_alloc(sizeof(*type_info))))
1301 return E_OUTOFMEMORY;
1303 for(i = 0; i < This->global_funcs_cnt; i++)
1304 if(This->global_funcs[i]->is_public)
1305 num_funcs++;
1307 type_info->ITypeInfo_iface.lpVtbl = &ScriptTypeInfoVtbl;
1308 type_info->ITypeComp_iface.lpVtbl = &ScriptTypeCompVtbl;
1309 type_info->ref = 1;
1310 type_info->num_funcs = num_funcs;
1311 type_info->num_vars = This->global_vars_cnt;
1312 type_info->disp = This;
1314 type_info->funcs = heap_alloc(sizeof(*type_info->funcs) * num_funcs);
1315 if(!type_info->funcs)
1317 heap_free(type_info);
1318 return E_OUTOFMEMORY;
1321 for(j = 0, i = 0; i < This->global_funcs_cnt; i++)
1323 if(!This->global_funcs[i]->is_public) continue;
1325 type_info->funcs[j].memid = i + 1 + DISPID_FUNCTION_MASK;
1326 type_info->funcs[j].func = This->global_funcs[i];
1327 grab_vbscode(This->global_funcs[i]->code_ctx);
1328 j++;
1331 IDispatchEx_AddRef(&This->IDispatchEx_iface);
1333 *ret = &type_info->ITypeInfo_iface;
1334 return S_OK;
1337 static HRESULT WINAPI ScriptDisp_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
1338 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1340 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
1341 UINT i;
1342 HRESULT hres;
1344 TRACE("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
1345 lcid, rgDispId);
1347 if(cNames == 0)
1348 return S_OK;
1350 hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[0], 0, rgDispId);
1351 if(FAILED(hres))
1352 return hres;
1354 /* DISPIDs for parameters don't seem to be supported */
1355 if(cNames > 1) {
1356 for(i = 1; i < cNames; i++)
1357 rgDispId[i] = DISPID_UNKNOWN;
1358 hres = DISP_E_UNKNOWNNAME;
1361 return hres;
1364 static HRESULT WINAPI ScriptDisp_Invoke(IDispatchEx *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
1365 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1367 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
1369 TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1370 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1372 return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags,
1373 pDispParams, pVarResult, pExcepInfo, NULL);
1376 static HRESULT WINAPI ScriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
1378 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
1379 unsigned i;
1381 TRACE("(%p)->(%s %lx %p)\n", This, debugstr_w(bstrName), grfdex, pid);
1383 if(!This->ctx)
1384 return E_UNEXPECTED;
1386 for(i = 0; i < This->global_vars_cnt; i++) {
1387 if(!wcsicmp(This->global_vars[i]->name, bstrName)) {
1388 *pid = i + 1;
1389 return S_OK;
1393 for(i = 0; i < This->global_funcs_cnt; i++) {
1394 if(!wcsicmp(This->global_funcs[i]->name, bstrName)) {
1395 *pid = i + 1 + DISPID_FUNCTION_MASK;
1396 return S_OK;
1400 *pid = -1;
1401 return DISP_E_UNKNOWNNAME;
1404 static HRESULT WINAPI ScriptDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
1405 VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
1407 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
1408 HRESULT hres;
1410 TRACE("(%p)->(%lx %lx %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
1412 if (!This->ctx)
1413 return E_UNEXPECTED;
1415 if (id & DISPID_FUNCTION_MASK)
1417 id &= ~DISPID_FUNCTION_MASK;
1418 if (id > This->global_funcs_cnt)
1419 return DISP_E_MEMBERNOTFOUND;
1421 switch (wFlags)
1423 case DISPATCH_METHOD:
1424 case DISPATCH_METHOD | DISPATCH_PROPERTYGET:
1425 hres = exec_script(This->ctx, TRUE, This->global_funcs[id - 1], NULL, pdp, pvarRes);
1426 break;
1427 default:
1428 FIXME("Unsupported flags %x\n", wFlags);
1429 hres = E_NOTIMPL;
1432 return hres;
1435 if (id > This->global_vars_cnt)
1436 return DISP_E_MEMBERNOTFOUND;
1438 if (This->global_vars[id - 1]->is_const)
1440 FIXME("const not supported\n");
1441 return E_NOTIMPL;
1444 return invoke_variant_prop(This->ctx, &This->global_vars[id - 1]->v, wFlags, pdp, pvarRes);
1447 static HRESULT WINAPI ScriptDisp_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
1449 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
1450 FIXME("(%p)->(%s %lx)\n", This, debugstr_w(bstrName), grfdex);
1451 return E_NOTIMPL;
1454 static HRESULT WINAPI ScriptDisp_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
1456 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
1457 FIXME("(%p)->(%lx)\n", This, id);
1458 return E_NOTIMPL;
1461 static HRESULT WINAPI ScriptDisp_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
1463 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
1464 FIXME("(%p)->(%lx %lx %p)\n", This, id, grfdexFetch, pgrfdex);
1465 return E_NOTIMPL;
1468 static HRESULT WINAPI ScriptDisp_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
1470 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
1471 FIXME("(%p)->(%lx %p)\n", This, id, pbstrName);
1472 return E_NOTIMPL;
1475 static HRESULT WINAPI ScriptDisp_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
1477 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
1478 FIXME("(%p)->(%lx %lx %p)\n", This, grfdex, id, pid);
1479 return E_NOTIMPL;
1482 static HRESULT WINAPI ScriptDisp_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
1484 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
1485 FIXME("(%p)->(%p)\n", This, ppunk);
1486 return E_NOTIMPL;
1489 static IDispatchExVtbl ScriptDispVtbl = {
1490 ScriptDisp_QueryInterface,
1491 ScriptDisp_AddRef,
1492 ScriptDisp_Release,
1493 ScriptDisp_GetTypeInfoCount,
1494 ScriptDisp_GetTypeInfo,
1495 ScriptDisp_GetIDsOfNames,
1496 ScriptDisp_Invoke,
1497 ScriptDisp_GetDispID,
1498 ScriptDisp_InvokeEx,
1499 ScriptDisp_DeleteMemberByName,
1500 ScriptDisp_DeleteMemberByDispID,
1501 ScriptDisp_GetMemberProperties,
1502 ScriptDisp_GetMemberName,
1503 ScriptDisp_GetNextDispID,
1504 ScriptDisp_GetNameSpaceParent
1507 HRESULT create_script_disp(script_ctx_t *ctx, ScriptDisp **ret)
1509 ScriptDisp *script_disp;
1511 script_disp = heap_alloc_zero(sizeof(*script_disp));
1512 if(!script_disp)
1513 return E_OUTOFMEMORY;
1515 script_disp->IDispatchEx_iface.lpVtbl = &ScriptDispVtbl;
1516 script_disp->ref = 1;
1517 script_disp->ctx = ctx;
1518 heap_pool_init(&script_disp->heap);
1520 *ret = script_disp;
1521 return S_OK;
1524 void collect_objects(script_ctx_t *ctx)
1526 vbdisp_t *iter, *iter2;
1528 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &ctx->objects, vbdisp_t, entry)
1529 run_terminator(iter);
1531 while(!list_empty(&ctx->objects)) {
1532 iter = LIST_ENTRY(list_head(&ctx->objects), vbdisp_t, entry);
1534 IDispatchEx_AddRef(&iter->IDispatchEx_iface);
1535 clean_props(iter);
1536 iter->desc = NULL;
1537 list_remove(&iter->entry);
1538 list_init(&iter->entry);
1539 IDispatchEx_Release(&iter->IDispatchEx_iface);
1543 HRESULT disp_get_id(IDispatch *disp, BSTR name, vbdisp_invoke_type_t invoke_type, BOOL search_private, DISPID *id)
1545 IDispatchEx *dispex;
1546 vbdisp_t *vbdisp;
1547 HRESULT hres;
1549 vbdisp = unsafe_impl_from_IDispatch(disp);
1550 if(vbdisp)
1551 return vbdisp_get_id(vbdisp, name, invoke_type, search_private, id);
1553 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1554 if(FAILED(hres)) {
1555 TRACE("using IDispatch\n");
1556 return IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, id);
1559 hres = IDispatchEx_GetDispID(dispex, name, fdexNameCaseInsensitive, id);
1560 IDispatchEx_Release(dispex);
1561 return hres;
1564 #define RPC_E_SERVER_UNAVAILABLE 0x800706ba
1566 void map_vbs_exception(EXCEPINFO *ei)
1568 int vbse_number;
1570 if(HRESULT_FACILITY(ei->scode) == FACILITY_VBS)
1571 vbse_number = HRESULT_CODE(ei->scode);
1572 else
1574 switch(ei->scode) {
1575 case E_NOTIMPL: vbse_number = VBSE_ACTION_NOT_SUPPORTED; break;
1576 case E_NOINTERFACE: vbse_number = VBSE_OLE_NOT_SUPPORTED; break;
1577 case DISP_E_UNKNOWNINTERFACE: vbse_number = VBSE_OLE_NO_PROP_OR_METHOD; break;
1578 case DISP_E_MEMBERNOTFOUND: vbse_number = VBSE_OLE_NO_PROP_OR_METHOD; break;
1579 case DISP_E_PARAMNOTFOUND: vbse_number = VBSE_NAMED_PARAM_NOT_FOUND; break;
1580 case DISP_E_TYPEMISMATCH: vbse_number = VBSE_TYPE_MISMATCH; break;
1581 case DISP_E_UNKNOWNNAME: vbse_number = VBSE_OLE_NO_PROP_OR_METHOD; break;
1582 case DISP_E_NONAMEDARGS: vbse_number = VBSE_NAMED_ARGS_NOT_SUPPORTED; break;
1583 case DISP_E_BADVARTYPE: vbse_number = VBSE_INVALID_TYPELIB_VARIABLE; break;
1584 case DISP_E_OVERFLOW: vbse_number = VBSE_OVERFLOW; break;
1585 case DISP_E_BADINDEX: vbse_number = VBSE_OUT_OF_BOUNDS; break;
1586 case DISP_E_UNKNOWNLCID: vbse_number = VBSE_LOCALE_SETTING_NOT_SUPPORTED; break;
1587 case DISP_E_ARRAYISLOCKED: vbse_number = VBSE_ARRAY_LOCKED; break;
1588 case DISP_E_BADPARAMCOUNT: vbse_number = VBSE_FUNC_ARITY_MISMATCH; break;
1589 case DISP_E_PARAMNOTOPTIONAL: vbse_number = VBSE_PARAMETER_NOT_OPTIONAL; break;
1590 case DISP_E_NOTACOLLECTION: vbse_number = VBSE_NOT_ENUM; break;
1591 case TYPE_E_DLLFUNCTIONNOTFOUND: vbse_number = VBSE_INVALID_DLL_FUNCTION_NAME; break;
1592 case TYPE_E_TYPEMISMATCH: vbse_number = VBSE_TYPE_MISMATCH; break;
1593 case TYPE_E_OUTOFBOUNDS: vbse_number = VBSE_OUT_OF_BOUNDS; break;
1594 case TYPE_E_IOERROR: vbse_number = VBSE_IO_ERROR; break;
1595 case TYPE_E_CANTCREATETMPFILE: vbse_number = VBSE_CANT_CREATE_TMP_FILE; break;
1596 case STG_E_FILENOTFOUND: vbse_number = VBSE_OLE_FILE_NOT_FOUND; break;
1597 case STG_E_PATHNOTFOUND: vbse_number = VBSE_PATH_NOT_FOUND; break;
1598 case STG_E_TOOMANYOPENFILES: vbse_number = VBSE_TOO_MANY_FILES; break;
1599 case STG_E_ACCESSDENIED: vbse_number = VBSE_PERMISSION_DENIED; break;
1600 case STG_E_INSUFFICIENTMEMORY: vbse_number = VBSE_OUT_OF_MEMORY; break;
1601 case STG_E_NOMOREFILES: vbse_number = VBSE_TOO_MANY_FILES; break;
1602 case STG_E_DISKISWRITEPROTECTED: vbse_number = VBSE_PERMISSION_DENIED; break;
1603 case STG_E_WRITEFAULT: vbse_number = VBSE_IO_ERROR; break;
1604 case STG_E_READFAULT: vbse_number = VBSE_IO_ERROR; break;
1605 case STG_E_SHAREVIOLATION: vbse_number = VBSE_PATH_FILE_ACCESS; break;
1606 case STG_E_LOCKVIOLATION: vbse_number = VBSE_PERMISSION_DENIED; break;
1607 case STG_E_FILEALREADYEXISTS: vbse_number = VBSE_FILE_ALREADY_EXISTS; break;
1608 case STG_E_MEDIUMFULL: vbse_number = VBSE_DISK_FULL; break;
1609 case STG_E_INVALIDNAME: vbse_number = VBSE_FILE_NOT_FOUND; break;
1610 case STG_E_INUSE: vbse_number = VBSE_PERMISSION_DENIED; break;
1611 case STG_E_NOTCURRENT: vbse_number = VBSE_PERMISSION_DENIED; break;
1612 case STG_E_CANTSAVE: vbse_number = VBSE_IO_ERROR; break;
1613 case REGDB_E_CLASSNOTREG: vbse_number = VBSE_CANT_CREATE_OBJECT; break;
1614 case MK_E_UNAVAILABLE: vbse_number = VBSE_CANT_CREATE_OBJECT; break;
1615 case MK_E_INVALIDEXTENSION: vbse_number = VBSE_OLE_FILE_NOT_FOUND; break;
1616 case MK_E_CANTOPENFILE: vbse_number = VBSE_OLE_FILE_NOT_FOUND; break;
1617 case CO_E_CLASSSTRING: vbse_number = VBSE_CANT_CREATE_OBJECT; break;
1618 case CO_E_APPNOTFOUND: vbse_number = VBSE_CANT_CREATE_OBJECT; break;
1619 case CO_E_APPDIDNTREG: vbse_number = VBSE_CANT_CREATE_OBJECT; break;
1620 case E_ACCESSDENIED: vbse_number = VBSE_PERMISSION_DENIED; break;
1621 case E_OUTOFMEMORY: vbse_number = VBSE_OUT_OF_MEMORY; break;
1622 case E_INVALIDARG: vbse_number = VBSE_ILLEGAL_FUNC_CALL; break;
1623 case RPC_E_SERVER_UNAVAILABLE: vbse_number = VBSE_SERVER_NOT_FOUND; break;
1624 case CO_E_SERVER_EXEC_FAILURE: vbse_number = VBSE_CANT_CREATE_OBJECT; break;
1625 default: return; /* early return, all other HRESULT left as-is */
1627 ei->scode = MAKE_VBSERROR(vbse_number);
1629 if(!ei->bstrSource)
1630 ei->bstrSource = get_vbscript_string(VBS_RUNTIME_ERROR);
1631 if(!ei->bstrDescription)
1632 if(!(ei->bstrDescription = get_vbscript_string(vbse_number)))
1633 ei->bstrDescription = get_vbscript_string(VBS_UNKNOWN_RUNTIME_ERROR);
1636 HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, DISPPARAMS *dp, VARIANT *retv)
1638 const WORD flags = DISPATCH_METHOD|(retv ? DISPATCH_PROPERTYGET : 0);
1639 IDispatchEx *dispex;
1640 vbdisp_t *vbdisp;
1641 EXCEPINFO ei;
1642 HRESULT hres;
1644 memset(&ei, 0, sizeof(ei));
1645 if(retv)
1646 V_VT(retv) = VT_EMPTY;
1648 vbdisp = unsafe_impl_from_IDispatch(disp);
1649 if(vbdisp && vbdisp->desc && vbdisp->desc->ctx == ctx)
1650 return invoke_vbdisp(vbdisp, id, flags, FALSE, dp, retv);
1652 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1653 if(SUCCEEDED(hres)) {
1654 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, dp, retv, &ei, NULL /* CALLER_FIXME */);
1655 IDispatchEx_Release(dispex);
1656 }else {
1657 UINT err = 0;
1659 TRACE("using IDispatch\n");
1660 hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, dp, retv, &ei, &err);
1663 if(hres == DISP_E_EXCEPTION) {
1664 clear_ei(&ctx->ei);
1665 ctx->ei = ei;
1666 hres = SCRIPT_E_RECORDED;
1668 return hres;
1671 HRESULT get_disp_value(script_ctx_t *ctx, IDispatch *disp, VARIANT *v)
1673 DISPPARAMS dp = {NULL};
1674 if(!disp)
1675 return MAKE_VBSERROR(VBSE_OBJECT_VARIABLE_NOT_SET);
1676 return disp_call(ctx, disp, DISPID_VALUE, &dp, v);
1679 HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, DISPPARAMS *dp)
1681 IDispatchEx *dispex;
1682 vbdisp_t *vbdisp;
1683 EXCEPINFO ei = {0};
1684 HRESULT hres;
1686 vbdisp = unsafe_impl_from_IDispatch(disp);
1687 if(vbdisp && vbdisp->desc && vbdisp->desc->ctx == ctx)
1688 return invoke_vbdisp(vbdisp, id, flags, FALSE, dp, NULL);
1690 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
1691 if(SUCCEEDED(hres)) {
1692 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, dp, NULL, &ei, NULL /* FIXME! */);
1693 IDispatchEx_Release(dispex);
1694 }else {
1695 UINT err = 0;
1697 TRACE("using IDispatch\n");
1698 hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, dp, NULL, &ei, &err);
1701 if(hres == DISP_E_EXCEPTION) {
1702 clear_ei(&ctx->ei);
1703 ctx->ei = ei;
1704 hres = SCRIPT_E_RECORDED;
1706 return hres;