mshtml: Added HTMLDocument's IDispatchEx implementation.
[wine/wine-kai.git] / dlls / mshtml / dispex.c
blob26be1e8e7e0e26dad62bb1ab2cc1c1f6be6d36fa
1 /*
2 * Copyright 2008 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 <stdarg.h>
21 #define COBJMACROS
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "ole2.h"
28 #include "wine/debug.h"
30 #include "mshtml_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
34 typedef struct {
35 DISPID id;
36 BSTR name;
37 tid_t tid;
38 } func_info_t;
40 struct dispex_data_t {
41 DWORD func_cnt;
42 func_info_t *funcs;
43 func_info_t **name_table;
45 struct list entry;
48 static ITypeLib *typelib;
49 static ITypeInfo *typeinfos[LAST_tid];
50 static struct list dispex_data_list = LIST_INIT(dispex_data_list);
52 static REFIID tid_ids[] = {
53 &IID_NULL,
54 &DIID_DispHTMLDocument,
55 &DIID_DispHTMLWindow2,
56 &IID_IHTMLDocument2,
57 &IID_IHTMLDocument3,
58 &IID_IHTMLDocument4,
59 &IID_IHTMLDocument5,
60 &IID_IHTMLWindow2,
61 &IID_IHTMLWindow3,
62 &IID_IOmNavigator
65 HRESULT get_typeinfo(tid_t tid, ITypeInfo **typeinfo)
67 HRESULT hres;
69 if(!typelib) {
70 ITypeLib *tl;
72 hres = LoadRegTypeLib(&LIBID_MSHTML, 4, 0, LOCALE_SYSTEM_DEFAULT, &tl);
73 if(FAILED(hres)) {
74 ERR("LoadRegTypeLib failed: %08x\n", hres);
75 return hres;
78 if(InterlockedCompareExchangePointer((void**)&typelib, tl, NULL))
79 ITypeLib_Release(tl);
82 if(!typeinfos[tid]) {
83 ITypeInfo *typeinfo;
85 hres = ITypeLib_GetTypeInfoOfGuid(typelib, tid_ids[tid], &typeinfo);
86 if(FAILED(hres)) {
87 ERR("GetTypeInfoOfGuid(%s) failed: %08x\n", debugstr_guid(tid_ids[tid]), hres);
88 return hres;
91 if(InterlockedCompareExchangePointer((void**)(typeinfos+tid), typeinfo, NULL))
92 ITypeInfo_Release(typeinfo);
95 *typeinfo = typeinfos[tid];
96 return S_OK;
99 void release_typelib(void)
101 dispex_data_t *iter;
102 unsigned i;
104 while(!list_empty(&dispex_data_list)) {
105 iter = LIST_ENTRY(list_head(&dispex_data_list), dispex_data_t, entry);
106 list_remove(&iter->entry);
108 for(i=0; i < iter->func_cnt; i++)
109 SysFreeString(iter->funcs[i].name);
111 heap_free(iter->funcs);
112 heap_free(iter->name_table);
113 heap_free(iter);
116 if(!typelib)
117 return;
119 for(i=0; i < sizeof(typeinfos)/sizeof(*typeinfos); i++)
120 if(typeinfos[i])
121 ITypeInfo_Release(typeinfos[i]);
123 ITypeLib_Release(typelib);
126 static void add_func_info(dispex_data_t *data, DWORD *size, tid_t tid, DISPID id, ITypeInfo *dti)
128 HRESULT hres;
130 if(data->func_cnt && data->funcs[data->func_cnt-1].id == id)
131 return;
133 if(data->func_cnt == *size)
134 data->funcs = heap_realloc(data->funcs, (*size <<= 1)*sizeof(func_info_t));
136 hres = ITypeInfo_GetDocumentation(dti, id, &data->funcs[data->func_cnt].name, NULL, NULL, NULL);
137 if(FAILED(hres))
138 return;
140 data->funcs[data->func_cnt].id = id;
141 data->funcs[data->func_cnt].tid = tid;
143 data->func_cnt++;
146 static int dispid_cmp(const void *p1, const void *p2)
148 return ((func_info_t*)p1)->id - ((func_info_t*)p2)->id;
151 static int func_name_cmp(const void *p1, const void *p2)
153 return strcmpiW((*(func_info_t**)p1)->name, (*(func_info_t**)p2)->name);
156 static dispex_data_t *preprocess_dispex_data(DispatchEx *This)
158 const tid_t *tid = This->data->iface_tids;
159 FUNCDESC *funcdesc;
160 dispex_data_t *data;
161 DWORD size = 16, i;
162 ITypeInfo *ti, *dti;
163 HRESULT hres;
165 TRACE("(%p)\n", This);
167 hres = get_typeinfo(This->data->disp_tid, &dti);
168 if(FAILED(hres)) {
169 ERR("Could not get disp type info: %08x\n", hres);
170 return NULL;
173 data = heap_alloc(sizeof(dispex_data_t));
174 data->func_cnt = 0;
175 data->funcs = heap_alloc(size*sizeof(func_info_t));
176 list_add_tail(&dispex_data_list, &data->entry);
178 while(*tid) {
179 hres = get_typeinfo(*tid, &ti);
180 if(FAILED(hres))
181 break;
183 i=7;
184 while(1) {
185 hres = ITypeInfo_GetFuncDesc(ti, i++, &funcdesc);
186 if(FAILED(hres))
187 break;
189 add_func_info(data, &size, *tid, funcdesc->memid, dti);
190 ITypeInfo_ReleaseFuncDesc(ti, funcdesc);
193 tid++;
196 if(!data->func_cnt) {
197 heap_free(data->funcs);
198 data->funcs = NULL;
199 }else if(data->func_cnt != size) {
200 data->funcs = heap_realloc(data->funcs, data->func_cnt * sizeof(func_info_t));
203 qsort(data->funcs, data->func_cnt, sizeof(func_info_t), dispid_cmp);
205 if(data->funcs) {
206 data->name_table = heap_alloc(data->func_cnt * sizeof(func_info_t*));
207 for(i=0; i < data->func_cnt; i++)
208 data->name_table[i] = data->funcs+i;
209 qsort(data->name_table, data->func_cnt, sizeof(func_info_t*), func_name_cmp);
210 }else {
211 data->name_table = NULL;
214 return data;
217 static CRITICAL_SECTION cs_dispex_static_data;
218 static CRITICAL_SECTION_DEBUG cs_dispex_static_data_dbg =
220 0, 0, &cs_dispex_static_data,
221 { &cs_dispex_static_data_dbg.ProcessLocksList, &cs_dispex_static_data_dbg.ProcessLocksList },
222 0, 0, { (DWORD_PTR)(__FILE__ ": dispex_static_data") }
224 static CRITICAL_SECTION cs_dispex_static_data = { &cs_dispex_static_data_dbg, -1, 0, 0, 0, 0 };
227 static dispex_data_t *get_dispex_data(DispatchEx *This)
229 if(This->data->data)
230 return This->data->data;
232 EnterCriticalSection(&cs_dispex_static_data);
234 if(!This->data->data)
235 This->data->data = preprocess_dispex_data(This);
237 LeaveCriticalSection(&cs_dispex_static_data);
239 return This->data->data;
242 void call_disp_func(HTMLDocument *doc, IDispatch *disp)
244 DISPID named_arg = DISPID_THIS;
245 VARIANTARG arg;
246 DISPPARAMS params = {&arg, &named_arg, 1, 1};
247 EXCEPINFO ei;
248 IDispatchEx *dispex;
249 VARIANT res;
250 HRESULT hres;
252 hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex);
253 if(FAILED(hres)) {
254 FIXME("Could not get IDispatchEx interface: %08x\n", hres);
255 return;
258 V_VT(&arg) = VT_DISPATCH;
259 V_DISPATCH(&arg) = (IDispatch*)HTMLWINDOW2(doc->window);
260 VariantInit(&res);
261 memset(&ei, 0, sizeof(ei));
263 hres = IDispatchEx_InvokeEx(dispex, 0, GetUserDefaultLCID(), DISPATCH_METHOD, &params, &res, &ei, NULL);
264 IDispatchEx_Release(dispex);
266 TRACE("%p returned %08x\n", disp, hres);
268 VariantClear(&res);
271 #define DISPATCHEX_THIS(iface) DEFINE_THIS(DispatchEx, IDispatchEx, iface)
273 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
275 DispatchEx *This = DISPATCHEX_THIS(iface);
277 return IUnknown_QueryInterface(This->outer, riid, ppv);
280 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
282 DispatchEx *This = DISPATCHEX_THIS(iface);
284 return IUnknown_AddRef(This->outer);
287 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
289 DispatchEx *This = DISPATCHEX_THIS(iface);
291 return IUnknown_Release(This->outer);
294 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
296 DispatchEx *This = DISPATCHEX_THIS(iface);
298 TRACE("(%p)->(%p)\n", This, pctinfo);
300 *pctinfo = 1;
301 return S_OK;
304 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo,
305 LCID lcid, ITypeInfo **ppTInfo)
307 DispatchEx *This = DISPATCHEX_THIS(iface);
308 HRESULT hres;
310 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
312 hres = get_typeinfo(This->data->disp_tid, ppTInfo);
313 if(FAILED(hres))
314 return hres;
316 ITypeInfo_AddRef(*ppTInfo);
317 return S_OK;
320 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
321 LPOLESTR *rgszNames, UINT cNames,
322 LCID lcid, DISPID *rgDispId)
324 DispatchEx *This = DISPATCHEX_THIS(iface);
325 UINT i;
326 HRESULT hres;
328 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
329 lcid, rgDispId);
331 for(i=0; i < cNames; i++) {
332 hres = IDispatchEx_GetDispID(DISPATCHEX(This), rgszNames[i], 0, rgDispId+i);
333 if(FAILED(hres))
334 return hres;
337 return S_OK;
340 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
341 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
342 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
344 DispatchEx *This = DISPATCHEX_THIS(iface);
346 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
347 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
349 return IDispatchEx_InvokeEx(DISPATCHEX(This), dispIdMember, lcid, wFlags,
350 pDispParams, pVarResult, pExcepInfo, NULL);
353 static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
355 DispatchEx *This = DISPATCHEX_THIS(iface);
356 dispex_data_t *data;
357 int min, max, n, c;
359 TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid);
361 if(grfdex & (~fdexNameCaseSensitive))
362 FIXME("Unsupported grfdex %x\n", grfdex);
364 data = get_dispex_data(This);
365 if(!data)
366 return E_FAIL;
368 min = 0;
369 max = data->func_cnt-1;
371 while(min <= max) {
372 n = (min+max)/2;
374 c = strcmpiW(data->name_table[n]->name, bstrName);
375 if(!c) {
376 if((grfdex & fdexNameCaseSensitive) && strcmpW(data->name_table[n]->name, bstrName))
377 break;
379 *pid = data->name_table[n]->id;
380 return S_OK;
383 if(c > 0)
384 max = n-1;
385 else
386 min = n+1;
389 TRACE("not found %s\n", debugstr_w(bstrName));
390 return DISP_E_UNKNOWNNAME;
393 static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
394 VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
396 DispatchEx *This = DISPATCHEX_THIS(iface);
397 IUnknown *unk;
398 ITypeInfo *ti;
399 dispex_data_t *data;
400 UINT argerr=0;
401 int min, max, n;
402 HRESULT hres;
404 TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
406 if(wFlags == DISPATCH_CONSTRUCT) {
407 FIXME("DISPATCH_CONSTRUCT not implemented\n");
408 return E_NOTIMPL;
411 data = get_dispex_data(This);
412 if(!data)
413 return E_FAIL;
415 min = 0;
416 max = data->func_cnt-1;
418 while(min <= max) {
419 n = (min+max)/2;
421 if(data->funcs[n].id == id)
422 break;
424 if(data->funcs[n].id < id)
425 min = n+1;
426 else
427 max = n-1;
430 if(min > max) {
431 WARN("invalid id %x\n", id);
432 return DISP_E_UNKNOWNNAME;
435 hres = get_typeinfo(data->funcs[n].tid, &ti);
436 if(FAILED(hres)) {
437 ERR("Could not get type info: %08x\n", hres);
438 return hres;
441 hres = IUnknown_QueryInterface(This->outer, tid_ids[data->funcs[n].tid], (void**)&unk);
442 if(FAILED(hres)) {
443 ERR("Could not get iface: %08x\n", hres);
444 return E_FAIL;
447 hres = ITypeInfo_Invoke(ti, unk, id, wFlags, pdp, pvarRes, pei, &argerr);
449 IUnknown_Release(unk);
450 return hres;
453 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
455 DispatchEx *This = DISPATCHEX_THIS(iface);
456 FIXME("(%p)->(%s %x)\n", This, debugstr_w(bstrName), grfdex);
457 return E_NOTIMPL;
460 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
462 DispatchEx *This = DISPATCHEX_THIS(iface);
463 FIXME("(%p)->(%x)\n", This, id);
464 return E_NOTIMPL;
467 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
469 DispatchEx *This = DISPATCHEX_THIS(iface);
470 FIXME("(%p)->(%x %x %p)\n", This, id, grfdexFetch, pgrfdex);
471 return E_NOTIMPL;
474 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
476 DispatchEx *This = DISPATCHEX_THIS(iface);
477 FIXME("(%p)->(%x %p)\n", This, id, pbstrName);
478 return E_NOTIMPL;
481 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
483 DispatchEx *This = DISPATCHEX_THIS(iface);
484 FIXME("(%p)->(%x %x %p)\n", This, grfdex, id, pid);
485 return E_NOTIMPL;
488 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
490 DispatchEx *This = DISPATCHEX_THIS(iface);
491 FIXME("(%p)->(%p)\n", This, ppunk);
492 return E_NOTIMPL;
495 #undef DISPATCHEX_THIS
497 static IDispatchExVtbl DispatchExVtbl = {
498 DispatchEx_QueryInterface,
499 DispatchEx_AddRef,
500 DispatchEx_Release,
501 DispatchEx_GetTypeInfoCount,
502 DispatchEx_GetTypeInfo,
503 DispatchEx_GetIDsOfNames,
504 DispatchEx_Invoke,
505 DispatchEx_GetDispID,
506 DispatchEx_InvokeEx,
507 DispatchEx_DeleteMemberByName,
508 DispatchEx_DeleteMemberByDispID,
509 DispatchEx_GetMemberProperties,
510 DispatchEx_GetMemberName,
511 DispatchEx_GetNextDispID,
512 DispatchEx_GetNameSpaceParent
515 void init_dispex(DispatchEx *dispex, IUnknown *outer, dispex_static_data_t *data)
517 dispex->lpIDispatchExVtbl = &DispatchExVtbl;
518 dispex->outer = outer;
519 dispex->data = data;