crypt32: Make sure we show Unicode characters (Dutch translation).
[wine] / dlls / mshtml / dispex.c
1 /*
2  * Copyright 2008 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 <stdarg.h>
20
21 #define COBJMACROS
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "ole2.h"
27
28 #include "wine/debug.h"
29
30 #include "mshtml_private.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
33
34 typedef struct {
35     DISPID id;
36     BSTR name;
37     tid_t tid;
38 } func_info_t;
39
40 struct dispex_data_t {
41     DWORD func_cnt;
42     func_info_t *funcs;
43     func_info_t **name_table;
44
45     struct list entry;
46 };
47
48 typedef struct {
49     VARIANT var;
50     LPWSTR name;
51 } dynamic_prop_t;
52
53 struct dispex_dynamic_data_t {
54     DWORD buf_size;
55     DWORD prop_cnt;
56     dynamic_prop_t *props;
57 };
58
59 #define DISPID_DYNPROP_0    0x50000000
60 #define DISPID_DYNPROP_MAX  0x5fffffff
61
62 static ITypeLib *typelib;
63 static ITypeInfo *typeinfos[LAST_tid];
64 static struct list dispex_data_list = LIST_INIT(dispex_data_list);
65
66 static REFIID tid_ids[] = {
67     &IID_NULL,
68     &DIID_DispCEventObj,
69     &DIID_DispDOMChildrenCollection,
70     &DIID_DispHTMLBody,
71     &DIID_DispHTMLCommentElement,
72     &DIID_DispHTMLCurrentStyle,
73     &DIID_DispHTMLDocument,
74     &DIID_DispHTMLDOMTextNode,
75     &DIID_DispHTMLElementCollection,
76     &DIID_DispHTMLGenericElement,
77     &DIID_DispHTMLIFrame,
78     &DIID_DispHTMLImg,
79     &DIID_DispHTMLInputElement,
80     &DIID_DispHTMLLocation,
81     &DIID_DispHTMLNavigator,
82     &DIID_DispHTMLOptionElement,
83     &DIID_DispHTMLSelectElement,
84     &DIID_DispHTMLStyle,
85     &DIID_DispHTMLTable,
86     &DIID_DispHTMLTableRow,
87     &DIID_DispHTMLUnknownElement,
88     &DIID_DispHTMLWindow2,
89     &IID_IHTMLBodyElement,
90     &IID_IHTMLBodyElement2,
91     &IID_IHTMLCommentElement,
92     &IID_IHTMLCurrentStyle,
93     &IID_IHTMLCurrentStyle2,
94     &IID_IHTMLCurrentStyle3,
95     &IID_IHTMLCurrentStyle4,
96     &IID_IHTMLDocument2,
97     &IID_IHTMLDocument3,
98     &IID_IHTMLDocument4,
99     &IID_IHTMLDocument5,
100     &IID_IHTMLDOMChildrenCollection,
101     &IID_IHTMLDOMNode,
102     &IID_IHTMLDOMNode2,
103     &IID_IHTMLDOMTextNode,
104     &IID_IHTMLElement,
105     &IID_IHTMLElement2,
106     &IID_IHTMLElement3,
107     &IID_IHTMLElement4,
108     &IID_IHTMLElementCollection,
109     &IID_IHTMLEventObj,
110     &IID_IHTMLFrameBase2,
111     &IID_IHTMLGenericElement,
112     &IID_IHTMLImgElement,
113     &IID_IHTMLInputElement,
114     &IID_IHTMLLocation,
115     &IID_IHTMLOptionElement,
116     &IID_IHTMLSelectElement,
117     &IID_IHTMLStyle,
118     &IID_IHTMLStyle2,
119     &IID_IHTMLStyle3,
120     &IID_IHTMLStyle4,
121     &IID_IHTMLTable,
122     &IID_IHTMLTableRow,
123     &IID_IHTMLTextContainer,
124     &IID_IHTMLUniqueName,
125     &IID_IHTMLWindow2,
126     &IID_IHTMLWindow3,
127     &IID_IOmNavigator
128 };
129
130 static HRESULT get_typeinfo(tid_t tid, ITypeInfo **typeinfo)
131 {
132     HRESULT hres;
133
134     if(!typelib) {
135         ITypeLib *tl;
136
137         hres = LoadRegTypeLib(&LIBID_MSHTML, 4, 0, LOCALE_SYSTEM_DEFAULT, &tl);
138         if(FAILED(hres)) {
139             ERR("LoadRegTypeLib failed: %08x\n", hres);
140             return hres;
141         }
142
143         if(InterlockedCompareExchangePointer((void**)&typelib, tl, NULL))
144             ITypeLib_Release(tl);
145     }
146
147     if(!typeinfos[tid]) {
148         ITypeInfo *typeinfo;
149
150         hres = ITypeLib_GetTypeInfoOfGuid(typelib, tid_ids[tid], &typeinfo);
151         if(FAILED(hres)) {
152             ERR("GetTypeInfoOfGuid(%s) failed: %08x\n", debugstr_guid(tid_ids[tid]), hres);
153             return hres;
154         }
155
156         if(InterlockedCompareExchangePointer((void**)(typeinfos+tid), typeinfo, NULL))
157             ITypeInfo_Release(typeinfo);
158     }
159
160     *typeinfo = typeinfos[tid];
161     return S_OK;
162 }
163
164 void release_typelib(void)
165 {
166     dispex_data_t *iter;
167     unsigned i;
168
169     while(!list_empty(&dispex_data_list)) {
170         iter = LIST_ENTRY(list_head(&dispex_data_list), dispex_data_t, entry);
171         list_remove(&iter->entry);
172
173         for(i=0; i < iter->func_cnt; i++)
174             SysFreeString(iter->funcs[i].name);
175
176         heap_free(iter->funcs);
177         heap_free(iter->name_table);
178         heap_free(iter);
179     }
180
181     if(!typelib)
182         return;
183
184     for(i=0; i < sizeof(typeinfos)/sizeof(*typeinfos); i++)
185         if(typeinfos[i])
186             ITypeInfo_Release(typeinfos[i]);
187
188     ITypeLib_Release(typelib);
189 }
190
191 static void add_func_info(dispex_data_t *data, DWORD *size, tid_t tid, DISPID id, ITypeInfo *dti)
192 {
193     HRESULT hres;
194
195     if(data->func_cnt && data->funcs[data->func_cnt-1].id == id)
196         return;
197
198     if(data->func_cnt == *size)
199         data->funcs = heap_realloc(data->funcs, (*size <<= 1)*sizeof(func_info_t));
200
201     hres = ITypeInfo_GetDocumentation(dti, id, &data->funcs[data->func_cnt].name, NULL, NULL, NULL);
202     if(FAILED(hres))
203         return;
204
205     data->funcs[data->func_cnt].id = id;
206     data->funcs[data->func_cnt].tid = tid;
207
208     data->func_cnt++;
209 }
210
211 static int dispid_cmp(const void *p1, const void *p2)
212 {
213     return ((func_info_t*)p1)->id - ((func_info_t*)p2)->id;
214 }
215
216 static int func_name_cmp(const void *p1, const void *p2)
217 {
218     return strcmpiW((*(func_info_t**)p1)->name, (*(func_info_t**)p2)->name);
219 }
220
221 static dispex_data_t *preprocess_dispex_data(DispatchEx *This)
222 {
223     const tid_t *tid = This->data->iface_tids;
224     FUNCDESC *funcdesc;
225     dispex_data_t *data;
226     DWORD size = 16, i;
227     ITypeInfo *ti, *dti;
228     HRESULT hres;
229
230     TRACE("(%p)\n", This);
231
232     hres = get_typeinfo(This->data->disp_tid, &dti);
233     if(FAILED(hres)) {
234         ERR("Could not get disp type info: %08x\n", hres);
235         return NULL;
236     }
237
238     data = heap_alloc(sizeof(dispex_data_t));
239     data->func_cnt = 0;
240     data->funcs = heap_alloc(size*sizeof(func_info_t));
241     list_add_tail(&dispex_data_list, &data->entry);
242
243     while(*tid) {
244         hres = get_typeinfo(*tid, &ti);
245         if(FAILED(hres))
246             break;
247
248         i=7;
249         while(1) {
250             hres = ITypeInfo_GetFuncDesc(ti, i++, &funcdesc);
251             if(FAILED(hres))
252                 break;
253
254             add_func_info(data, &size, *tid, funcdesc->memid, dti);
255             ITypeInfo_ReleaseFuncDesc(ti, funcdesc);
256         }
257
258         tid++;
259     }
260
261     if(!data->func_cnt) {
262         heap_free(data->funcs);
263         data->funcs = NULL;
264     }else if(data->func_cnt != size) {
265         data->funcs = heap_realloc(data->funcs, data->func_cnt * sizeof(func_info_t));
266     }
267
268     qsort(data->funcs, data->func_cnt, sizeof(func_info_t), dispid_cmp);
269
270     if(data->funcs) {
271         data->name_table = heap_alloc(data->func_cnt * sizeof(func_info_t*));
272         for(i=0; i < data->func_cnt; i++)
273             data->name_table[i] = data->funcs+i;
274         qsort(data->name_table, data->func_cnt, sizeof(func_info_t*), func_name_cmp);
275     }else {
276         data->name_table = NULL;
277     }
278
279     return data;
280 }
281
282 static CRITICAL_SECTION cs_dispex_static_data;
283 static CRITICAL_SECTION_DEBUG cs_dispex_static_data_dbg =
284 {
285     0, 0, &cs_dispex_static_data,
286     { &cs_dispex_static_data_dbg.ProcessLocksList, &cs_dispex_static_data_dbg.ProcessLocksList },
287       0, 0, { (DWORD_PTR)(__FILE__ ": dispex_static_data") }
288 };
289 static CRITICAL_SECTION cs_dispex_static_data = { &cs_dispex_static_data_dbg, -1, 0, 0, 0, 0 };
290
291
292 static dispex_data_t *get_dispex_data(DispatchEx *This)
293 {
294     if(This->data->data)
295         return This->data->data;
296
297     EnterCriticalSection(&cs_dispex_static_data);
298
299     if(!This->data->data)
300         This->data->data = preprocess_dispex_data(This);
301
302     LeaveCriticalSection(&cs_dispex_static_data);
303
304     return This->data->data;
305 }
306
307 void call_disp_func(HTMLDocument *doc, IDispatch *disp, IDispatch *this_obj)
308 {
309     DISPID named_arg = DISPID_THIS;
310     VARIANTARG arg;
311     DISPPARAMS params = {&arg, &named_arg, 1, 1};
312     EXCEPINFO ei;
313     IDispatchEx *dispex;
314     VARIANT res;
315     HRESULT hres;
316
317     hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
318     if(FAILED(hres)) {
319         FIXME("Could not get IDispatchEx interface: %08x\n", hres);
320         return;
321     }
322
323     V_VT(&arg) = VT_DISPATCH;
324     V_DISPATCH(&arg) = this_obj;
325     VariantInit(&res);
326     memset(&ei, 0, sizeof(ei));
327
328     hres = IDispatchEx_InvokeEx(dispex, 0, GetUserDefaultLCID(), DISPATCH_METHOD, &params, &res, &ei, NULL);
329     IDispatchEx_Release(dispex);
330
331     TRACE("%p returned %08x\n", disp, hres);
332
333     VariantClear(&res);
334 }
335
336 static inline BOOL is_custom_dispid(DISPID id)
337 {
338     return MSHTML_DISPID_CUSTOM_MIN <= id && id <= MSHTML_DISPID_CUSTOM_MAX;
339 }
340
341 static inline BOOL is_dynamic_dispid(DISPID id)
342 {
343     return DISPID_DYNPROP_0 <= id && id <= DISPID_DYNPROP_MAX;
344 }
345
346 static HRESULT get_dynamic_prop(DispatchEx *This, const WCHAR *name, BOOL alloc, dynamic_prop_t **ret)
347 {
348     dispex_dynamic_data_t *data = This->dynamic_data;
349
350     if(data) {
351         unsigned i;
352
353         for(i=0; i < data->prop_cnt; i++) {
354             if(!strcmpW(data->props[i].name, name)) {
355                 *ret = data->props+i;
356                 return S_OK;
357             }
358         }
359     }
360
361     if(alloc) {
362         TRACE("creating dynamic prop %s\n", debugstr_w(name));
363
364         if(!data) {
365             data = This->dynamic_data = heap_alloc_zero(sizeof(dispex_dynamic_data_t));
366             if(!data)
367                 return E_OUTOFMEMORY;
368         }
369
370         if(!data->buf_size) {
371             data->props = heap_alloc(sizeof(dynamic_prop_t)*4);
372             if(!data->props)
373                 return E_OUTOFMEMORY;
374             data->buf_size = 4;
375         }else if(data->buf_size == data->prop_cnt) {
376             dynamic_prop_t *new_props;
377
378             new_props = heap_realloc(data->props, sizeof(dynamic_prop_t)*(data->buf_size<<1));
379             if(!new_props)
380                 return E_OUTOFMEMORY;
381
382             data->props = new_props;
383             data->buf_size <<= 1;
384         }
385
386         data->props[data->prop_cnt].name = heap_strdupW(name);
387         VariantInit(&data->props[data->prop_cnt].var);
388         *ret = data->props + data->prop_cnt++;
389
390         return S_OK;
391     }
392
393     TRACE("not found %s\n", debugstr_w(name));
394     return DISP_E_UNKNOWNNAME;
395 }
396
397 HRESULT dispex_get_dprop_ref(DispatchEx *This, const WCHAR *name, BOOL alloc, VARIANT **ret)
398 {
399     dynamic_prop_t *prop;
400     HRESULT hres;
401
402     hres = get_dynamic_prop(This, name, alloc, &prop);
403     if(FAILED(hres))
404         return hres;
405
406     *ret = &prop->var;
407     return S_OK;
408 }
409
410 #define DISPATCHEX_THIS(iface) DEFINE_THIS(DispatchEx, IDispatchEx, iface)
411
412 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
413 {
414     DispatchEx *This = DISPATCHEX_THIS(iface);
415
416     return IUnknown_QueryInterface(This->outer, riid, ppv);
417 }
418
419 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
420 {
421     DispatchEx *This = DISPATCHEX_THIS(iface);
422
423     return IUnknown_AddRef(This->outer);
424 }
425
426 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
427 {
428     DispatchEx *This = DISPATCHEX_THIS(iface);
429
430     return IUnknown_Release(This->outer);
431 }
432
433 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
434 {
435     DispatchEx *This = DISPATCHEX_THIS(iface);
436
437     TRACE("(%p)->(%p)\n", This, pctinfo);
438
439     *pctinfo = 1;
440     return S_OK;
441 }
442
443 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo,
444                                               LCID lcid, ITypeInfo **ppTInfo)
445 {
446     DispatchEx *This = DISPATCHEX_THIS(iface);
447     HRESULT hres;
448
449     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
450
451     hres = get_typeinfo(This->data->disp_tid, ppTInfo);
452     if(FAILED(hres))
453         return hres;
454
455     ITypeInfo_AddRef(*ppTInfo);
456     return S_OK;
457 }
458
459 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
460                                                 LPOLESTR *rgszNames, UINT cNames,
461                                                 LCID lcid, DISPID *rgDispId)
462 {
463     DispatchEx *This = DISPATCHEX_THIS(iface);
464     UINT i;
465     HRESULT hres;
466
467     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
468           lcid, rgDispId);
469
470     for(i=0; i < cNames; i++) {
471         hres = IDispatchEx_GetDispID(DISPATCHEX(This), rgszNames[i], 0, rgDispId+i);
472         if(FAILED(hres))
473             return hres;
474     }
475
476     return S_OK;
477 }
478
479 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
480                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
481                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
482 {
483     DispatchEx *This = DISPATCHEX_THIS(iface);
484
485     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
486           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
487
488     return IDispatchEx_InvokeEx(DISPATCHEX(This), dispIdMember, lcid, wFlags,
489                                 pDispParams, pVarResult, pExcepInfo, NULL);
490 }
491
492 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
493 {
494     DispatchEx *This = DISPATCHEX_THIS(iface);
495     dynamic_prop_t *dprop;
496     dispex_data_t *data;
497     int min, max, n, c;
498     HRESULT hres;
499
500     TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
501
502     if(grfdex & ~(fdexNameCaseSensitive|fdexNameEnsure|fdexNameImplicit))
503         FIXME("Unsupported grfdex %x\n", grfdex);
504
505     data = get_dispex_data(This);
506     if(!data)
507         return E_FAIL;
508
509     min = 0;
510     max = data->func_cnt-1;
511
512     while(min <= max) {
513         n = (min+max)/2;
514
515         c = strcmpiW(data->name_table[n]->name, bstrName);
516         if(!c) {
517             if((grfdex & fdexNameCaseSensitive) && strcmpW(data->name_table[n]->name, bstrName))
518                 break;
519
520             *pid = data->name_table[n]->id;
521             return S_OK;
522         }
523
524         if(c > 0)
525             max = n-1;
526         else
527             min = n+1;
528     }
529
530     if(This->data->vtbl && This->data->vtbl->get_dispid) {
531         HRESULT hres;
532
533         hres = This->data->vtbl->get_dispid(This->outer, bstrName, grfdex, pid);
534         if(hres != DISP_E_UNKNOWNNAME)
535             return hres;
536     }
537
538     hres = get_dynamic_prop(This, bstrName, grfdex&fdexNameEnsure, &dprop);
539     if(FAILED(hres))
540         return hres;
541
542     *pid = DISPID_DYNPROP_0 + (dprop - This->dynamic_data->props);
543     return S_OK;
544 }
545
546 static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
547         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
548 {
549     DispatchEx *This = DISPATCHEX_THIS(iface);
550     IUnknown *unk;
551     ITypeInfo *ti;
552     dispex_data_t *data;
553     UINT argerr=0;
554     int min, max, n;
555     HRESULT hres;
556
557     TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
558
559     if(is_custom_dispid(id) && This->data->vtbl && This->data->vtbl->invoke)
560         return This->data->vtbl->invoke(This->outer, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
561
562     if(wFlags == DISPATCH_CONSTRUCT) {
563         FIXME("DISPATCH_CONSTRUCT not implemented\n");
564         return E_NOTIMPL;
565     }
566
567     if(is_dynamic_dispid(id)) {
568         DWORD idx = id - DISPID_DYNPROP_0;
569         VARIANT *var;
570
571         if(!This->dynamic_data || This->dynamic_data->prop_cnt <= idx)
572             return DISP_E_UNKNOWNNAME;
573
574         var = &This->dynamic_data->props[idx].var;
575
576         switch(wFlags) {
577         case INVOKE_FUNC: {
578             DISPID named_arg = DISPID_THIS;
579             DISPPARAMS dp = {NULL, &named_arg, 0, 1};
580             IDispatchEx *dispex;
581
582             if(V_VT(var) != VT_DISPATCH) {
583                 FIXME("invoke vt %d\n", V_VT(var));
584                 return E_NOTIMPL;
585             }
586
587             if(pdp->cNamedArgs) {
588                 FIXME("named args not supported\n");
589                 return E_NOTIMPL;
590             }
591
592             dp.rgvarg = heap_alloc((pdp->cArgs+1)*sizeof(VARIANTARG));
593             if(!dp.rgvarg)
594                 return E_OUTOFMEMORY;
595
596             dp.cArgs = pdp->cArgs+1;
597             memcpy(dp.rgvarg+1, pdp->rgvarg, pdp->cArgs*sizeof(VARIANTARG));
598
599             V_VT(dp.rgvarg) = VT_DISPATCH;
600             V_DISPATCH(dp.rgvarg) = (IDispatch*)DISPATCHEX(This);
601
602             hres = IDispatch_QueryInterface(V_DISPATCH(var), &IID_IDispatchEx, (void**)&dispex);
603             TRACE("%s call\n", debugstr_w(This->dynamic_data->props[idx].name));
604             if(SUCCEEDED(hres)) {
605                 hres = IDispatchEx_InvokeEx(dispex, DISPID_VALUE, lcid, wFlags, &dp, pvarRes, pei, pspCaller);
606                 IDispatchEx_Release(dispex);
607             }else {
608                 ULONG err = 0;
609                 hres = IDispatch_Invoke(V_DISPATCH(var), DISPID_VALUE, &IID_NULL, lcid, wFlags, pdp, pvarRes, pei, &err);
610             }
611             TRACE("%s ret %08x\n", debugstr_w(This->dynamic_data->props[idx].name), hres);
612
613             heap_free(dp.rgvarg);
614             return hres;
615         }
616         case INVOKE_PROPERTYGET:
617             return VariantCopy(pvarRes, var);
618         case INVOKE_PROPERTYPUT:
619             VariantClear(var);
620             return VariantCopy(var, pdp->rgvarg);
621         default:
622             FIXME("unhandled wFlags %x\n", wFlags);
623             return E_NOTIMPL;
624         }
625     }
626
627     data = get_dispex_data(This);
628     if(!data)
629         return E_FAIL;
630
631     min = 0;
632     max = data->func_cnt-1;
633
634     while(min <= max) {
635         n = (min+max)/2;
636
637         if(data->funcs[n].id == id)
638             break;
639
640         if(data->funcs[n].id < id)
641             min = n+1;
642         else
643             max = n-1;
644     }
645
646     if(min > max) {
647         WARN("invalid id %x\n", id);
648         return DISP_E_UNKNOWNNAME;
649     }
650
651     hres = get_typeinfo(data->funcs[n].tid, &ti);
652     if(FAILED(hres)) {
653         ERR("Could not get type info: %08x\n", hres);
654         return hres;
655     }
656
657     hres = IUnknown_QueryInterface(This->outer, tid_ids[data->funcs[n].tid], (void**)&unk);
658     if(FAILED(hres)) {
659         ERR("Could not get iface %s: %08x\n", debugstr_guid(tid_ids[data->funcs[n].tid]), hres);
660         return E_FAIL;
661     }
662
663     hres = ITypeInfo_Invoke(ti, unk, id, wFlags, pdp, pvarRes, pei, &argerr);
664
665     IUnknown_Release(unk);
666     return hres;
667 }
668
669 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
670 {
671     DispatchEx *This = DISPATCHEX_THIS(iface);
672     FIXME("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex);
673     return E_NOTIMPL;
674 }
675
676 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
677 {
678     DispatchEx *This = DISPATCHEX_THIS(iface);
679     FIXME("(%p)->(%x)\n", This, id);
680     return E_NOTIMPL;
681 }
682
683 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
684 {
685     DispatchEx *This = DISPATCHEX_THIS(iface);
686     FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex);
687     return E_NOTIMPL;
688 }
689
690 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
691 {
692     DispatchEx *This = DISPATCHEX_THIS(iface);
693     FIXME("(%p)->(%x %p)\n", This, id, pbstrName);
694     return E_NOTIMPL;
695 }
696
697 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
698 {
699     DispatchEx *This = DISPATCHEX_THIS(iface);
700     FIXME("(%p)->(%x %x %p)\n", This, grfdex, id, pid);
701     return E_NOTIMPL;
702 }
703
704 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
705 {
706     DispatchEx *This = DISPATCHEX_THIS(iface);
707     FIXME("(%p)->(%p)\n", This, ppunk);
708     return E_NOTIMPL;
709 }
710
711 #undef DISPATCHEX_THIS
712
713 static IDispatchExVtbl DispatchExVtbl = {
714     DispatchEx_QueryInterface,
715     DispatchEx_AddRef,
716     DispatchEx_Release,
717     DispatchEx_GetTypeInfoCount,
718     DispatchEx_GetTypeInfo,
719     DispatchEx_GetIDsOfNames,
720     DispatchEx_Invoke,
721     DispatchEx_GetDispID,
722     DispatchEx_InvokeEx,
723     DispatchEx_DeleteMemberByName,
724     DispatchEx_DeleteMemberByDispID,
725     DispatchEx_GetMemberProperties,
726     DispatchEx_GetMemberName,
727     DispatchEx_GetNextDispID,
728     DispatchEx_GetNameSpaceParent
729 };
730
731 BOOL dispex_query_interface(DispatchEx *This, REFIID riid, void **ppv)
732 {
733     static const IID IID_UndocumentedScriptIface =
734         {0x719c3050,0xf9d3,0x11cf,{0xa4,0x93,0x00,0x40,0x05,0x23,0xa8,0xa0}};
735     static const IID IID_IDispatchJS =
736         {0x719c3050,0xf9d3,0x11cf,{0xa4,0x93,0x00,0x40,0x05,0x23,0xa8,0xa6}};
737
738     if(IsEqualGUID(&IID_IDispatch, riid)) {
739         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
740         *ppv = DISPATCHEX(This);
741     }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
742         TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
743         *ppv = DISPATCHEX(This);
744     }else if(IsEqualGUID(&IID_IDispatchJS, riid)) {
745         TRACE("(%p)->(IID_IDispatchJS %p) returning NULL\n", This, ppv);
746         *ppv = NULL;
747     }else if(IsEqualGUID(&IID_UndocumentedScriptIface, riid)) {
748         TRACE("(%p)->(IID_UndocumentedScriptIface %p) returning NULL\n", This, ppv);
749         *ppv = NULL;
750     }else {
751         return FALSE;
752     }
753
754     if(*ppv)
755         IUnknown_AddRef((IUnknown*)*ppv);
756     return TRUE;
757 }
758
759 void init_dispex(DispatchEx *dispex, IUnknown *outer, dispex_static_data_t *data)
760 {
761     dispex->lpIDispatchExVtbl = &DispatchExVtbl;
762     dispex->outer = outer;
763     dispex->data = data;
764 }