diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 7dc00637764..647b4d82a4a 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -31,11 +31,28 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml); +typedef struct { + DISPID id; + BSTR name; + tid_t tid; +} func_info_t; + +struct dispex_data_t { + DWORD func_cnt; + func_info_t *funcs; + func_info_t **name_table; + + struct list entry; +}; + static ITypeLib *typelib; static ITypeInfo *typeinfos[LAST_tid]; +static struct list dispex_data_list = LIST_INIT(dispex_data_list); static REFIID tid_ids[] = { + &IID_NULL, &IID_IHTMLWindow2, + &IID_IOmNavigator }; HRESULT get_typeinfo(tid_t tid, ITypeInfo **typeinfo) @@ -60,7 +77,7 @@ HRESULT get_typeinfo(tid_t tid, ITypeInfo **typeinfo) hres = ITypeLib_GetTypeInfoOfGuid(typelib, tid_ids[tid], &typeinfo); if(FAILED(hres)) { - ERR("GetTypeInfoOfGuid failed: %08x\n", hres); + ERR("GetTypeInfoOfGuid(%s) failed: %08x\n", debugstr_guid(tid_ids[tid]), hres); return hres; } @@ -74,8 +91,21 @@ HRESULT get_typeinfo(tid_t tid, ITypeInfo **typeinfo) void release_typelib(void) { + dispex_data_t *iter; unsigned i; + while(!list_empty(&dispex_data_list)) { + iter = LIST_ENTRY(list_head(&dispex_data_list), dispex_data_t, entry); + list_remove(&iter->entry); + + for(i=0; i < iter->func_cnt; i++) + SysFreeString(iter->funcs[i].name); + + heap_free(iter->funcs); + heap_free(iter->name_table); + heap_free(iter); + } + if(!typelib) return; @@ -86,6 +116,122 @@ void release_typelib(void) ITypeLib_Release(typelib); } +static void add_func_info(dispex_data_t *data, DWORD *size, tid_t tid, DISPID id, ITypeInfo *dti) +{ + HRESULT hres; + + if(data->func_cnt && data->funcs[data->func_cnt-1].id == id) + return; + + if(data->func_cnt == *size) + data->funcs = heap_realloc(data->funcs, (*size <<= 1)*sizeof(func_info_t)); + + hres = ITypeInfo_GetDocumentation(dti, id, &data->funcs[data->func_cnt].name, NULL, NULL, NULL); + if(FAILED(hres)) + return; + + data->funcs[data->func_cnt].id = id; + data->funcs[data->func_cnt].tid = tid; + + data->func_cnt++; +} + +static int dispid_cmp(const void *p1, const void *p2) +{ + return ((func_info_t*)p1)->id - ((func_info_t*)p2)->id; +} + +static int func_name_cmp(const void *p1, const void *p2) +{ + return strcmpiW((*(func_info_t**)p1)->name, (*(func_info_t**)p2)->name); +} + +static dispex_data_t *preprocess_dispex_data(DispatchEx *This) +{ + const tid_t *tid = This->data->iface_tids; + FUNCDESC *funcdesc; + dispex_data_t *data; + DWORD size = 16, i; + ITypeInfo *ti, *dti; + HRESULT hres; + + TRACE("(%p)\n", This); + + hres = get_typeinfo(This->data->disp_tid, &dti); + if(FAILED(hres)) { + ERR("Could not get disp type info: %08x\n", hres); + return NULL; + } + + data = heap_alloc(sizeof(dispex_data_t)); + data->func_cnt = 0; + data->funcs = heap_alloc(size*sizeof(func_info_t)); + list_add_tail(&dispex_data_list, &data->entry); + + while(*tid) { + hres = get_typeinfo(*tid, &ti); + if(FAILED(hres)) + break; + + i=7; + while(1) { + hres = ITypeInfo_GetFuncDesc(ti, i++, &funcdesc); + if(FAILED(hres)) + break; + + add_func_info(data, &size, *tid, funcdesc->memid, dti); + ITypeInfo_ReleaseFuncDesc(ti, funcdesc); + } + + tid++; + } + + if(!data->func_cnt) { + heap_free(data->funcs); + data->funcs = NULL; + }else if(data->func_cnt != size) { + data->funcs = heap_realloc(data->funcs, data->func_cnt * sizeof(func_info_t)); + } + + qsort(data->funcs, data->func_cnt, sizeof(func_info_t), dispid_cmp); + + if(data->funcs) { + data->name_table = heap_alloc(data->func_cnt * sizeof(func_info_t*)); + for(i=0; i < data->func_cnt; i++) + data->name_table[i] = data->funcs+i; + qsort(data->name_table, data->func_cnt, sizeof(func_info_t*), func_name_cmp); + }else { + data->name_table = NULL; + } + + return data; +} + +static CRITICAL_SECTION cs_dispex_static_data; +static CRITICAL_SECTION_DEBUG cs_dispex_static_data_dbg = +{ + 0, 0, &cs_dispex_static_data, + { &cs_dispex_static_data_dbg.ProcessLocksList, &cs_dispex_static_data_dbg.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": dispex_static_data") } +}; +static CRITICAL_SECTION cs_dispex_static_data = { &cs_dispex_static_data_dbg, -1, 0, 0, 0, 0 }; + + +static dispex_data_t *get_dispex_data(DispatchEx *This) +{ + if(This->data->data) + return This->data->data; + + EnterCriticalSection(&cs_dispex_static_data); + + if(!This->data->data) + This->data->data = preprocess_dispex_data(This); + + LeaveCriticalSection(&cs_dispex_static_data); + + return This->data->data; +} + void call_disp_func(HTMLDocument *doc, IDispatch *disp) { DISPID named_arg = DISPID_THIS; @@ -152,8 +298,16 @@ static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { DispatchEx *This = DISPATCHEX_THIS(iface); - FIXME("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); - return E_NOTIMPL; + HRESULT hres; + + TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo); + + hres = get_typeinfo(This->data->disp_tid, ppTInfo); + if(FAILED(hres)) + return hres; + + ITypeInfo_AddRef(*ppTInfo); + return S_OK; } static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid, @@ -179,8 +333,41 @@ static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) { DispatchEx *This = DISPATCHEX_THIS(iface); - FIXME("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid); - return E_NOTIMPL; + dispex_data_t *data; + int min, max, n, c; + + TRACE("(%p)->(%s %x %p)\n", This, debugstr_w(bstrName), grfdex, pid); + + if(grfdex & (~fdexNameCaseSensitive)) + FIXME("Unsupported grfdex %x\n", grfdex); + + data = get_dispex_data(This); + if(!data) + return E_FAIL; + + min = 0; + max = data->func_cnt-1; + + while(min <= max) { + n = (min+max)/2; + + c = strcmpiW(data->name_table[n]->name, bstrName); + if(!c) { + if((grfdex & fdexNameCaseSensitive) && strcmpW(data->name_table[n]->name, bstrName)) + break; + + *pid = data->name_table[n]->id; + return S_OK; + } + + if(c > 0) + max = n-1; + else + min = n+1; + } + + TRACE("not found %s\n", debugstr_w(bstrName)); + return DISP_E_UNKNOWNNAME; } static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, @@ -253,8 +440,9 @@ static IDispatchExVtbl DispatchExVtbl = { DispatchEx_GetNameSpaceParent }; -void init_dispex(DispatchEx *dispex, IUnknown *outer) +void init_dispex(DispatchEx *dispex, IUnknown *outer, dispex_static_data_t *data) { dispex->lpIDispatchExVtbl = &DispatchExVtbl; dispex->outer = outer; + dispex->data = data; } diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 48f3b1bf9f8..e0f28c76a8c 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -60,17 +60,29 @@ typedef struct event_target_t event_target_t; /* NOTE: make sure to keep in sync with dispex.c */ typedef enum { + NULL_tid, IHTMLWindow2_tid, + IOmNavigator_tid, LAST_tid } tid_t; +typedef struct dispex_data_t dispex_data_t; + +typedef struct { + const tid_t disp_tid; + dispex_data_t *data; + const tid_t iface_tids[]; +} dispex_static_data_t; + typedef struct { const IDispatchExVtbl *lpIDispatchExVtbl; IUnknown *outer; + + dispex_static_data_t *data; } DispatchEx; -void init_dispex(DispatchEx*,IUnknown*); +void init_dispex(DispatchEx*,IUnknown*,dispex_static_data_t*); typedef struct { const IHTMLWindow2Vtbl *lpHTMLWindow2Vtbl; diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 1a1e7e8bea4..7f7e8c0c447 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -301,6 +301,15 @@ static const IOmNavigatorVtbl OmNavigatorVtbl = { OmNavigator_get_userProfile }; +static dispex_static_data_t OmNavigator_dispex = { + IOmNavigator_tid, + NULL, + { + IOmNavigator_tid, + 0 + } +}; + IOmNavigator *OmNavigator_Create(void) { OmNavigator *ret; @@ -309,7 +318,7 @@ IOmNavigator *OmNavigator_Create(void) ret->lpIOmNavigatorVtbl = &OmNavigatorVtbl; ret->ref = 1; - init_dispex(&ret->dispex, (IUnknown*)OMNAVIGATOR(ret)); + init_dispex(&ret->dispex, (IUnknown*)OMNAVIGATOR(ret), &OmNavigator_dispex); return OMNAVIGATOR(ret); }