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
28 #include "wine/debug.h"
30 #include "mshtml_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(mshtml
);
40 struct dispex_data_t
{
43 func_info_t
**name_table
;
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
[] = {
54 &DIID_DispHTMLDocument
,
55 &DIID_DispHTMLWindow2
,
65 HRESULT
get_typeinfo(tid_t tid
, ITypeInfo
**typeinfo
)
72 hres
= LoadRegTypeLib(&LIBID_MSHTML
, 4, 0, LOCALE_SYSTEM_DEFAULT
, &tl
);
74 ERR("LoadRegTypeLib failed: %08x\n", hres
);
78 if(InterlockedCompareExchangePointer((void**)&typelib
, tl
, NULL
))
85 hres
= ITypeLib_GetTypeInfoOfGuid(typelib
, tid_ids
[tid
], &typeinfo
);
87 ERR("GetTypeInfoOfGuid(%s) failed: %08x\n", debugstr_guid(tid_ids
[tid
]), hres
);
91 if(InterlockedCompareExchangePointer((void**)(typeinfos
+tid
), typeinfo
, NULL
))
92 ITypeInfo_Release(typeinfo
);
95 *typeinfo
= typeinfos
[tid
];
99 void release_typelib(void)
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
);
119 for(i
=0; i
< sizeof(typeinfos
)/sizeof(*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
)
130 if(data
->func_cnt
&& data
->funcs
[data
->func_cnt
-1].id
== id
)
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
);
140 data
->funcs
[data
->func_cnt
].id
= id
;
141 data
->funcs
[data
->func_cnt
].tid
= tid
;
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
;
165 TRACE("(%p)\n", This
);
167 hres
= get_typeinfo(This
->data
->disp_tid
, &dti
);
169 ERR("Could not get disp type info: %08x\n", hres
);
173 data
= heap_alloc(sizeof(dispex_data_t
));
175 data
->funcs
= heap_alloc(size
*sizeof(func_info_t
));
176 list_add_tail(&dispex_data_list
, &data
->entry
);
179 hres
= get_typeinfo(*tid
, &ti
);
185 hres
= ITypeInfo_GetFuncDesc(ti
, i
++, &funcdesc
);
189 add_func_info(data
, &size
, *tid
, funcdesc
->memid
, dti
);
190 ITypeInfo_ReleaseFuncDesc(ti
, funcdesc
);
196 if(!data
->func_cnt
) {
197 heap_free(data
->funcs
);
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
);
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
);
211 data
->name_table
= NULL
;
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
)
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
;
246 DISPPARAMS params
= {&arg
, &named_arg
, 1, 1};
252 hres
= IDispatch_QueryInterface(disp
, &IID_IDispatchEx
, (void**)&dispex
);
254 FIXME("Could not get IDispatchEx interface: %08x\n", hres
);
258 V_VT(&arg
) = VT_DISPATCH
;
259 V_DISPATCH(&arg
) = (IDispatch
*)HTMLWINDOW2(doc
->window
);
261 memset(&ei
, 0, sizeof(ei
));
263 hres
= IDispatchEx_InvokeEx(dispex
, 0, GetUserDefaultLCID(), DISPATCH_METHOD
, ¶ms
, &res
, &ei
, NULL
);
264 IDispatchEx_Release(dispex
);
266 TRACE("%p returned %08x\n", disp
, hres
);
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
);
304 static HRESULT WINAPI
DispatchEx_GetTypeInfo(IDispatchEx
*iface
, UINT iTInfo
,
305 LCID lcid
, ITypeInfo
**ppTInfo
)
307 DispatchEx
*This
= DISPATCHEX_THIS(iface
);
310 TRACE("(%p)->(%u %u %p)\n", This
, iTInfo
, lcid
, ppTInfo
);
312 hres
= get_typeinfo(This
->data
->disp_tid
, ppTInfo
);
316 ITypeInfo_AddRef(*ppTInfo
);
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
);
328 TRACE("(%p)->(%s %p %u %u %p)\n", This
, debugstr_guid(riid
), rgszNames
, cNames
,
331 for(i
=0; i
< cNames
; i
++) {
332 hres
= IDispatchEx_GetDispID(DISPATCHEX(This
), rgszNames
[i
], 0, rgDispId
+i
);
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
);
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
);
369 max
= data
->func_cnt
-1;
374 c
= strcmpiW(data
->name_table
[n
]->name
, bstrName
);
376 if((grfdex
& fdexNameCaseSensitive
) && strcmpW(data
->name_table
[n
]->name
, bstrName
))
379 *pid
= data
->name_table
[n
]->id
;
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
);
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");
411 data
= get_dispex_data(This
);
416 max
= data
->func_cnt
-1;
421 if(data
->funcs
[n
].id
== id
)
424 if(data
->funcs
[n
].id
< id
)
431 WARN("invalid id %x\n", id
);
432 return DISP_E_UNKNOWNNAME
;
435 hres
= get_typeinfo(data
->funcs
[n
].tid
, &ti
);
437 ERR("Could not get type info: %08x\n", hres
);
441 hres
= IUnknown_QueryInterface(This
->outer
, tid_ids
[data
->funcs
[n
].tid
], (void**)&unk
);
443 ERR("Could not get iface: %08x\n", hres
);
447 hres
= ITypeInfo_Invoke(ti
, unk
, id
, wFlags
, pdp
, pvarRes
, pei
, &argerr
);
449 IUnknown_Release(unk
);
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
);
460 static HRESULT WINAPI
DispatchEx_DeleteMemberByDispID(IDispatchEx
*iface
, DISPID id
)
462 DispatchEx
*This
= DISPATCHEX_THIS(iface
);
463 FIXME("(%p)->(%x)\n", This
, id
);
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
);
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
);
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
);
488 static HRESULT WINAPI
DispatchEx_GetNameSpaceParent(IDispatchEx
*iface
, IUnknown
**ppunk
)
490 DispatchEx
*This
= DISPATCHEX_THIS(iface
);
491 FIXME("(%p)->(%p)\n", This
, ppunk
);
495 #undef DISPATCHEX_THIS
497 static IDispatchExVtbl DispatchExVtbl
= {
498 DispatchEx_QueryInterface
,
501 DispatchEx_GetTypeInfoCount
,
502 DispatchEx_GetTypeInfo
,
503 DispatchEx_GetIDsOfNames
,
505 DispatchEx_GetDispID
,
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
;