1 /*
2 * Copyright 2011 Jacek Caban for CodeWeavers
3 *
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.
8 *
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.
13 *
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
17 */
18
19 #include <assert.h>
20
21 #include "vbscript.h"
22
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
26
27 #define FDEX_VERSION_MASK 0xf0000000
28
is_func_id(vbdisp_t * This,DISPID id)29 static inline BOOL is_func_id(vbdisp_t *This, DISPID id)
30 {
31 return id < This->desc->func_cnt;
32 }
33
get_func_id(vbdisp_t * This,const WCHAR * name,vbdisp_invoke_type_t invoke_type,BOOL search_private,DISPID * id)34 static BOOL get_func_id(vbdisp_t *This, const WCHAR *name, vbdisp_invoke_type_t invoke_type, BOOL search_private, DISPID *id)
35 {
36 unsigned i;
37
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;
48 }
49
50 if(!wcsicmp(This->desc->funcs[i].name, name)) {
51 *id = i;
52 return TRUE;
53 }
54 }
55
56 return FALSE;
57 }
58
vbdisp_get_id(vbdisp_t * This,BSTR name,vbdisp_invoke_type_t invoke_type,BOOL search_private,DISPID * id)59 HRESULT vbdisp_get_id(vbdisp_t *This, BSTR name, vbdisp_invoke_type_t invoke_type, BOOL search_private, DISPID *id)
60 {
61 unsigned i;
62
63 if(get_func_id(This, name, invoke_type, search_private, id))
64 return S_OK;
65
66 for(i=0; i < This->desc->prop_cnt; i++) {
67 if(!search_private && !This->desc->props[i].is_public)
68 continue;
69
70 if(!wcsicmp(This->desc->props[i].name, name)) {
71 *id = i + This->desc->func_cnt;
72 return S_OK;
73 }
74 }
75
76 *id = -1;
77 return DISP_E_UNKNOWNNAME;
78 }
79
get_propput_arg(script_ctx_t * ctx,const DISPPARAMS * dp,WORD flags,VARIANT * v,BOOL * is_owned)80 static HRESULT get_propput_arg(script_ctx_t *ctx, const DISPPARAMS *dp, WORD flags, VARIANT *v, BOOL *is_owned)
81 {
82 unsigned i;
83
84 for(i=0; i < dp->cNamedArgs; i++) {
85 if(dp->rgdispidNamedArgs[i] == DISPID_PROPERTYPUT)
86 break;
87 }
88 if(i == dp->cNamedArgs) {
89 WARN("no value to set\n");
90 return DISP_E_PARAMNOTOPTIONAL;
91 }
92
93 *v = dp->rgvarg[i];
94 if(V_VT(v) == (VT_VARIANT|VT_BYREF))
95 *v = *V_VARIANTREF(v);
96 *is_owned = FALSE;
97
98 if(V_VT(v) == VT_DISPATCH) {
99 if(!(flags & DISPATCH_PROPERTYPUTREF)) {
100 HRESULT hres;
101
102 hres = get_disp_value(ctx, V_DISPATCH(v), v);
103 if(FAILED(hres))
104 return hres;
105
106 *is_owned = TRUE;
107 }
108 }else if(!(flags & DISPATCH_PROPERTYPUT)) {
109 WARN("%s can't be assigned without DISPATCH_PROPERTYPUT flag\n", debugstr_variant(v));
110 return DISP_E_EXCEPTION;
111 }
112
113 return S_OK;
114 }
115
invoke_variant_prop(script_ctx_t * ctx,VARIANT * v,WORD flags,DISPPARAMS * dp,VARIANT * res)116 static HRESULT invoke_variant_prop(script_ctx_t *ctx, VARIANT *v, WORD flags, DISPPARAMS *dp, VARIANT *res)
117 {
118 HRESULT hres;
119
120 switch(flags) {
121 case DISPATCH_PROPERTYGET|DISPATCH_METHOD:
122 case DISPATCH_PROPERTYGET:
123 if(dp->cArgs) {
124 WARN("called with arguments\n");
125 return DISP_E_MEMBERNOTFOUND; /* That's what tests show */
126 }
127
128 hres = VariantCopyInd(res, v);
129 break;
130
131 case DISPATCH_PROPERTYPUT:
132 case DISPATCH_PROPERTYPUTREF:
133 case DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF: {
134 VARIANT put_val;
135 BOOL own_val;
136
137 hres = get_propput_arg(ctx, dp, flags, &put_val, &own_val);
138 if(FAILED(hres))
139 return hres;
140
141 if(arg_cnt(dp)) {
142 FIXME("Arguments not supported\n");
143 return E_NOTIMPL;
144 }
145
146 if(res)
147 V_VT(res) = VT_EMPTY;
148
149 if(own_val)
150 *v = put_val;
151 else
152 hres = VariantCopyInd(v, &put_val);
153 break;
154 }
155
156 default:
157 FIXME("unimplemented flags %x\n", flags);
158 return E_NOTIMPL;
159 }
160
161 return hres;
162 }
163
invoke_vbdisp(vbdisp_t * This,DISPID id,DWORD flags,BOOL extern_caller,DISPPARAMS * params,VARIANT * res)164 static HRESULT invoke_vbdisp(vbdisp_t *This, DISPID id, DWORD flags, BOOL extern_caller, DISPPARAMS *params, VARIANT *res)
165 {
166 if(id < 0)
167 return DISP_E_MEMBERNOTFOUND;
168
169 if(is_func_id(This, id)) {
170 function_t *func;
171
172 TRACE("%p->%s\n", This, debugstr_w(This->desc->funcs[id].name));
173
174 switch(flags) {
175 case DISPATCH_PROPERTYGET:
176 func = This->desc->funcs[id].entries[VBDISP_CALLGET];
177 if(!func || (func->type != FUNC_PROPGET && func->type != FUNC_DEFGET)) {
178 WARN("no getter\n");
179 return DISP_E_MEMBERNOTFOUND;
180 }
181
182 return exec_script(This->desc->ctx, extern_caller, func, This, params, res);
183
184 case DISPATCH_METHOD:
185 case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
186 func = This->desc->funcs[id].entries[VBDISP_CALLGET];
187 if(!func) {
188 FIXME("no invoke/getter\n");
189 return DISP_E_MEMBERNOTFOUND;
190 }
191
192 return exec_script(This->desc->ctx, extern_caller, func, This, params, res);
193
194 case DISPATCH_PROPERTYPUT:
195 case DISPATCH_PROPERTYPUTREF:
196 case DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF: {
197 DISPPARAMS dp = {NULL, NULL, 1, 0};
198 BOOL needs_release;
199 VARIANT put_val;
200 HRESULT hres;
201
202 if(arg_cnt(params)) {
203 FIXME("arguments not implemented\n");
204 return E_NOTIMPL;
205 }
206
207 hres = get_propput_arg(This->desc->ctx, params, flags, &put_val, &needs_release);
208 if(FAILED(hres))
209 return hres;
210
211 dp.rgvarg = &put_val;
212 func = This->desc->funcs[id].entries[V_VT(&put_val) == VT_DISPATCH ? VBDISP_SET : VBDISP_LET];
213 if(!func) {
214 FIXME("no letter/setter\n");
215 return DISP_E_MEMBERNOTFOUND;
216 }
217
218 hres = exec_script(This->desc->ctx, extern_caller, func, This, &dp, NULL);
219 if(needs_release)
220 VariantClear(&put_val);
221 return hres;
222 }
223 default:
224 FIXME("flags %x\n", flags);
225 return DISP_E_MEMBERNOTFOUND;
226 }
227 }
228
229 if(id >= This->desc->prop_cnt + This->desc->func_cnt)
230 return DISP_E_MEMBERNOTFOUND;
231
232 TRACE("%p->%s\n", This, debugstr_w(This->desc->props[id - This->desc->func_cnt].name));
233 return invoke_variant_prop(This->desc->ctx, This->props+(id-This->desc->func_cnt), flags, params, res);
234 }
235
run_terminator(vbdisp_t * This)236 static BOOL run_terminator(vbdisp_t *This)
237 {
238 DISPPARAMS dp = {0};
239
240 if(This->terminator_ran)
241 return TRUE;
242 This->terminator_ran = TRUE;
243
244 if(!This->desc->class_terminate_id)
245 return TRUE;
246
247 This->ref++;
248 exec_script(This->desc->ctx, FALSE, This->desc->funcs[This->desc->class_terminate_id].entries[VBDISP_CALLGET],
249 This, &dp, NULL);
250 return !--This->ref;
251 }
252
clean_props(vbdisp_t * This)253 static void clean_props(vbdisp_t *This)
254 {
255 unsigned i;
256
257 if(!This->desc)
258 return;
259
260 for(i=0; i < This->desc->array_cnt; i++) {
261 if(This->arrays[i]) {
262 SafeArrayDestroy(This->arrays[i]);
263 This->arrays[i] = NULL;
264 }
265 }
266
267 for(i=0; i < This->desc->prop_cnt; i++)
268 VariantClear(This->props+i);
269 }
270
impl_from_IDispatchEx(IDispatchEx * iface)271 static inline vbdisp_t *impl_from_IDispatchEx(IDispatchEx *iface)
272 {
273 return CONTAINING_RECORD(iface, vbdisp_t, IDispatchEx_iface);
274 }
275
DispatchEx_QueryInterface(IDispatchEx * iface,REFIID riid,void ** ppv)276 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
277 {
278 vbdisp_t *This = impl_from_IDispatchEx(iface);
279
280 if(IsEqualGUID(&IID_IUnknown, riid)) {
281 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
282 *ppv = &This->IDispatchEx_iface;
283 }else if(IsEqualGUID(&IID_IDispatch, riid)) {
284 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
285 *ppv = &This->IDispatchEx_iface;
286 }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
287 TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
288 *ppv = &This->IDispatchEx_iface;
289 }else {
290 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
291 *ppv = NULL;
292 return E_NOINTERFACE;
293 }
294
295 IUnknown_AddRef((IUnknown*)*ppv);
296 return S_OK;
297 }
298
DispatchEx_AddRef(IDispatchEx * iface)299 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
300 {
301 vbdisp_t *This = impl_from_IDispatchEx(iface);
302 LONG ref = InterlockedIncrement(&This->ref);
303
304 TRACE("(%p) ref=%d\n", This, ref);
305
306 return ref;
307 }
308
DispatchEx_Release(IDispatchEx * iface)309 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
310 {
311 vbdisp_t *This = impl_from_IDispatchEx(iface);
312 LONG ref = InterlockedDecrement(&This->ref);
313
314 TRACE("(%p) ref=%d\n", This, ref);
315
316 if(!ref && run_terminator(This)) {
317 clean_props(This);
318 list_remove(&This->entry);
319 heap_free(This->arrays);
320 heap_free(This);
321 }
322
323 return ref;
324 }
325
DispatchEx_GetTypeInfoCount(IDispatchEx * iface,UINT * pctinfo)326 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
327 {
328 vbdisp_t *This = impl_from_IDispatchEx(iface);
329
330 TRACE("(%p)->(%p)\n", This, pctinfo);
331
332 *pctinfo = 1;
333 return S_OK;
334 }
335
DispatchEx_GetTypeInfo(IDispatchEx * iface,UINT iTInfo,LCID lcid,ITypeInfo ** ppTInfo)336 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid,
337 ITypeInfo **ppTInfo)
338 {
339 vbdisp_t *This = impl_from_IDispatchEx(iface);
340 FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
341 return E_NOTIMPL;
342 }
343
DispatchEx_GetIDsOfNames(IDispatchEx * iface,REFIID riid,LPOLESTR * rgszNames,UINT cNames,LCID lcid,DISPID * rgDispId)344 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
345 LPOLESTR *rgszNames, UINT cNames, LCID lcid,
346 DISPID *rgDispId)
347 {
348 vbdisp_t *This = impl_from_IDispatchEx(iface);
349 FIXME("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
350 lcid, rgDispId);
351 return E_NOTIMPL;
352 }
353
DispatchEx_Invoke(IDispatchEx * iface,DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)354 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
355 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
356 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
357 {
358 vbdisp_t *This = impl_from_IDispatchEx(iface);
359
360 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
361 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
362
363 return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, NULL);
364 }
365
DispatchEx_GetDispID(IDispatchEx * iface,BSTR bstrName,DWORD grfdex,DISPID * pid)366 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
367 {
368 vbdisp_t *This = impl_from_IDispatchEx(iface);
369
370 TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
371
372 grfdex &= ~FDEX_VERSION_MASK;
373
374 if(!This->desc)
375 return E_UNEXPECTED;
376
377 /* Tests show that fdexNameCaseSensitive is ignored */
378
379 if(grfdex & ~(fdexNameEnsure|fdexNameCaseInsensitive|fdexNameCaseSensitive)) {
380 FIXME("unsupported flags %x\n", grfdex);
381 return E_NOTIMPL;
382 }
383
384 return vbdisp_get_id(This, bstrName, VBDISP_ANY, FALSE, pid);
385 }
386
DispatchEx_InvokeEx(IDispatchEx * iface,DISPID id,LCID lcid,WORD wFlags,DISPPARAMS * pdp,VARIANT * pvarRes,EXCEPINFO * pei,IServiceProvider * pspCaller)387 static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
388 VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
389 {
390 vbdisp_t *This = impl_from_IDispatchEx(iface);
391
392 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
393
394 if(!This->desc)
395 return E_UNEXPECTED;
396
397 if(pvarRes)
398 V_VT(pvarRes) = VT_EMPTY;
399
400 return invoke_vbdisp(This, id, wFlags, TRUE, pdp, pvarRes);
401 }
402
DispatchEx_DeleteMemberByName(IDispatchEx * iface,BSTR bstrName,DWORD grfdex)403 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
404 {
405 vbdisp_t *This = impl_from_IDispatchEx(iface);
406 FIXME("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex);
407 return E_NOTIMPL;
408 }
409
DispatchEx_DeleteMemberByDispID(IDispatchEx * iface,DISPID id)410 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
411 {
412 vbdisp_t *This = impl_from_IDispatchEx(iface);
413 FIXME("(%p)->(%x)\n", This, id);
414 return E_NOTIMPL;
415 }
416
DispatchEx_GetMemberProperties(IDispatchEx * iface,DISPID id,DWORD grfdexFetch,DWORD * pgrfdex)417 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
418 {
419 vbdisp_t *This = impl_from_IDispatchEx(iface);
420 FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex);
421 return E_NOTIMPL;
422 }
423
DispatchEx_GetMemberName(IDispatchEx * iface,DISPID id,BSTR * pbstrName)424 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
425 {
426 vbdisp_t *This = impl_from_IDispatchEx(iface);
427 FIXME("(%p)->(%x %p)\n", This, id, pbstrName);
428 return E_NOTIMPL;
429 }
430
DispatchEx_GetNextDispID(IDispatchEx * iface,DWORD grfdex,DISPID id,DISPID * pid)431 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
432 {
433 vbdisp_t *This = impl_from_IDispatchEx(iface);
434 FIXME("(%p)->(%x %x %p)\n", This, grfdex, id, pid);
435 return E_NOTIMPL;
436 }
437
DispatchEx_GetNameSpaceParent(IDispatchEx * iface,IUnknown ** ppunk)438 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
439 {
440 vbdisp_t *This = impl_from_IDispatchEx(iface);
441 FIXME("(%p)->(%p)\n", This, ppunk);
442 return E_NOTIMPL;
443 }
444
445 static IDispatchExVtbl DispatchExVtbl = {
446 DispatchEx_QueryInterface,
447 DispatchEx_AddRef,
448 DispatchEx_Release,
449 DispatchEx_GetTypeInfoCount,
450 DispatchEx_GetTypeInfo,
451 DispatchEx_GetIDsOfNames,
452 DispatchEx_Invoke,
453 DispatchEx_GetDispID,
454 DispatchEx_InvokeEx,
455 DispatchEx_DeleteMemberByName,
456 DispatchEx_DeleteMemberByDispID,
457 DispatchEx_GetMemberProperties,
458 DispatchEx_GetMemberName,
459 DispatchEx_GetNextDispID,
460 DispatchEx_GetNameSpaceParent
461 };
462
unsafe_impl_from_IDispatch(IDispatch * iface)463 static inline vbdisp_t *unsafe_impl_from_IDispatch(IDispatch *iface)
464 {
465 return iface->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl
466 ? CONTAINING_RECORD((IDispatchEx *)iface, vbdisp_t, IDispatchEx_iface)
467 : NULL;
468 }
469
create_vbdisp(const class_desc_t * desc,vbdisp_t ** ret)470 HRESULT create_vbdisp(const class_desc_t *desc, vbdisp_t **ret)
471 {
472 vbdisp_t *vbdisp;
473 HRESULT hres = S_OK;
474
475 vbdisp = heap_alloc_zero( FIELD_OFFSET( vbdisp_t, props[desc->prop_cnt] ));
476 if(!vbdisp)
477 return E_OUTOFMEMORY;
478
479 vbdisp->IDispatchEx_iface.lpVtbl = &DispatchExVtbl;
480 vbdisp->ref = 1;
481 vbdisp->desc = desc;
482
483 list_add_tail(&desc->ctx->objects, &vbdisp->entry);
484
485 if(desc->array_cnt) {
486 vbdisp->arrays = heap_alloc_zero(desc->array_cnt * sizeof(*vbdisp->arrays));
487 if(vbdisp->arrays) {
488 unsigned i, j;
489
490 for(i=0; i < desc->array_cnt; i++) {
491 if(!desc->array_descs[i].dim_cnt)
492 continue;
493
494 vbdisp->arrays[i] = SafeArrayCreate(VT_VARIANT, desc->array_descs[i].dim_cnt, desc->array_descs[i].bounds);
495 if(!vbdisp->arrays[i]) {
496 hres = E_OUTOFMEMORY;
497 break;
498 }
499 }
500
501 if(SUCCEEDED(hres)) {
502 for(i=0, j=0; i < desc->prop_cnt; i++) {
503 if(desc->props[i].is_array) {
504 V_VT(vbdisp->props+i) = VT_ARRAY|VT_BYREF|VT_VARIANT;
505 V_ARRAYREF(vbdisp->props+i) = vbdisp->arrays + j++;
506 }
507 }
508 }
509 }else {
510 hres = E_OUTOFMEMORY;
511 }
512 }
513
514 if(SUCCEEDED(hres) && desc->class_initialize_id) {
515 DISPPARAMS dp = {0};
516 hres = exec_script(desc->ctx, FALSE, desc->funcs[desc->class_initialize_id].entries[VBDISP_CALLGET],
517 vbdisp, &dp, NULL);
518 }
519
520 if(FAILED(hres)) {
521 IDispatchEx_Release(&vbdisp->IDispatchEx_iface);
522 return hres;
523 }
524
525 *ret = vbdisp;
526 return S_OK;
527 }
528
529 struct _ident_map_t {
530 const WCHAR *name;
531 BOOL is_var;
532 union {
533 dynamic_var_t *var;
534 function_t *func;
535 } u;
536 };
537
ident_to_id(ScriptDisp * This,ident_map_t * ident)538 static inline DISPID ident_to_id(ScriptDisp *This, ident_map_t *ident)
539 {
540 return (ident-This->ident_map)+1;
541 }
542
id_to_ident(ScriptDisp * This,DISPID id)543 static inline ident_map_t *id_to_ident(ScriptDisp *This, DISPID id)
544 {
545 return 0 < id && id <= This->ident_map_cnt ? This->ident_map+id-1 : NULL;
546 }
547
add_ident(ScriptDisp * This,const WCHAR * name)548 static ident_map_t *add_ident(ScriptDisp *This, const WCHAR *name)
549 {
550 ident_map_t *ret;
551
552 if(!This->ident_map_size) {
553 This->ident_map = heap_alloc(4 * sizeof(*This->ident_map));
554 if(!This->ident_map)
555 return NULL;
556 This->ident_map_size = 4;
557 }else if(This->ident_map_cnt == This->ident_map_size) {
558 ident_map_t *new_map;
559
560 new_map = heap_realloc(This->ident_map, 2*This->ident_map_size*sizeof(*new_map));
561 if(!new_map)
562 return NULL;
563 This->ident_map = new_map;
564 This->ident_map_size *= 2;
565 }
566
567 ret = This->ident_map + This->ident_map_cnt++;
568 ret->name = name;
569 return ret;
570 }
571
ScriptDisp_from_IDispatchEx(IDispatchEx * iface)572 static inline ScriptDisp *ScriptDisp_from_IDispatchEx(IDispatchEx *iface)
573 {
574 return CONTAINING_RECORD(iface, ScriptDisp, IDispatchEx_iface);
575 }
576
ScriptDisp_QueryInterface(IDispatchEx * iface,REFIID riid,void ** ppv)577 static HRESULT WINAPI ScriptDisp_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
578 {
579 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
580
581 if(IsEqualGUID(&IID_IUnknown, riid)) {
582 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
583 *ppv = &This->IDispatchEx_iface;
584 }else if(IsEqualGUID(&IID_IDispatch, riid)) {
585 TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
586 *ppv = &This->IDispatchEx_iface;
587 }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
588 TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
589 *ppv = &This->IDispatchEx_iface;
590 }else {
591 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
592 *ppv = NULL;
593 return E_NOINTERFACE;
594 }
595
596 IUnknown_AddRef((IUnknown*)*ppv);
597 return S_OK;
598 }
599
ScriptDisp_AddRef(IDispatchEx * iface)600 static ULONG WINAPI ScriptDisp_AddRef(IDispatchEx *iface)
601 {
602 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
603 LONG ref = InterlockedIncrement(&This->ref);
604
605 TRACE("(%p) ref=%d\n", This, ref);
606
607 return ref;
608 }
609
ScriptDisp_Release(IDispatchEx * iface)610 static ULONG WINAPI ScriptDisp_Release(IDispatchEx *iface)
611 {
612 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
613 LONG ref = InterlockedDecrement(&This->ref);
614
615 TRACE("(%p) ref=%d\n", This, ref);
616
617 if(!ref) {
618 assert(!This->ctx);
619 heap_free(This->ident_map);
620 heap_free(This);
621 }
622
623 return ref;
624 }
625
ScriptDisp_GetTypeInfoCount(IDispatchEx * iface,UINT * pctinfo)626 static HRESULT WINAPI ScriptDisp_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
627 {
628 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
629
630 TRACE("(%p)->(%p)\n", This, pctinfo);
631
632 *pctinfo = 1;
633 return S_OK;
634 }
635
ScriptDisp_GetTypeInfo(IDispatchEx * iface,UINT iTInfo,LCID lcid,ITypeInfo ** ppTInfo)636 static HRESULT WINAPI ScriptDisp_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid,
637 ITypeInfo **ppTInfo)
638 {
639 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
640 FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
641 return E_NOTIMPL;
642 }
643
ScriptDisp_GetIDsOfNames(IDispatchEx * iface,REFIID riid,LPOLESTR * rgszNames,UINT cNames,LCID lcid,DISPID * rgDispId)644 static HRESULT WINAPI ScriptDisp_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
645 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
646 {
647 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
648 UINT i;
649 HRESULT hres;
650
651 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
652 lcid, rgDispId);
653
654 for(i=0; i < cNames; i++) {
655 hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, rgszNames[i], 0, rgDispId+i);
656 if(FAILED(hres))
657 return hres;
658 }
659
660 return S_OK;
661 }
662
ScriptDisp_Invoke(IDispatchEx * iface,DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)663 static HRESULT WINAPI ScriptDisp_Invoke(IDispatchEx *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
664 WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
665 {
666 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
667
668 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
669 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
670
671 return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags,
672 pDispParams, pVarResult, pExcepInfo, NULL);
673 }
674
ScriptDisp_GetDispID(IDispatchEx * iface,BSTR bstrName,DWORD grfdex,DISPID * pid)675 static HRESULT WINAPI ScriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
676 {
677 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
678 dynamic_var_t *var;
679 ident_map_t *ident;
680 function_t *func;
681
682 TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
683
684 if(!This->ctx)
685 return E_UNEXPECTED;
686
687 for(ident = This->ident_map; ident < This->ident_map+This->ident_map_cnt; ident++) {
688 if(!wcsicmp(ident->name, bstrName)) {
689 *pid = ident_to_id(This, ident);
690 return S_OK;
691 }
692 }
693
694 for(var = This->ctx->global_vars; var; var = var->next) {
695 if(!wcsicmp(var->name, bstrName)) {
696 ident = add_ident(This, var->name);
697 if(!ident)
698 return E_OUTOFMEMORY;
699
700 ident->is_var = TRUE;
701 ident->u.var = var;
702 *pid = ident_to_id(This, ident);
703 return S_OK;
704 }
705 }
706
707 for(func = This->ctx->global_funcs; func; func = func->next) {
708 if(!wcsicmp(func->name, bstrName)) {
709 ident = add_ident(This, func->name);
710 if(!ident)
711 return E_OUTOFMEMORY;
712
713 ident->is_var = FALSE;
714 ident->u.func = func;
715 *pid = ident_to_id(This, ident);
716 return S_OK;
717 }
718 }
719
720 *pid = -1;
721 return DISP_E_UNKNOWNNAME;
722 }
723
ScriptDisp_InvokeEx(IDispatchEx * iface,DISPID id,LCID lcid,WORD wFlags,DISPPARAMS * pdp,VARIANT * pvarRes,EXCEPINFO * pei,IServiceProvider * pspCaller)724 static HRESULT WINAPI ScriptDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
725 VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
726 {
727 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
728 ident_map_t *ident;
729 HRESULT hres;
730
731 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
732
733 ident = id_to_ident(This, id);
734 if(!ident)
735 return DISP_E_MEMBERNOTFOUND;
736
737 if(ident->is_var) {
738 if(ident->u.var->is_const) {
739 FIXME("const not supported\n");
740 return E_NOTIMPL;
741 }
742
743 return invoke_variant_prop(This->ctx, &ident->u.var->v, wFlags, pdp, pvarRes);
744 }
745
746 switch(wFlags) {
747 case DISPATCH_METHOD:
748 case DISPATCH_METHOD|DISPATCH_PROPERTYGET:
749 hres = exec_script(This->ctx, TRUE, ident->u.func, NULL, pdp, pvarRes);
750 break;
751 default:
752 FIXME("Unsupported flags %x\n", wFlags);
753 hres = E_NOTIMPL;
754 }
755
756 return hres;
757 }
758
ScriptDisp_DeleteMemberByName(IDispatchEx * iface,BSTR bstrName,DWORD grfdex)759 static HRESULT WINAPI ScriptDisp_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
760 {
761 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
762 FIXME("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex);
763 return E_NOTIMPL;
764 }
765
ScriptDisp_DeleteMemberByDispID(IDispatchEx * iface,DISPID id)766 static HRESULT WINAPI ScriptDisp_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
767 {
768 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
769 FIXME("(%p)->(%x)\n", This, id);
770 return E_NOTIMPL;
771 }
772
ScriptDisp_GetMemberProperties(IDispatchEx * iface,DISPID id,DWORD grfdexFetch,DWORD * pgrfdex)773 static HRESULT WINAPI ScriptDisp_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
774 {
775 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
776 FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex);
777 return E_NOTIMPL;
778 }
779
ScriptDisp_GetMemberName(IDispatchEx * iface,DISPID id,BSTR * pbstrName)780 static HRESULT WINAPI ScriptDisp_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
781 {
782 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
783 FIXME("(%p)->(%x %p)\n", This, id, pbstrName);
784 return E_NOTIMPL;
785 }
786
ScriptDisp_GetNextDispID(IDispatchEx * iface,DWORD grfdex,DISPID id,DISPID * pid)787 static HRESULT WINAPI ScriptDisp_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
788 {
789 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
790 FIXME("(%p)->(%x %x %p)\n", This, grfdex, id, pid);
791 return E_NOTIMPL;
792 }
793
ScriptDisp_GetNameSpaceParent(IDispatchEx * iface,IUnknown ** ppunk)794 static HRESULT WINAPI ScriptDisp_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
795 {
796 ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
797 FIXME("(%p)->(%p)\n", This, ppunk);
798 return E_NOTIMPL;
799 }
800
801 static IDispatchExVtbl ScriptDispVtbl = {
802 ScriptDisp_QueryInterface,
803 ScriptDisp_AddRef,
804 ScriptDisp_Release,
805 ScriptDisp_GetTypeInfoCount,
806 ScriptDisp_GetTypeInfo,
807 ScriptDisp_GetIDsOfNames,
808 ScriptDisp_Invoke,
809 ScriptDisp_GetDispID,
810 ScriptDisp_InvokeEx,
811 ScriptDisp_DeleteMemberByName,
812 ScriptDisp_DeleteMemberByDispID,
813 ScriptDisp_GetMemberProperties,
814 ScriptDisp_GetMemberName,
815 ScriptDisp_GetNextDispID,
816 ScriptDisp_GetNameSpaceParent
817 };
818
create_script_disp(script_ctx_t * ctx,ScriptDisp ** ret)819 HRESULT create_script_disp(script_ctx_t *ctx, ScriptDisp **ret)
820 {
821 ScriptDisp *script_disp;
822
823 script_disp = heap_alloc_zero(sizeof(*script_disp));
824 if(!script_disp)
825 return E_OUTOFMEMORY;
826
827 script_disp->IDispatchEx_iface.lpVtbl = &ScriptDispVtbl;
828 script_disp->ref = 1;
829 script_disp->ctx = ctx;
830
831 *ret = script_disp;
832 return S_OK;
833 }
834
collect_objects(script_ctx_t * ctx)835 void collect_objects(script_ctx_t *ctx)
836 {
837 vbdisp_t *iter, *iter2;
838
839 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &ctx->objects, vbdisp_t, entry)
840 run_terminator(iter);
841
842 while(!list_empty(&ctx->objects)) {
843 iter = LIST_ENTRY(list_head(&ctx->objects), vbdisp_t, entry);
844
845 IDispatchEx_AddRef(&iter->IDispatchEx_iface);
846 clean_props(iter);
847 iter->desc = NULL;
848 list_remove(&iter->entry);
849 list_init(&iter->entry);
850 IDispatchEx_Release(&iter->IDispatchEx_iface);
851 }
852 }
853
disp_get_id(IDispatch * disp,BSTR name,vbdisp_invoke_type_t invoke_type,BOOL search_private,DISPID * id)854 HRESULT disp_get_id(IDispatch *disp, BSTR name, vbdisp_invoke_type_t invoke_type, BOOL search_private, DISPID *id)
855 {
856 IDispatchEx *dispex;
857 vbdisp_t *vbdisp;
858 HRESULT hres;
859
860 vbdisp = unsafe_impl_from_IDispatch(disp);
861 if(vbdisp)
862 return vbdisp_get_id(vbdisp, name, invoke_type, search_private, id);
863
864 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
865 if(FAILED(hres)) {
866 TRACE("using IDispatch\n");
867 return IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, id);
868 }
869
870 hres = IDispatchEx_GetDispID(dispex, name, fdexNameCaseInsensitive, id);
871 IDispatchEx_Release(dispex);
872 return hres;
873 }
874
875 #define RPC_E_SERVER_UNAVAILABLE 0x800706ba
876
map_hres(HRESULT hres)877 HRESULT map_hres(HRESULT hres)
878 {
879 if(SUCCEEDED(hres) || HRESULT_FACILITY(hres) == FACILITY_VBS)
880 return hres;
881
882 switch(hres) {
883 case E_NOTIMPL: return MAKE_VBSERROR(VBSE_ACTION_NOT_SUPPORTED);
884 case E_NOINTERFACE: return MAKE_VBSERROR(VBSE_OLE_NOT_SUPPORTED);
885 case DISP_E_UNKNOWNINTERFACE: return MAKE_VBSERROR(VBSE_OLE_NO_PROP_OR_METHOD);
886 case DISP_E_MEMBERNOTFOUND: return MAKE_VBSERROR(VBSE_OLE_NO_PROP_OR_METHOD);
887 case DISP_E_PARAMNOTFOUND: return MAKE_VBSERROR(VBSE_NAMED_PARAM_NOT_FOUND);
888 case DISP_E_TYPEMISMATCH: return MAKE_VBSERROR(VBSE_TYPE_MISMATCH);
889 case DISP_E_UNKNOWNNAME: return MAKE_VBSERROR(VBSE_OLE_NO_PROP_OR_METHOD);
890 case DISP_E_NONAMEDARGS: return MAKE_VBSERROR(VBSE_NAMED_ARGS_NOT_SUPPORTED);
891 case DISP_E_BADVARTYPE: return MAKE_VBSERROR(VBSE_INVALID_TYPELIB_VARIABLE);
892 case DISP_E_OVERFLOW: return MAKE_VBSERROR(VBSE_OVERFLOW);
893 case DISP_E_BADINDEX: return MAKE_VBSERROR(VBSE_OUT_OF_BOUNDS);
894 case DISP_E_UNKNOWNLCID: return MAKE_VBSERROR(VBSE_LOCALE_SETTING_NOT_SUPPORTED);
895 case DISP_E_ARRAYISLOCKED: return MAKE_VBSERROR(VBSE_ARRAY_LOCKED);
896 case DISP_E_BADPARAMCOUNT: return MAKE_VBSERROR(VBSE_FUNC_ARITY_MISMATCH);
897 case DISP_E_PARAMNOTOPTIONAL: return MAKE_VBSERROR(VBSE_PARAMETER_NOT_OPTIONAL);
898 case DISP_E_NOTACOLLECTION: return MAKE_VBSERROR(VBSE_NOT_ENUM);
899 case TYPE_E_DLLFUNCTIONNOTFOUND: return MAKE_VBSERROR(VBSE_INVALID_DLL_FUNCTION_NAME);
900 case TYPE_E_TYPEMISMATCH: return MAKE_VBSERROR(VBSE_TYPE_MISMATCH);
901 case TYPE_E_OUTOFBOUNDS: return MAKE_VBSERROR(VBSE_OUT_OF_BOUNDS);
902 case TYPE_E_IOERROR: return MAKE_VBSERROR(VBSE_IO_ERROR);
903 case TYPE_E_CANTCREATETMPFILE: return MAKE_VBSERROR(VBSE_CANT_CREATE_TMP_FILE);
904 case STG_E_FILENOTFOUND: return MAKE_VBSERROR(VBSE_OLE_FILE_NOT_FOUND);
905 case STG_E_PATHNOTFOUND: return MAKE_VBSERROR(VBSE_PATH_NOT_FOUND);
906 case STG_E_TOOMANYOPENFILES: return MAKE_VBSERROR(VBSE_TOO_MANY_FILES);
907 case STG_E_ACCESSDENIED: return MAKE_VBSERROR(VBSE_PERMISSION_DENIED);
908 case STG_E_INSUFFICIENTMEMORY: return MAKE_VBSERROR(VBSE_OUT_OF_MEMORY);
909 case STG_E_NOMOREFILES: return MAKE_VBSERROR(VBSE_TOO_MANY_FILES);
910 case STG_E_DISKISWRITEPROTECTED: return MAKE_VBSERROR(VBSE_PERMISSION_DENIED);
911 case STG_E_WRITEFAULT: return MAKE_VBSERROR(VBSE_IO_ERROR);
912 case STG_E_READFAULT: return MAKE_VBSERROR(VBSE_IO_ERROR);
913 case STG_E_SHAREVIOLATION: return MAKE_VBSERROR(VBSE_PATH_FILE_ACCESS);
914 case STG_E_LOCKVIOLATION: return MAKE_VBSERROR(VBSE_PERMISSION_DENIED);
915 case STG_E_FILEALREADYEXISTS: return MAKE_VBSERROR(VBSE_FILE_ALREADY_EXISTS);
916 case STG_E_MEDIUMFULL: return MAKE_VBSERROR(VBSE_DISK_FULL);
917 case STG_E_INVALIDNAME: return MAKE_VBSERROR(VBSE_FILE_NOT_FOUND);
918 case STG_E_INUSE: return MAKE_VBSERROR(VBSE_PERMISSION_DENIED);
919 case STG_E_NOTCURRENT: return MAKE_VBSERROR(VBSE_PERMISSION_DENIED);
920 case STG_E_CANTSAVE: return MAKE_VBSERROR(VBSE_IO_ERROR);
921 case REGDB_E_CLASSNOTREG: return MAKE_VBSERROR(VBSE_CANT_CREATE_OBJECT);
922 case MK_E_UNAVAILABLE: return MAKE_VBSERROR(VBSE_CANT_CREATE_OBJECT);
923 case MK_E_INVALIDEXTENSION: return MAKE_VBSERROR(VBSE_OLE_FILE_NOT_FOUND);
924 case MK_E_CANTOPENFILE: return MAKE_VBSERROR(VBSE_OLE_FILE_NOT_FOUND);
925 case CO_E_CLASSSTRING: return MAKE_VBSERROR(VBSE_CANT_CREATE_OBJECT);
926 case CO_E_APPNOTFOUND: return MAKE_VBSERROR(VBSE_CANT_CREATE_OBJECT);
927 case CO_E_APPDIDNTREG: return MAKE_VBSERROR(VBSE_CANT_CREATE_OBJECT);
928 case E_ACCESSDENIED: return MAKE_VBSERROR(VBSE_PERMISSION_DENIED);
929 case E_OUTOFMEMORY: return MAKE_VBSERROR(VBSE_OUT_OF_MEMORY);
930 case E_INVALIDARG: return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
931 case RPC_E_SERVER_UNAVAILABLE: return MAKE_VBSERROR(VBSE_SERVER_NOT_FOUND);
932 case CO_E_SERVER_EXEC_FAILURE: return MAKE_VBSERROR(VBSE_CANT_CREATE_OBJECT);
933 }
934
935 return hres;
936 }
937
disp_call(script_ctx_t * ctx,IDispatch * disp,DISPID id,DISPPARAMS * dp,VARIANT * retv)938 HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, DISPPARAMS *dp, VARIANT *retv)
939 {
940 const WORD flags = DISPATCH_METHOD|(retv ? DISPATCH_PROPERTYGET : 0);
941 IDispatchEx *dispex;
942 vbdisp_t *vbdisp;
943 EXCEPINFO ei;
944 HRESULT hres;
945
946 memset(&ei, 0, sizeof(ei));
947 if(retv)
948 V_VT(retv) = VT_EMPTY;
949
950 vbdisp = unsafe_impl_from_IDispatch(disp);
951 if(vbdisp && vbdisp->desc && vbdisp->desc->ctx == ctx)
952 return invoke_vbdisp(vbdisp, id, flags, FALSE, dp, retv);
953
954 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
955 if(FAILED(hres)) {
956 UINT err = 0;
957
958 TRACE("using IDispatch\n");
959 return IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, dp, retv, &ei, &err);
960 }
961
962 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, dp, retv, &ei, NULL /* CALLER_FIXME */);
963 IDispatchEx_Release(dispex);
964 return hres;
965 }
966
get_disp_value(script_ctx_t * ctx,IDispatch * disp,VARIANT * v)967 HRESULT get_disp_value(script_ctx_t *ctx, IDispatch *disp, VARIANT *v)
968 {
969 DISPPARAMS dp = {NULL};
970 if(!disp)
971 return MAKE_VBSERROR(VBSE_OBJECT_VARIABLE_NOT_SET);
972 return disp_call(ctx, disp, DISPID_VALUE, &dp, v);
973 }
974
disp_propput(script_ctx_t * ctx,IDispatch * disp,DISPID id,WORD flags,DISPPARAMS * dp)975 HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, DISPPARAMS *dp)
976 {
977 IDispatchEx *dispex;
978 vbdisp_t *vbdisp;
979 EXCEPINFO ei = {0};
980 HRESULT hres;
981
982 vbdisp = unsafe_impl_from_IDispatch(disp);
983 if(vbdisp && vbdisp->desc && vbdisp->desc->ctx == ctx)
984 return invoke_vbdisp(vbdisp, id, flags, FALSE, dp, NULL);
985
986 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
987 if(SUCCEEDED(hres)) {
988 hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, dp, NULL, &ei, NULL /* FIXME! */);
989 IDispatchEx_Release(dispex);
990 }else {
991 ULONG err = 0;
992
993 TRACE("using IDispatch\n");
994 hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, dp, NULL, &ei, &err);
995 }
996
997 return hres;
998 }
999