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