Currently the treeview items do not change selection when back or forward buttons are clicked. The DoSync function also needed to be changed because the paths to the htm files in the .chm don't line up with the path to the .chm, especially if the .chm is not in the same path as hh.exe.
-- v5: hhctrl.ocx: Selection of treeview items in the content tab should reflect web browser page.
From: Jacob Czekalla jczekalla@codeweavers.com
Currently the treeview items do not change selection when back or forward buttons are clicked. --- dlls/hhctrl.ocx/help.c | 164 ++++++++++++++++++++++++++++++++--- dlls/hhctrl.ocx/hhctrl.h | 13 +++ dlls/hhctrl.ocx/webbrowser.c | 2 + 3 files changed, 168 insertions(+), 11 deletions(-)
diff --git a/dlls/hhctrl.ocx/help.c b/dlls/hhctrl.ocx/help.c index 413659c7097..4eacb07d53c 100644 --- a/dlls/hhctrl.ocx/help.c +++ b/dlls/hhctrl.ocx/help.c @@ -25,6 +25,7 @@ #include "wingdi.h" #include "commctrl.h" #include "wininet.h" +#include "exdispid.h"
#include "wine/debug.h"
@@ -258,12 +259,21 @@ BOOL NavigateToChm(HHInfo *info, LPCWSTR file, LPCWSTR index) return SUCCEEDED(navigate_url(info, buf)); }
-static void DoSync(HHInfo *info) +static BOOL is_chm(WCHAR *url) { - WCHAR buf[INTERNET_MAX_URL_LENGTH]; + const WCHAR *prefix = L"mk:@MSITStore:"; + return !wcsncmp(url, prefix, wcslen(prefix)); +} + +static void DoSyncContent(HHInfo *info) +{ + const WCHAR *index; HRESULT hres; BSTR url;
+ if (info->current_tab != TAB_CONTENTS) + return; + hres = IWebBrowser2_get_LocationURL(info->web_browser->web_browser, &url);
if (FAILED(hres)) @@ -272,24 +282,123 @@ static void DoSync(HHInfo *info) return; }
- /* If we're not currently viewing a page in the active .chm file, abort */ - if ((!AppendFullPathURL(info->WinType.pszFile, buf, NULL)) || (lstrlenW(buf) > lstrlenW(url))) + /* If we're not currently viewing a page in a .chm file, abort */ + if (!is_chm(url)) { SysFreeString(url); return; }
- if (lstrcmpiW(buf, url) > 0) + index = wcsstr(url, L"::/"); + + if (index) + ActivateContentTopic(info->tabs[TAB_CONTENTS].hwnd, index + 3, info->content); /* skip over ::/ */ + + SysFreeString(url); +} + +static HRESULT WINAPI WebBrowserEvents2_QueryInterface(IDispatch *iface, REFIID riid, void **v) +{ + *v = NULL; + + if (IsEqualGUID(&IID_IDispatch, riid) || IsEqualGUID(&IID_IUnknown, riid)) + { + *v = iface; + IDispatch_AddRef(iface); + return S_OK; + } + + return E_NOINTERFACE; +} + +static inline WebBrowserEvents2Impl *impl_from_IDispatch(IDispatch *iface) +{ + return CONTAINING_RECORD(iface, WebBrowserEvents2Impl, WebBrowserEvents2Impl_iface); +} + +static ULONG WINAPI WebBrowserEvents2_AddRef(IDispatch *iface) +{ + WebBrowserEvents2Impl *impl = impl_from_IDispatch(iface); + return InterlockedIncrement(&impl->ref); +} + +static ULONG WINAPI WebBrowserEvents2_Release(IDispatch *iface) +{ + WebBrowserEvents2Impl *impl = impl_from_IDispatch(iface); + ULONG ref = InterlockedDecrement(&impl->ref); + + if (!ref) + free(impl); + return ref; +} + +static HRESULT WINAPI WebBrowserEvents2_GetTypeInfoCount(IDispatch *iface, UINT *pctinfo) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI WebBrowserEvents2_GetTypeInfo(IDispatch *iface, UINT iTInfo, LCID lcid, + ITypeInfo **ppTInfo) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI WebBrowserEvents2_GetIDsOfNames(IDispatch *iface, REFIID riid, LPOLESTR *rgszNames, + UINT cNames, LCID lcid, DISPID *rgDispId) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI WebBrowserEvents2_Invoke(IDispatch *iface, DISPID dispIdMember, REFIID riid, + LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + if (dispIdMember == DISPID_NAVIGATECOMPLETE2) { - const WCHAR *index; + WebBrowserEvents2Impl *impl = impl_from_IDispatch(iface); + DoSyncContent((HHInfo *)impl->info); + } + return S_OK; +} + +static const IDispatchVtbl WebBrowserEvents2Vtbl = +{ + WebBrowserEvents2_QueryInterface, + WebBrowserEvents2_AddRef, + WebBrowserEvents2_Release, + WebBrowserEvents2_GetTypeInfoCount, + WebBrowserEvents2_GetTypeInfo, + WebBrowserEvents2_GetIDsOfNames, + WebBrowserEvents2_Invoke +}; + +static void hook_WebBrowserEvents2(HHInfo *info, BOOL init) +{ + IConnectionPointContainer *container; + IConnectionPoint *point; + HRESULT hres;
- index = wcsstr(url, L"::/"); + hres = IWebBrowser2_QueryInterface(info->web_browser->web_browser, &IID_IConnectionPointContainer, (void **)&container); + if (FAILED(hres)) + return;
- if (index) - ActivateContentTopic(info->tabs[TAB_CONTENTS].hwnd, index + 3, info->content); /* skip over ::/ */ + hres = IConnectionPointContainer_FindConnectionPoint(container, &DIID_DWebBrowserEvents2, &point); + IConnectionPointContainer_Release(container); + if (FAILED(hres)) + return; + + if (init) + { + info->web_browser->WebBrowser_events_sink = malloc(sizeof(*(info->web_browser->WebBrowser_events_sink))); + info->web_browser->WebBrowser_events_sink->WebBrowserEvents2Impl_iface.lpVtbl = &WebBrowserEvents2Vtbl; + info->web_browser->WebBrowser_events_sink->info = (struct HHInfo *)info; + info->web_browser->WebBrowser_events_sink->ref = 1; + IConnectionPoint_Advise(point, (IUnknown *)info->web_browser->WebBrowser_events_sink, &info->web_browser->WebBrowser_events_sink->cookie); } + else + IConnectionPoint_Unadvise(point, info->web_browser->WebBrowser_events_sink->cookie);
- SysFreeString(url); + IConnectionPoint_Release(point); }
/* Size Bar */ @@ -577,9 +686,36 @@ static LRESULT OnTabChange(HWND hwnd) if(info->tabs[info->current_tab].hwnd) ShowWindow(info->tabs[info->current_tab].hwnd, SW_SHOW);
+ if (info->current_tab == TAB_CONTENTS) + DoSyncContent(info); + return 0; }
+static BOOL is_current_page(HHInfo *info, const WCHAR *local) +{ + WCHAR *url; + WCHAR *current_page; + HRESULT res; + + res = IWebBrowser2_get_LocationURL(info->web_browser->web_browser, &url); + if (FAILED(res)) + return FALSE; + + if (is_chm(url)) + { + current_page = wcsstr(url, L"::/"); + if (current_page && !lstrcmpW(local, current_page + 3)) + return TRUE; + }else + { + if (!lstrcmpW(local, url)) + return TRUE; + } + + return FALSE; +} + static LRESULT OnTopicChange(HHInfo *info, void *user_data) { LPCWSTR chmfile = NULL, name = NULL, local = NULL; @@ -596,6 +732,9 @@ static LRESULT OnTopicChange(HHInfo *info, void *user_data) citer = (ContentItem *) user_data; name = citer->name; local = citer->local; + if (is_current_page(info, local)) + return 0; + while(citer) { if(citer->merge.chm_file) { chmfile = citer->merge.chm_file; @@ -880,7 +1019,7 @@ static void TB_OnClick(HWND hWnd, DWORD dwID) ExpandContract(info); break; case IDTB_SYNC: - DoSync(info); + DoSyncContent(info); break; case IDTB_OPTIONS: DisplayPopupMenu(info); @@ -1158,6 +1297,8 @@ static BOOL HH_AddHTMLPane(HHInfo *pHHInfo) if (!InitWebBrowser(pHHInfo, hWnd)) return FALSE;
+ hook_WebBrowserEvents2(pHHInfo, TRUE); + /* store the pointer to the HH info struct */ SetWindowLongPtrW(hWnd, 0, (LONG_PTR)pHHInfo);
@@ -1785,6 +1926,7 @@ void ReleaseHelpViewer(HHInfo *info) if (info->pCHMInfo) CloseCHM(info->pCHMInfo);
+ hook_WebBrowserEvents2(info, FALSE); ReleaseWebBrowser(info); ReleaseContent(info); ReleaseIndex(info); diff --git a/dlls/hhctrl.ocx/hhctrl.h b/dlls/hhctrl.ocx/hhctrl.h index ebec0eebf30..f346fc735d5 100644 --- a/dlls/hhctrl.ocx/hhctrl.h +++ b/dlls/hhctrl.ocx/hhctrl.h @@ -168,6 +168,17 @@ struct wintype_stringsA { char *pszCustomTabs; };
+struct HHInfo; + +typedef struct WebBrowserEvents2Impl +{ + IDispatch WebBrowserEvents2Impl_iface; + + struct HHInfo *info; + LONG ref; + DWORD cookie; +} WebBrowserEvents2Impl; + typedef struct { IOleClientSite IOleClientSite_iface; IOleInPlaceSite IOleInPlaceSite_iface; @@ -179,6 +190,8 @@ typedef struct { IOleObject *ole_obj; IWebBrowser2 *web_browser; HWND hwndWindow; + + WebBrowserEvents2Impl *WebBrowser_events_sink; } WebBrowserContainer;
typedef struct { diff --git a/dlls/hhctrl.ocx/webbrowser.c b/dlls/hhctrl.ocx/webbrowser.c index 4e97a727a72..4fc7d9fc901 100644 --- a/dlls/hhctrl.ocx/webbrowser.c +++ b/dlls/hhctrl.ocx/webbrowser.c @@ -81,6 +81,8 @@ static ULONG STDMETHODCALLTYPE Site_Release(IOleClientSite *iface) IOleObject_Release(This->ole_obj); if(This->web_browser) IWebBrowser2_Release(This->web_browser); + if(This->WebBrowser_events_sink) + IDispatch_Release(&This->WebBrowser_events_sink->WebBrowserEvents2Impl_iface); free(This); }