* Sync with Wine 1.5.26.
svn path=/trunk/; revision=58723
help.c
hhctrl.c
index.c
- regsvr.c
search.c
stream.c
webbrowser.c
- hhctrl.rc
+ hhctrl.rc
${CMAKE_CURRENT_BINARY_DIR}/hhctrl.def)
+add_typelib(hhctrl_tlb.idl)
+set_source_files_properties(hhctrl.rc PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/hhctrl_tlb.tlb)
set_module_type(hhctrl win32ocx)
target_link_libraries(hhctrl uuid wine itss_guid)
-
-add_importlibs(hhctrl
- advapi32
- comctl32
- shlwapi
- ole32
- oleaut32
- user32
- gdi32
- msvcrt
- kernel32
- ntdll)
-
+add_importlibs(hhctrl advapi32 comctl32 shlwapi ole32 oleaut32 user32 gdi32 msvcrt kernel32 ntdll)
add_dependencies(hhctrl wineheaders)
add_pch(hhctrl hhctrl.h)
add_cd_file(TARGET hhctrl DESTINATION reactos/system32 FOR all)
*/
#include "hhctrl.h"
+#include "stream.h"
#include <winreg.h>
#include <shlwapi.h>
WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp);
-#define BLOCK_BITS 12
-#define BLOCK_SIZE (1 << BLOCK_BITS)
-#define BLOCK_MASK (BLOCK_SIZE-1)
-
/* Reads a string from the #STRINGS section in the CHM file */
static LPCSTR GetChmString(CHMInfo *chm, DWORD offset)
{
heap_free(chm->defTitle);
chm->defTitle = strdupnAtoW(buf, entry.len);
break;
+ case 0x4:
+ /* TODO: Currently only the Locale ID is loaded from this field */
+ TRACE("Locale is: %d\n", *(LCID*)&buf[0]);
+ if(!GetLocaleInfoW(*(LCID*)&buf[0], LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER,
+ (WCHAR *)&chm->codePage, sizeof(chm->codePage)/sizeof(WCHAR)))
+ chm->codePage = CP_ACP;
+ break;
case 0x5:
- TRACE("Default window is %s\n", debugstr_an(buf, entry.len));
+ TRACE("Window name is %s\n", debugstr_an(buf, entry.len));
+ chm->defWindow = strdupnAtoW(buf, entry.len);
break;
case 0x6:
TRACE("Compiled file is %s\n", debugstr_an(buf, entry.len));
+ heap_free(chm->compiledFile);
+ chm->compiledFile = strdupnAtoW(buf, entry.len);
break;
case 0x9:
TRACE("Version is %s\n", debugstr_an(buf, entry.len));
return strdupAtoW(ret);
}
+/*
+ * Tests if the file <chmfile>.<ext> exists, used for loading Indices, Table of Contents, etc.
+ * when these files are not available from the HH_WINTYPE structure.
+ */
+static WCHAR *FindHTMLHelpSetting(HHInfo *info, const WCHAR *extW)
+{
+ static const WCHAR periodW[] = {'.',0};
+ IStorage *pStorage = info->pCHMInfo->pStorage;
+ IStream *pStream;
+ WCHAR *filename;
+ HRESULT hr;
+
+ filename = heap_alloc( (strlenW(info->pCHMInfo->compiledFile)
+ + strlenW(periodW) + strlenW(extW) + 1) * sizeof(WCHAR) );
+ strcpyW(filename, info->pCHMInfo->compiledFile);
+ strcatW(filename, periodW);
+ strcatW(filename, extW);
+ hr = IStorage_OpenStream(pStorage, filename, NULL, STGM_READ, 0, &pStream);
+ if (FAILED(hr))
+ {
+ heap_free(filename);
+ return strdupAtoW("");
+ }
+ IStream_Release(pStream);
+ return filename;
+}
+
+static inline WCHAR *MergeChmString(LPCWSTR src, WCHAR **dst)
+{
+ if(*dst == NULL)
+ *dst = strdupW(src);
+ return *dst;
+}
+
+void MergeChmProperties(HH_WINTYPEW *src, HHInfo *info, BOOL override)
+{
+ DWORD unhandled_params = src->fsValidMembers & ~(HHWIN_PARAM_PROPERTIES|HHWIN_PARAM_STYLES
+ |HHWIN_PARAM_EXSTYLES|HHWIN_PARAM_RECT|HHWIN_PARAM_NAV_WIDTH
+ |HHWIN_PARAM_SHOWSTATE|HHWIN_PARAM_INFOTYPES|HHWIN_PARAM_TB_FLAGS
+ |HHWIN_PARAM_EXPANSION|HHWIN_PARAM_TABPOS|HHWIN_PARAM_TABORDER
+ |HHWIN_PARAM_HISTORY_COUNT|HHWIN_PARAM_CUR_TAB);
+ HH_WINTYPEW *dst = &info->WinType;
+ DWORD merge = override ? src->fsValidMembers : src->fsValidMembers & ~dst->fsValidMembers;
+
+ if (unhandled_params)
+ FIXME("Unsupported fsValidMembers fields: 0x%x\n", unhandled_params);
+
+ dst->fsValidMembers |= merge;
+ if (dst->cbStruct == 0)
+ {
+ /* If the structure has not been filled in yet then use all of the values */
+ dst->cbStruct = sizeof(HH_WINTYPEW);
+ merge = ~0;
+ }
+ if (merge & HHWIN_PARAM_PROPERTIES) dst->fsWinProperties = src->fsWinProperties;
+ if (merge & HHWIN_PARAM_STYLES) dst->dwStyles = src->dwStyles;
+ if (merge & HHWIN_PARAM_EXSTYLES) dst->dwExStyles = src->dwExStyles;
+ if (merge & HHWIN_PARAM_RECT) dst->rcWindowPos = src->rcWindowPos;
+ if (merge & HHWIN_PARAM_NAV_WIDTH) dst->iNavWidth = src->iNavWidth;
+ if (merge & HHWIN_PARAM_SHOWSTATE) dst->nShowState = src->nShowState;
+ if (merge & HHWIN_PARAM_INFOTYPES) dst->paInfoTypes = src->paInfoTypes;
+ if (merge & HHWIN_PARAM_TB_FLAGS) dst->fsToolBarFlags = src->fsToolBarFlags;
+ if (merge & HHWIN_PARAM_EXPANSION) dst->fNotExpanded = src->fNotExpanded;
+ if (merge & HHWIN_PARAM_TABPOS) dst->tabpos = src->tabpos;
+ if (merge & HHWIN_PARAM_TABORDER) memcpy(dst->tabOrder, src->tabOrder, sizeof(src->tabOrder));
+ if (merge & HHWIN_PARAM_HISTORY_COUNT) dst->cHistory = src->cHistory;
+ if (merge & HHWIN_PARAM_CUR_TAB) dst->curNavType = src->curNavType;
+
+ /*
+ * Note: We assume that hwndHelp, hwndCaller, hwndToolBar, hwndNavigation, and hwndHTML cannot be
+ * modified by the user. rcHTML and rcMinSize are not currently supported, so don't bother to copy them.
+ */
+
+ dst->pszType = MergeChmString(src->pszType, &info->stringsW.pszType);
+ dst->pszFile = MergeChmString(src->pszFile, &info->stringsW.pszFile);
+ dst->pszToc = MergeChmString(src->pszToc, &info->stringsW.pszToc);
+ dst->pszIndex = MergeChmString(src->pszIndex, &info->stringsW.pszIndex);
+ dst->pszCaption = MergeChmString(src->pszCaption, &info->stringsW.pszCaption);
+ dst->pszHome = MergeChmString(src->pszHome, &info->stringsW.pszHome);
+ dst->pszJump1 = MergeChmString(src->pszJump1, &info->stringsW.pszJump1);
+ dst->pszJump2 = MergeChmString(src->pszJump2, &info->stringsW.pszJump2);
+ dst->pszUrlJump1 = MergeChmString(src->pszUrlJump1, &info->stringsW.pszUrlJump1);
+ dst->pszUrlJump2 = MergeChmString(src->pszUrlJump2, &info->stringsW.pszUrlJump2);
+
+ /* FIXME: pszCustomTabs is a list of multiple zero-terminated strings so ReadString won't
+ * work in this case
+ */
+#if 0
+ dst->pszCustomTabs = MergeChmString(src->pszCustomTabs, &info->pszCustomTabs);
+#endif
+}
+
+static inline WCHAR *ConvertChmString(HHInfo *info, const WCHAR **str)
+{
+ WCHAR *ret = NULL;
+
+ if(*str)
+ *str = ret = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)*str));
+ return ret;
+}
+
/* Loads the HH_WINTYPE data from the CHM file
*
* FIXME: There may be more than one window type in the file, so
BOOL LoadWinTypeFromCHM(HHInfo *info)
{
LARGE_INTEGER liOffset;
+ WCHAR *pszType = NULL, *pszFile = NULL, *pszToc = NULL, *pszIndex = NULL, *pszCaption = NULL;
+ WCHAR *pszHome = NULL, *pszJump1 = NULL, *pszJump2 = NULL, *pszUrlJump1 = NULL, *pszUrlJump2 = NULL;
IStorage *pStorage = info->pCHMInfo->pStorage;
- IStream *pStream;
+ IStream *pStream = NULL;
+ HH_WINTYPEW wintype;
HRESULT hr;
DWORD cbRead;
+ BOOL ret = FALSE;
+ static const WCHAR null[] = {0};
+ static const WCHAR toc_extW[] = {'h','h','c',0};
+ static const WCHAR index_extW[] = {'h','h','k',0};
static const WCHAR windowsW[] = {'#','W','I','N','D','O','W','S',0};
hr = IStorage_OpenStream(pStorage, windowsW, NULL, STGM_READ, 0, &pStream);
- if (FAILED(hr))
+ if (SUCCEEDED(hr))
+ {
+ /* jump past the #WINDOWS header */
+ liOffset.QuadPart = sizeof(DWORD) * 2;
+
+ hr = IStream_Seek(pStream, liOffset, STREAM_SEEK_SET, NULL);
+ if (FAILED(hr)) goto done;
+
+ /* read the HH_WINTYPE struct data */
+ hr = IStream_Read(pStream, &wintype, sizeof(wintype), &cbRead);
+ if (FAILED(hr)) goto done;
+
+ /* convert the #STRINGS offsets to actual strings */
+ pszType = ConvertChmString(info, &wintype.pszType);
+ pszFile = ConvertChmString(info, &wintype.pszFile);
+ pszToc = ConvertChmString(info, &wintype.pszToc);
+ pszIndex = ConvertChmString(info, &wintype.pszIndex);
+ pszCaption = ConvertChmString(info, &wintype.pszCaption);
+ pszHome = ConvertChmString(info, &wintype.pszHome);
+ pszJump1 = ConvertChmString(info, &wintype.pszJump1);
+ pszJump2 = ConvertChmString(info, &wintype.pszJump2);
+ pszUrlJump1 = ConvertChmString(info, &wintype.pszUrlJump1);
+ pszUrlJump2 = ConvertChmString(info, &wintype.pszUrlJump2);
+ }
+ else
{
/* no defined window types so use (hopefully) sane defaults */
static const WCHAR defaultwinW[] = {'d','e','f','a','u','l','t','w','i','n','\0'};
- static const WCHAR null[] = {0};
- memset((void*)&(info->WinType), 0, sizeof(info->WinType));
- info->WinType.cbStruct=sizeof(info->WinType);
- info->WinType.fUniCodeStrings=TRUE;
- info->WinType.pszType=strdupW(defaultwinW);
- info->WinType.pszToc = strdupW(info->pCHMInfo->defToc ? info->pCHMInfo->defToc : null);
- info->WinType.pszIndex = strdupW(null);
- info->WinType.fsValidMembers=0;
- info->WinType.fsWinProperties=HHWIN_PROP_TRI_PANE;
- info->WinType.pszCaption=strdupW(info->pCHMInfo->defTitle ? info->pCHMInfo->defTitle : null);
- info->WinType.dwStyles=WS_POPUP;
- info->WinType.dwExStyles=0;
- info->WinType.nShowState=SW_SHOW;
- info->WinType.pszFile=strdupW(info->pCHMInfo->defTopic ? info->pCHMInfo->defTopic : null);
- info->WinType.curNavType=HHWIN_NAVTYPE_TOC;
- return TRUE;
+ memset(&wintype, 0, sizeof(wintype));
+ wintype.cbStruct = sizeof(wintype);
+ wintype.fUniCodeStrings = TRUE;
+ wintype.pszType = pszType = strdupW(info->pCHMInfo->defWindow ? info->pCHMInfo->defWindow : defaultwinW);
+ wintype.pszToc = pszToc = strdupW(info->pCHMInfo->defToc ? info->pCHMInfo->defToc : null);
+ wintype.pszIndex = pszIndex = strdupW(null);
+ wintype.fsValidMembers = 0;
+ wintype.fsWinProperties = HHWIN_PROP_TRI_PANE;
+ wintype.dwStyles = WS_POPUP;
+ wintype.dwExStyles = 0;
+ wintype.nShowState = SW_SHOW;
+ wintype.curNavType = HHWIN_NAVTYPE_TOC;
}
- /* jump past the #WINDOWS header */
- liOffset.QuadPart = sizeof(DWORD) * 2;
-
- hr = IStream_Seek(pStream, liOffset, STREAM_SEEK_SET, NULL);
- if (FAILED(hr)) goto done;
-
- /* read the HH_WINTYPE struct data */
- hr = IStream_Read(pStream, &info->WinType, sizeof(info->WinType), &cbRead);
- if (FAILED(hr)) goto done;
-
- /* convert the #STRINGS offsets to actual strings */
- info->WinType.pszType = info->pszType = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszType));
- info->WinType.pszCaption = info->pszCaption = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszCaption));
- info->WinType.pszToc = info->pszToc = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszToc));
- info->WinType.pszIndex = info->pszIndex = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszIndex));
- info->WinType.pszFile = info->pszFile = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszFile));
- info->WinType.pszHome = info->pszHome = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszHome));
- info->WinType.pszJump1 = info->pszJump1 = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszJump1));
- info->WinType.pszJump2 = info->pszJump2 = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszJump2));
- info->WinType.pszUrlJump1 = info->pszUrlJump1 = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszUrlJump1));
- info->WinType.pszUrlJump2 = info->pszUrlJump2 = strdupAtoW(GetChmString(info->pCHMInfo, (DWORD_PTR)info->WinType.pszUrlJump2));
-
- /* FIXME: pszCustomTabs is a list of multiple zero-terminated strings so ReadString won't
- * work in this case
- */
-#if 0
- info->WinType.pszCustomTabs = info->pszCustomTabs = CHM_ReadString(pChmInfo, (DWORD_PTR)info->WinType.pszCustomTabs);
-#endif
+ /* merge the new data with any pre-existing HH_WINTYPE structure */
+ MergeChmProperties(&wintype, info, FALSE);
+ if (!info->WinType.pszCaption)
+ info->WinType.pszCaption = info->stringsW.pszCaption = strdupW(info->pCHMInfo->defTitle ? info->pCHMInfo->defTitle : null);
+ if (!info->WinType.pszFile)
+ info->WinType.pszFile = info->stringsW.pszFile = strdupW(info->pCHMInfo->defTopic ? info->pCHMInfo->defTopic : null);
+ if (!info->WinType.pszToc)
+ info->WinType.pszToc = info->stringsW.pszToc = FindHTMLHelpSetting(info, toc_extW);
+ if (!info->WinType.pszIndex)
+ info->WinType.pszIndex = info->stringsW.pszIndex = FindHTMLHelpSetting(info, index_extW);
+
+ heap_free(pszType);
+ heap_free(pszFile);
+ heap_free(pszToc);
+ heap_free(pszIndex);
+ heap_free(pszCaption);
+ heap_free(pszHome);
+ heap_free(pszJump1);
+ heap_free(pszJump2);
+ heap_free(pszUrlJump1);
+ heap_free(pszUrlJump2);
+ ret = TRUE;
done:
- IStream_Release(pStream);
+ if (pStream)
+ IStream_Release(pStream);
- return SUCCEEDED(hr);
+ return ret;
}
-static LPCWSTR skip_schema(LPCWSTR url)
+LPCWSTR skip_schema(LPCWSTR url)
{
static const WCHAR its_schema[] = {'i','t','s',':'};
static const WCHAR msits_schema[] = {'m','s','-','i','t','s',':'};
return stream;
}
+/*
+ * Retrieve a CHM document and parse the data from the <title> element to get the document's title.
+ */
+WCHAR *GetDocumentTitle(CHMInfo *info, LPCWSTR document)
+{
+ strbuf_t node, node_name, content;
+ WCHAR *document_title = NULL;
+ IStream *str = NULL;
+ IStorage *storage;
+ stream_t stream;
+ HRESULT hres;
+
+ TRACE("%s\n", debugstr_w(document));
+
+ storage = info->pStorage;
+ if(!storage) {
+ WARN("Could not open storage to obtain the title for a document.\n");
+ return NULL;
+ }
+ IStorage_AddRef(storage);
+
+ hres = IStorage_OpenStream(storage, document, NULL, STGM_READ, 0, &str);
+ IStorage_Release(storage);
+ if(FAILED(hres))
+ WARN("Could not open stream: %08x\n", hres);
+
+ stream_init(&stream, str);
+ strbuf_init(&node);
+ strbuf_init(&content);
+ strbuf_init(&node_name);
+
+ while(next_node(&stream, &node)) {
+ get_node_name(&node, &node_name);
+
+ TRACE("%s\n", node.buf);
+
+ if(!strcasecmp(node_name.buf, "title")) {
+ if(next_content(&stream, &content) && content.len > 1)
+ {
+ document_title = strdupnAtoW(&content.buf[1], content.len-1);
+ FIXME("magic: %s\n", debugstr_w(document_title));
+ break;
+ }
+ }
+
+ strbuf_zero(&node);
+ }
+
+ strbuf_free(&node);
+ strbuf_free(&content);
+ strbuf_free(&node_name);
+ IStream_Release(str);
+
+ return document_title;
+}
+
/* Opens the CHM file for reading */
CHMInfo *OpenCHM(LPCWSTR szFile)
{
if (!(ret = heap_alloc_zero(sizeof(CHMInfo))))
return NULL;
+ ret->codePage = CP_ACP;
if (!(ret->szFile = strdupW(szFile))) {
heap_free(ret);
}
heap_free(chm->strings);
+ heap_free(chm->defWindow);
heap_free(chm->defTitle);
heap_free(chm->defTopic);
heap_free(chm->defToc);
heap_free(chm->szFile);
+ heap_free(chm->compiledFile);
heap_free(chm);
return NULL;
/*
* Copyright 2007 Jacek Caban for CodeWeavers
+ * Copyright 2011 Owen Rudge for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
#include "hhctrl.h"
#include "stream.h"
+#include "resource.h"
#include <wine/debug.h>
}
}
-static void parse_obj_node_param(ContentItem *item, ContentItem *hhc_root, const char *text)
+static void parse_obj_node_param(ContentItem *item, ContentItem *hhc_root, const char *text, UINT code_page)
{
const char *ptr;
LPWSTR *param, merge;
- int len, wlen;
+ int len;
ptr = get_attr(text, "name", &len);
if(!ptr) {
return;
}
- wlen = MultiByteToWideChar(CP_ACP, 0, ptr, len, NULL, 0);
- *param = heap_alloc((wlen+1)*sizeof(WCHAR));
- MultiByteToWideChar(CP_ACP, 0, ptr, len, *param, wlen);
- (*param)[wlen] = 0;
+ /*
+ * "merge" parameter data (referencing another CHM file) can be incorporated into the "local" parameter
+ * by specifying the filename in the format:
+ * MS-ITS:file.chm::/local_path.htm
+ */
+ if(param == &item->local && strstr(ptr, "::"))
+ {
+ const char *local = strstr(ptr, "::")+2;
+ int local_len = len-(local-ptr);
+
+ item->local = decode_html(local, local_len, code_page);
+ param = &merge;
+ }
+
+ *param = decode_html(ptr, len, code_page);
if(param == &merge) {
SetChmPath(&item->merge, hhc_root->merge.chm_file, merge);
if(!strcasecmp(node_name.buf, "/object"))
break;
if(!strcasecmp(node_name.buf, "param"))
- parse_obj_node_param(item, hhc_root, node.buf);
+ parse_obj_node_param(item, hhc_root, node.buf, info->pCHMInfo->codePage);
strbuf_zero(&node);
}
TVINSERTSTRUCTW tvis;
memset(&tvis, 0, sizeof(tvis));
- tvis.u.item.mask = TVIF_TEXT|TVIF_PARAM;
+ tvis.u.item.mask = TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
tvis.u.item.cchTextMax = strlenW(item->name)+1;
tvis.u.item.pszText = item->name;
tvis.u.item.lParam = (LPARAM)item;
+ tvis.u.item.iImage = item->child ? HHTV_FOLDER : HHTV_DOCUMENT;
+ tvis.u.item.iSelectedImage = item->child ? HHTV_FOLDER : HHTV_DOCUMENT;
tvis.hParent = parent ? parent->id : 0;
tvis.hInsertAfter = TVI_LAST;
{
free_content_item(info->content);
}
+
+void ActivateContentTopic(HWND hWnd, LPCWSTR filename, ContentItem *item)
+{
+ if (lstrcmpiW(item->local, filename) == 0)
+ {
+ SendMessageW(hWnd, TVM_SELECTITEM, TVGN_CARET, (LPARAM) item->id);
+ return;
+ }
+
+ if (item->next)
+ ActivateContentTopic(hWnd, filename, item->next);
+
+ if (item->child)
+ ActivateContentTopic(hWnd, filename, item->child);
+}
*
* Copyright 2005 James Hawkins
* Copyright 2007 Jacek Caban for CodeWeavers
+ * Copyright 2011 Owen Rudge for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp);
static LRESULT Help_OnSize(HWND hWnd);
+static void ExpandContract(HHInfo *pHHInfo);
/* Window type defaults */
#define TAB_MARGIN 8
#define EDIT_HEIGHT 20
+struct list window_list = LIST_INIT(window_list);
+
static const WCHAR szEmpty[] = {0};
+struct html_encoded_symbol {
+ const char *html_code;
+ char ansi_symbol;
+};
+
+/*
+ * Table mapping the conversion between HTML encoded symbols and their ANSI code page equivalent.
+ * Note: Add additional entries in proper alphabetical order (a binary search is used on this table).
+ */
+struct html_encoded_symbol html_encoded_symbols[] =
+{
+ {"AElig", 0xC6},
+ {"Aacute", 0xC1},
+ {"Acirc", 0xC2},
+ {"Agrave", 0xC0},
+ {"Aring", 0xC5},
+ {"Atilde", 0xC3},
+ {"Auml", 0xC4},
+ {"Ccedil", 0xC7},
+ {"ETH", 0xD0},
+ {"Eacute", 0xC9},
+ {"Ecirc", 0xCA},
+ {"Egrave", 0xC8},
+ {"Euml", 0xCB},
+ {"Iacute", 0xCD},
+ {"Icirc", 0xCE},
+ {"Igrave", 0xCC},
+ {"Iuml", 0xCF},
+ {"Ntilde", 0xD1},
+ {"Oacute", 0xD3},
+ {"Ocirc", 0xD4},
+ {"Ograve", 0xD2},
+ {"Oslash", 0xD8},
+ {"Otilde", 0xD5},
+ {"Ouml", 0xD6},
+ {"THORN", 0xDE},
+ {"Uacute", 0xDA},
+ {"Ucirc", 0xDB},
+ {"Ugrave", 0xD9},
+ {"Uuml", 0xDC},
+ {"Yacute", 0xDD},
+ {"aacute", 0xE1},
+ {"acirc", 0xE2},
+ {"acute", 0xB4},
+ {"aelig", 0xE6},
+ {"agrave", 0xE0},
+ {"amp", '&'},
+ {"aring", 0xE5},
+ {"atilde", 0xE3},
+ {"auml", 0xE4},
+ {"brvbar", 0xA6},
+ {"ccedil", 0xE7},
+ {"cedil", 0xB8},
+ {"cent", 0xA2},
+ {"copy", 0xA9},
+ {"curren", 0xA4},
+ {"deg", 0xB0},
+ {"divide", 0xF7},
+ {"eacute", 0xE9},
+ {"ecirc", 0xEA},
+ {"egrave", 0xE8},
+ {"eth", 0xF0},
+ {"euml", 0xEB},
+ {"frac12", 0xBD},
+ {"frac14", 0xBC},
+ {"frac34", 0xBE},
+ {"gt", '>'},
+ {"iacute", 0xED},
+ {"icirc", 0xEE},
+ {"iexcl", 0xA1},
+ {"igrave", 0xEC},
+ {"iquest", 0xBF},
+ {"iuml", 0xEF},
+ {"laquo", 0xAB},
+ {"lt", '<'},
+ {"macr", 0xAF},
+ {"micro", 0xB5},
+ {"middot", 0xB7},
+ {"nbsp", ' '},
+ {"not", 0xAC},
+ {"ntilde", 0xF1},
+ {"oacute", 0xF3},
+ {"ocirc", 0xF4},
+ {"ograve", 0xF2},
+ {"ordf", 0xAA},
+ {"ordm", 0xBA},
+ {"oslash", 0xF8},
+ {"otilde", 0xF5},
+ {"ouml", 0xF6},
+ {"para", 0xB6},
+ {"plusmn", 0xB1},
+ {"pound", 0xA3},
+ {"quot", '"'},
+ {"raquo", 0xBB},
+ {"reg", 0xAE},
+ {"sect", 0xA7},
+ {"shy", 0xAD},
+ {"sup1", 0xB9},
+ {"sup2", 0xB2},
+ {"sup3", 0xB3},
+ {"szlig", 0xDF},
+ {"thorn", 0xFE},
+ {"times", 0xD7},
+ {"uacute", 0xFA},
+ {"ucirc", 0xFB},
+ {"ugrave", 0xF9},
+ {"uml", 0xA8},
+ {"uuml", 0xFC},
+ {"yacute", 0xFD},
+ {"yen", 0xA5},
+ {"yuml", 0xFF}
+};
+
+static inline BOOL navigation_visible(HHInfo *info)
+{
+ return ((info->WinType.fsWinProperties & HHWIN_PROP_TRI_PANE) && !info->WinType.fNotExpanded);
+}
+
/* Loads a string from the resource file */
static LPWSTR HH_LoadString(DWORD dwID)
{
return ret;
}
-BOOL NavigateToChm(HHInfo *info, LPCWSTR file, LPCWSTR index)
+static BOOL AppendFullPathURL(LPCWSTR file, LPWSTR buf, LPCWSTR index)
{
- WCHAR buf[INTERNET_MAX_URL_LENGTH];
- WCHAR full_path[MAX_PATH];
- LPWSTR ptr;
-
static const WCHAR url_format[] =
{'m','k',':','@','M','S','I','T','S','t','o','r','e',':','%','s',':',':','%','s','%','s',0};
static const WCHAR slash[] = {'/',0};
static const WCHAR empty[] = {0};
+ WCHAR full_path[MAX_PATH];
- TRACE("%p %s %s\n", info, debugstr_w(file), debugstr_w(index));
-
- if (!info->web_browser)
- return FALSE;
+ TRACE("%s %p %s\n", debugstr_w(file), buf, debugstr_w(index));
if(!GetFullPathNameW(file, sizeof(full_path)/sizeof(full_path[0]), full_path, NULL)) {
WARN("GetFullPathName failed: %u\n", GetLastError());
}
wsprintfW(buf, url_format, full_path, (!index || index[0] == '/') ? empty : slash, index);
+ return TRUE;
+}
+
+BOOL NavigateToChm(HHInfo *info, LPCWSTR file, LPCWSTR index)
+{
+ WCHAR buf[INTERNET_MAX_URL_LENGTH];
+
+ TRACE("%p %s %s\n", info, debugstr_w(file), debugstr_w(index));
- /* FIXME: HACK */
- if((ptr = strchrW(buf, '#')))
- *ptr = 0;
+ if ((!info->web_browser) || !AppendFullPathURL(file, buf, index))
+ return FALSE;
return SUCCEEDED(navigate_url(info, buf));
}
+static void DoSync(HHInfo *info)
+{
+ WCHAR buf[INTERNET_MAX_URL_LENGTH];
+ HRESULT hres;
+ BSTR url;
+
+ hres = IWebBrowser2_get_LocationURL(info->web_browser, &url);
+
+ if (FAILED(hres))
+ {
+ WARN("get_LocationURL failed: %08x\n", hres);
+ 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)))
+ {
+ SysFreeString(url);
+ return;
+ }
+
+ if (lstrcmpiW(buf, url) > 0)
+ {
+ static const WCHAR delimW[] = {':',':','/',0};
+ const WCHAR *index;
+
+ index = strstrW(url, delimW);
+
+ if (index)
+ ActivateContentTopic(info->tabs[TAB_CONTENTS].hwnd, index + 3, info->content); /* skip over ::/ */
+ }
+
+ SysFreeString(url);
+}
+
/* Size Bar */
#define SIZEBAR_WIDTH 4
static void SB_OnLButtonUp(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
- HHInfo *pHHInfo = (HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
+ HHInfo *pHHInfo = (HHInfo *)GetWindowLongPtrW(hWnd, 0);
POINT pt;
pt.x = (short)LOWORD(lParam);
wcex.style = 0;
wcex.lpfnWndProc = SizeBar_WndProc;
wcex.cbClsExtra = 0;
- wcex.cbWndExtra = 0;
+ wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = hhctrl_hinstance;
wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_SIZEWE);
{
HWND hWnd;
HWND hwndParent = pHHInfo->WinType.hwndHelp;
- DWORD dwStyles = WS_CHILDWINDOW | WS_VISIBLE | WS_OVERLAPPED;
+ DWORD dwStyles = WS_CHILDWINDOW | WS_OVERLAPPED;
DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
RECT rc;
+ if (navigation_visible(pHHInfo))
+ dwStyles |= WS_VISIBLE;
+
SB_GetSizeBarRect(pHHInfo, &rc);
hWnd = CreateWindowExW(dwExStyles, szSizeBarClass, szEmpty, dwStyles,
return FALSE;
/* store the pointer to the HH info struct */
- SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)pHHInfo);
+ SetWindowLongPtrW(hWnd, 0, (LONG_PTR)pHHInfo);
pHHInfo->hwndSizeBar = hWnd;
return TRUE;
static LRESULT Child_OnSize(HWND hwnd)
{
- HHInfo *info = (HHInfo*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
+ HHInfo *info = (HHInfo*)GetWindowLongPtrW(hwnd, 0);
RECT rect;
if(!info || hwnd != info->WinType.hwndNavigation)
ResizeTabChild(info, TAB_CONTENTS);
ResizeTabChild(info, TAB_INDEX);
+ ResizeTabChild(info, TAB_SEARCH);
return 0;
}
static LRESULT OnTabChange(HWND hwnd)
{
- HHInfo *info = (HHInfo*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
+ HHInfo *info = (HHInfo*)GetWindowLongPtrW(hwnd, 0);
+ int tab_id, tab_index, i;
TRACE("%p\n", hwnd);
if(info->tabs[info->current_tab].hwnd)
ShowWindow(info->tabs[info->current_tab].hwnd, SW_HIDE);
- info->current_tab = SendMessageW(info->hwndTabCtrl, TCM_GETCURSEL, 0, 0);
+ tab_id = (int) SendMessageW(info->hwndTabCtrl, TCM_GETCURSEL, 0, 0);
+ /* convert the ID of the tab to an index in our tab list */
+ tab_index = -1;
+ for (i=0; i<TAB_NUMTABS; i++)
+ {
+ if (info->tabs[i].id == tab_id)
+ {
+ tab_index = i;
+ break;
+ }
+ }
+ if (tab_index == -1)
+ {
+ FIXME("Tab ID %d does not correspond to a valid index in the tab list.\n", tab_id);
+ return 0;
+ }
+ info->current_tab = tab_index;
if(info->tabs[info->current_tab].hwnd)
ShowWindow(info->tabs[info->current_tab].hwnd, SW_SHOW);
IndexSubItem *item = &iiter->items[i];
WCHAR *name = iiter->keyword;
+ if(!item->name)
+ item->name = GetDocumentTitle(info->pCHMInfo, item->local);
if(item->name)
name = item->name;
memset(&lvi, 0, sizeof(lvi));
case WM_SIZE:
return Child_OnSize(hWnd);
case WM_NOTIFY: {
- HHInfo *info = (HHInfo*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
+ HHInfo *info = (HHInfo*)GetWindowLongPtrW(hWnd, 0);
NMHDR *nmhdr = (NMHDR*)lParam;
switch(nmhdr->code) {
return OnTabChange(hWnd);
case TVN_SELCHANGEDW:
return OnTopicChange(info, (void*)((NMTREEVIEWW *)lParam)->itemNew.lParam);
+ case TVN_ITEMEXPANDINGW: {
+ TVITEMW *item = &((NMTREEVIEWW *)lParam)->itemNew;
+ HWND hwndTreeView = info->tabs[TAB_CONTENTS].hwnd;
+
+ item->mask = TVIF_IMAGE|TVIF_SELECTEDIMAGE;
+ if (item->state & TVIS_EXPANDED)
+ {
+ item->iImage = HHTV_FOLDER;
+ item->iSelectedImage = HHTV_FOLDER;
+ }
+ else
+ {
+ item->iImage = HHTV_OPENFOLDER;
+ item->iSelectedImage = HHTV_OPENFOLDER;
+ }
+ SendMessageW(hwndTreeView, TVM_SETITEMW, 0, (LPARAM)item);
+ return 0;
+ }
case NM_DBLCLK:
if(!info)
return 0;
wcex.style = 0;
wcex.lpfnWndProc = Child_WndProc;
wcex.cbClsExtra = 0;
- wcex.cbWndExtra = 0;
+ wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = hhctrl_hinstance;
wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
#define ICON_SIZE 20
+static void DisplayPopupMenu(HHInfo *info)
+{
+ HMENU menu, submenu;
+ TBBUTTONINFOW button;
+ MENUITEMINFOW item;
+ POINT coords;
+ RECT rect;
+ DWORD index;
+
+ menu = LoadMenuW(hhctrl_hinstance, MAKEINTRESOURCEW(MENU_POPUP));
+
+ if (!menu)
+ return;
+
+ submenu = GetSubMenu(menu, 0);
+
+ /* Update the Show/Hide menu item */
+ item.cbSize = sizeof(MENUITEMINFOW);
+ item.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_STRING;
+ item.fType = MFT_STRING;
+ item.fState = MF_ENABLED;
+
+ if (info->WinType.fNotExpanded)
+ item.dwTypeData = HH_LoadString(IDS_SHOWTABS);
+ else
+ item.dwTypeData = HH_LoadString(IDS_HIDETABS);
+
+ SetMenuItemInfoW(submenu, IDTB_EXPAND, FALSE, &item);
+ heap_free(item.dwTypeData);
+
+ /* Find the index toolbar button */
+ button.cbSize = sizeof(TBBUTTONINFOW);
+ button.dwMask = TBIF_COMMAND;
+ index = SendMessageW(info->WinType.hwndToolBar, TB_GETBUTTONINFOW, IDTB_OPTIONS, (LPARAM) &button);
+
+ if (index == -1)
+ return;
+
+ /* Get position */
+ SendMessageW(info->WinType.hwndToolBar, TB_GETITEMRECT, index, (LPARAM) &rect);
+
+ coords.x = rect.left;
+ coords.y = rect.bottom;
+
+ ClientToScreen(info->WinType.hwndToolBar, &coords);
+ TrackPopupMenu(submenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON | TPM_NOANIMATION, coords.x, coords.y, 0, info->WinType.hwndHelp, NULL);
+}
+
static void TB_OnClick(HWND hWnd, DWORD dwID)
{
- HHInfo *info = (HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
+ HHInfo *info = (HHInfo *)GetWindowLongPtrW(hWnd, 0);
switch (dwID)
{
case IDTB_FORWARD:
DoPageAction(info, WB_GOFORWARD);
break;
+ case IDTB_PRINT:
+ DoPageAction(info, WB_PRINT);
+ break;
case IDTB_EXPAND:
case IDTB_CONTRACT:
+ ExpandContract(info);
+ break;
case IDTB_SYNC:
- case IDTB_PRINT:
+ DoSync(info);
+ break;
case IDTB_OPTIONS:
+ DisplayPopupMenu(info);
+ break;
+ case IDTB_NOTES:
+ case IDTB_CONTENTS:
+ case IDTB_INDEX:
+ case IDTB_SEARCH:
+ case IDTB_HISTORY:
+ case IDTB_FAVORITES:
+ /* These are officially unimplemented as of the Windows 7 SDK */
+ break;
case IDTB_BROWSE_FWD:
case IDTB_BROWSE_BACK:
case IDTB_JUMP1:
}
}
-static void TB_AddButton(TBBUTTON *pButtons, DWORD dwIndex, DWORD dwID)
+static void TB_AddButton(TBBUTTON *pButtons, DWORD dwIndex, DWORD dwID, DWORD dwBitmap)
{
- /* FIXME: Load the correct button bitmaps */
- pButtons[dwIndex].iBitmap = STD_PRINT;
+ pButtons[dwIndex].iBitmap = dwBitmap;
pButtons[dwIndex].idCommand = dwID;
pButtons[dwIndex].fsState = TBSTATE_ENABLED;
pButtons[dwIndex].fsStyle = BTNS_BUTTON;
pButtons[dwIndex].iString = 0;
}
-static void TB_AddButtonsFromFlags(TBBUTTON *pButtons, DWORD dwButtonFlags, LPDWORD pdwNumButtons)
+static void TB_AddButtonsFromFlags(HHInfo *pHHInfo, TBBUTTON *pButtons, DWORD dwButtonFlags, LPDWORD pdwNumButtons)
{
+ int nHistBitmaps = 0, nStdBitmaps = 0, nHHBitmaps = 0;
+ HWND hToolbar = pHHInfo->WinType.hwndToolBar;
+ TBADDBITMAP tbAB;
+ DWORD unsupported;
+
+ /* Common bitmaps */
+ tbAB.hInst = HINST_COMMCTRL;
+ tbAB.nID = IDB_HIST_LARGE_COLOR;
+ nHistBitmaps = SendMessageW(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbAB);
+ tbAB.nID = IDB_STD_LARGE_COLOR;
+ nStdBitmaps = SendMessageW(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbAB);
+ /* hhctrl.ocx bitmaps */
+ tbAB.hInst = hhctrl_hinstance;
+ tbAB.nID = IDB_HHTOOLBAR;
+ nHHBitmaps = SendMessageW(hToolbar, TB_ADDBITMAP, HHTB_NUMBITMAPS, (LPARAM)&tbAB);
+
*pdwNumButtons = 0;
+ unsupported = dwButtonFlags & (HHWIN_BUTTON_BROWSE_FWD |
+ HHWIN_BUTTON_BROWSE_BCK | HHWIN_BUTTON_NOTES | HHWIN_BUTTON_CONTENTS |
+ HHWIN_BUTTON_INDEX | HHWIN_BUTTON_SEARCH | HHWIN_BUTTON_HISTORY |
+ HHWIN_BUTTON_FAVORITES | HHWIN_BUTTON_JUMP1 | HHWIN_BUTTON_JUMP2 |
+ HHWIN_BUTTON_ZOOM | HHWIN_BUTTON_TOC_NEXT | HHWIN_BUTTON_TOC_PREV);
+ if (unsupported)
+ FIXME("got asked for unsupported buttons: %06x\n", unsupported);
+
if (dwButtonFlags & HHWIN_BUTTON_EXPAND)
- TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_EXPAND);
+ {
+ TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_EXPAND, nHHBitmaps + HHTB_EXPAND);
+ TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_CONTRACT, nHHBitmaps + HHTB_CONTRACT);
+
+ if (pHHInfo->WinType.fNotExpanded)
+ pButtons[1].fsState |= TBSTATE_HIDDEN;
+ else
+ pButtons[0].fsState |= TBSTATE_HIDDEN;
+ }
if (dwButtonFlags & HHWIN_BUTTON_BACK)
- TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_BACK);
+ TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_BACK, nHistBitmaps + HIST_BACK);
if (dwButtonFlags & HHWIN_BUTTON_FORWARD)
- TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_FORWARD);
+ TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_FORWARD, nHistBitmaps + HIST_FORWARD);
if (dwButtonFlags & HHWIN_BUTTON_STOP)
- TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_STOP);
+ TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_STOP, nHHBitmaps + HHTB_STOP);
if (dwButtonFlags & HHWIN_BUTTON_REFRESH)
- TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_REFRESH);
+ TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_REFRESH, nHHBitmaps + HHTB_REFRESH);
if (dwButtonFlags & HHWIN_BUTTON_HOME)
- TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_HOME);
+ TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_HOME, nHHBitmaps + HHTB_HOME);
if (dwButtonFlags & HHWIN_BUTTON_SYNC)
- TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_SYNC);
+ TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_SYNC, nHHBitmaps + HHTB_SYNC);
if (dwButtonFlags & HHWIN_BUTTON_OPTIONS)
- TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_OPTIONS);
+ TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_OPTIONS, nStdBitmaps + STD_PROPERTIES);
if (dwButtonFlags & HHWIN_BUTTON_PRINT)
- TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_PRINT);
-
- if (dwButtonFlags & HHWIN_BUTTON_JUMP1)
- TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_JUMP1);
-
- if (dwButtonFlags & HHWIN_BUTTON_JUMP2)
- TB_AddButton(pButtons,(*pdwNumButtons)++, IDTB_JUMP2);
-
- if (dwButtonFlags & HHWIN_BUTTON_ZOOM)
- TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_ZOOM);
-
- if (dwButtonFlags & HHWIN_BUTTON_TOC_NEXT)
- TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_TOC_NEXT);
-
- if (dwButtonFlags & HHWIN_BUTTON_TOC_PREV)
- TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_TOC_PREV);
+ TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_PRINT, nStdBitmaps + STD_PRINT);
}
static BOOL HH_AddToolbar(HHInfo *pHHInfo)
HWND hwndParent = pHHInfo->WinType.hwndHelp;
DWORD toolbarFlags;
TBBUTTON buttons[IDTB_TOC_PREV - IDTB_EXPAND];
- TBADDBITMAP tbAB;
DWORD dwStyles, dwExStyles;
DWORD dwNumButtons, dwIndex;
else
toolbarFlags = HHWIN_DEF_BUTTONS;
- TB_AddButtonsFromFlags(buttons, toolbarFlags, &dwNumButtons);
-
- dwStyles = WS_CHILDWINDOW | WS_VISIBLE | TBSTYLE_FLAT |
- TBSTYLE_WRAPABLE | TBSTYLE_TOOLTIPS | CCS_NODIVIDER;
+ dwStyles = WS_CHILDWINDOW | TBSTYLE_FLAT | TBSTYLE_WRAPABLE | TBSTYLE_TOOLTIPS | CCS_NODIVIDER;
dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
hToolbar = CreateWindowExW(dwExStyles, TOOLBARCLASSNAMEW, NULL, dwStyles,
hhctrl_hinstance, NULL);
if (!hToolbar)
return FALSE;
+ pHHInfo->WinType.hwndToolBar = hToolbar;
SendMessageW(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(ICON_SIZE, ICON_SIZE));
SendMessageW(hToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
SendMessageW(hToolbar, WM_SETFONT, (WPARAM)pHHInfo->hFont, TRUE);
- /* FIXME: Load correct icons for all buttons */
- tbAB.hInst = HINST_COMMCTRL;
- tbAB.nID = IDB_STD_LARGE_COLOR;
- SendMessageW(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbAB);
+ TB_AddButtonsFromFlags(pHHInfo, buttons, toolbarFlags, &dwNumButtons);
for (dwIndex = 0; dwIndex < dwNumButtons; dwIndex++)
{
SendMessageW(hToolbar, TB_ADDBUTTONSW, dwNumButtons, (LPARAM)buttons);
SendMessageW(hToolbar, TB_AUTOSIZE, 0, 0);
- ShowWindow(hToolbar, SW_SHOW);
+ if (pHHInfo->WinType.fsWinProperties & HHWIN_PROP_TRI_PANE)
+ ShowWindow(hToolbar, SW_SHOW);
- pHHInfo->WinType.hwndToolBar = hToolbar;
return TRUE;
}
{
HWND hWnd, hwndTabCtrl;
HWND hwndParent = info->WinType.hwndHelp;
- DWORD dwStyles = WS_CHILDWINDOW | WS_VISIBLE;
+ DWORD dwStyles = WS_CHILDWINDOW;
DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
RECT rc;
+ if (navigation_visible(info))
+ dwStyles |= WS_VISIBLE;
+
NP_GetNavigationRect(info, &rc);
hWnd = CreateWindowExW(dwExStyles, szChildClass, szEmpty, dwStyles,
if (!hWnd)
return FALSE;
- SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)info);
+ SetWindowLongPtrW(hWnd, 0, (LONG_PTR)info);
- hwndTabCtrl = CreateWindowExW(dwExStyles, WC_TABCONTROLW, szEmpty, dwStyles,
+ hwndTabCtrl = CreateWindowExW(dwExStyles, WC_TABCONTROLW, szEmpty, dwStyles | WS_VISIBLE,
0, TAB_TOP_PADDING,
rc.right - TAB_RIGHT_PADDING,
rc.bottom - TAB_TOP_PADDING,
RECT rectTB, rectWND, rectNP, rectSB;
GetClientRect(info->WinType.hwndHelp, &rectWND);
- GetClientRect(info->WinType.hwndToolBar, &rectTB);
- GetClientRect(info->WinType.hwndNavigation, &rectNP);
GetClientRect(info->hwndSizeBar, &rectSB);
- rc->left = rectNP.right + rectSB.right;
- rc->top = rectTB.bottom;
+ rc->left = 0;
+ rc->top = 0;
+ if (navigation_visible(info))
+ {
+ GetClientRect(info->WinType.hwndNavigation, &rectNP);
+ rc->left += rectNP.right + rectSB.right;
+ }
+ if (info->WinType.fsWinProperties & HHWIN_PROP_TRI_PANE)
+ {
+ GetClientRect(info->WinType.hwndToolBar, &rectTB);
+ rc->top += rectTB.bottom;
+ }
rc->right = rectWND.right - rc->left;
- rc->bottom = rectWND.bottom - rectTB.bottom;
+ rc->bottom = rectWND.bottom - rc->top;
}
static BOOL HH_AddHTMLPane(HHInfo *pHHInfo)
return FALSE;
/* store the pointer to the HH info struct */
- SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)pHHInfo);
+ SetWindowLongPtrW(hWnd, 0, (LONG_PTR)pHHInfo);
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
static BOOL AddContentTab(HHInfo *info)
{
+ HIMAGELIST hImageList;
+ HBITMAP hBitmap;
+ HWND hWnd;
+
if(info->tabs[TAB_CONTENTS].id == -1)
return TRUE; /* No "Contents" tab */
- info->tabs[TAB_CONTENTS].hwnd = CreateWindowExW(WS_EX_CLIENTEDGE, WC_TREEVIEWW,
- szEmpty, WS_CHILD | WS_BORDER | 0x25, 50, 50, 100, 100,
- info->WinType.hwndNavigation, NULL, hhctrl_hinstance, NULL);
- if(!info->tabs[TAB_CONTENTS].hwnd) {
+ hWnd = CreateWindowExW(WS_EX_CLIENTEDGE, WC_TREEVIEWW, szEmpty, WS_CHILD | WS_BORDER | TVS_LINESATROOT
+ | TVS_SHOWSELALWAYS | TVS_HASBUTTONS, 50, 50, 100, 100,
+ info->WinType.hwndNavigation, NULL, hhctrl_hinstance, NULL);
+ if(!hWnd) {
ERR("Could not create treeview control\n");
return FALSE;
}
+ hImageList = ImageList_Create(16, 16, ILC_COLOR32, 0, HHTV_NUMBITMAPS);
+ hBitmap = LoadBitmapW(hhctrl_hinstance, MAKEINTRESOURCEW(IDB_HHTREEVIEW));
+ ImageList_Add(hImageList, hBitmap, NULL);
+ SendMessageW(hWnd, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)hImageList);
+
+ info->contents.hImageList = hImageList;
+ info->tabs[TAB_CONTENTS].hwnd = hWnd;
ResizeTabChild(info, TAB_CONTENTS);
- ShowWindow(info->tabs[TAB_CONTENTS].hwnd, SW_SHOW);
+ ShowWindow(hWnd, SW_SHOW);
return TRUE;
}
info->search.hwndContainer = hwndContainer;
info->tabs[TAB_SEARCH].hwnd = hwndContainer;
- SetWindowLongPtrW(hwndContainer, GWLP_USERDATA, (LONG_PTR)info);
+ SetWindowLongPtrW(hwndContainer, 0, (LONG_PTR)info);
ResizeTabChild(info, TAB_SEARCH);
static LRESULT CALLBACK HelpPopup_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
- HHInfo *info = (HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
+ HHInfo *info = (HHInfo *)GetWindowLongPtrW(hWnd, 0);
switch (message)
{
switch(nmhdr->code)
{
case NM_DBLCLK: {
- HHInfo *info = (HHInfo*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
+ HHInfo *info = (HHInfo*)GetWindowLongPtrW(hWnd, 0);
IndexSubItem *iter;
if(info == 0 || lParam == 0)
return 0;
}
case NM_RETURN: {
- HHInfo *info = (HHInfo*)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
+ HHInfo *info = (HHInfo*)GetWindowLongPtrW(hWnd, 0);
IndexSubItem *iter;
LVITEMW lvItem;
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = HelpPopup_WndProc;
wcex.cbClsExtra = 0;
- wcex.cbWndExtra = 0;
+ wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = hhctrl_hinstance;
wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
wcex.style = 0;
wcex.lpfnWndProc = PopupChild_WndProc;
wcex.cbClsExtra = 0;
- wcex.cbWndExtra = 0;
+ wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = hhctrl_hinstance;
wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
info->popup.hwndCallback = hwndCallback;
info->popup.hwndPopup = hwndPopup;
info->popup.hwndList = hwndList;
- SetWindowLongPtrW(hwndPopup, GWLP_USERDATA, (LONG_PTR)info);
- SetWindowLongPtrW(hwndCallback, GWLP_USERDATA, (LONG_PTR)info);
+ SetWindowLongPtrW(hwndPopup, 0, (LONG_PTR)info);
+ SetWindowLongPtrW(hwndCallback, 0, (LONG_PTR)info);
ResizePopupChild(info);
ShowWindow(hwndList, SW_SHOW);
/* Viewer Window */
+static void ExpandContract(HHInfo *pHHInfo)
+{
+ RECT r, nav;
+
+ pHHInfo->WinType.fNotExpanded = !pHHInfo->WinType.fNotExpanded;
+ GetWindowRect(pHHInfo->WinType.hwndHelp, &r);
+ NP_GetNavigationRect(pHHInfo, &nav);
+
+ /* hide/show both the nav bar and the size bar */
+ if (pHHInfo->WinType.fNotExpanded)
+ {
+ ShowWindow(pHHInfo->WinType.hwndNavigation, SW_HIDE);
+ ShowWindow(pHHInfo->hwndSizeBar, SW_HIDE);
+ r.left = r.left + nav.right;
+
+ SendMessageW(pHHInfo->WinType.hwndToolBar, TB_HIDEBUTTON, IDTB_EXPAND, MAKELPARAM(FALSE, 0));
+ SendMessageW(pHHInfo->WinType.hwndToolBar, TB_HIDEBUTTON, IDTB_CONTRACT, MAKELPARAM(TRUE, 0));
+ }
+ else
+ {
+ ShowWindow(pHHInfo->WinType.hwndNavigation, SW_SHOW);
+ ShowWindow(pHHInfo->hwndSizeBar, SW_SHOW);
+ r.left = r.left - nav.right;
+
+ SendMessageW(pHHInfo->WinType.hwndToolBar, TB_HIDEBUTTON, IDTB_EXPAND, MAKELPARAM(TRUE, 0));
+ SendMessageW(pHHInfo->WinType.hwndToolBar, TB_HIDEBUTTON, IDTB_CONTRACT, MAKELPARAM(FALSE, 0));
+ }
+
+ MoveWindow(pHHInfo->WinType.hwndHelp, r.left, r.top, r.right-r.left, r.bottom-r.top, TRUE);
+}
+
static LRESULT Help_OnSize(HWND hWnd)
{
- HHInfo *pHHInfo = (HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
+ HHInfo *pHHInfo = (HHInfo *)GetWindowLongPtrW(hWnd, 0);
DWORD dwSize;
RECT rc;
if (!pHHInfo)
return 0;
- NP_GetNavigationRect(pHHInfo, &rc);
- SetWindowPos(pHHInfo->WinType.hwndNavigation, HWND_TOP, 0, 0,
- rc.right, rc.bottom, SWP_NOMOVE);
+ if (navigation_visible(pHHInfo))
+ {
+ NP_GetNavigationRect(pHHInfo, &rc);
+ SetWindowPos(pHHInfo->WinType.hwndNavigation, HWND_TOP, 0, 0,
+ rc.right, rc.bottom, SWP_NOMOVE);
- SB_GetSizeBarRect(pHHInfo, &rc);
- SetWindowPos(pHHInfo->hwndSizeBar, HWND_TOP, rc.left, rc.top,
- rc.right, rc.bottom, SWP_SHOWWINDOW);
+ SB_GetSizeBarRect(pHHInfo, &rc);
+ SetWindowPos(pHHInfo->hwndSizeBar, HWND_TOP, rc.left, rc.top,
+ rc.right, rc.bottom, SWP_SHOWWINDOW);
+
+ }
HP_GetHTMLRect(pHHInfo, &rc);
SetWindowPos(pHHInfo->WinType.hwndHTML, HWND_TOP, rc.left, rc.top,
return 0;
}
+void UpdateHelpWindow(HHInfo *info)
+{
+ if (!info->WinType.hwndHelp)
+ return;
+
+ WARN("Only the size of the window is currently updated.\n");
+ if (info->WinType.fsValidMembers & HHWIN_PARAM_RECT)
+ {
+ RECT *rect = &info->WinType.rcWindowPos;
+ INT x, y, width, height;
+
+ x = rect->left;
+ y = rect->top;
+ width = rect->right - x;
+ height = rect->bottom - y;
+ SetWindowPos(info->WinType.hwndHelp, NULL, rect->left, rect->top, width, height,
+ SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+}
+
static LRESULT CALLBACK Help_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
case WM_SIZE:
return Help_OnSize(hWnd);
case WM_CLOSE:
- ReleaseHelpViewer((HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA));
+ ReleaseHelpViewer((HHInfo *)GetWindowLongPtrW(hWnd, 0));
return 0;
case WM_DESTROY:
if(hh_process)
static BOOL HH_CreateHelpWindow(HHInfo *info)
{
- HWND hWnd;
+ HWND hWnd, parent = 0;
RECT winPos = info->WinType.rcWindowPos;
WNDCLASSEXW wcex;
DWORD dwStyles, dwExStyles;
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = Help_WndProc;
wcex.cbClsExtra = 0;
- wcex.cbWndExtra = 0;
+ wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = hhctrl_hinstance;
wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
/* Read in window parameters if available */
if (info->WinType.fsValidMembers & HHWIN_PARAM_STYLES)
- dwStyles = info->WinType.dwStyles | WS_OVERLAPPEDWINDOW;
+ {
+ dwStyles = info->WinType.dwStyles;
+ if (!(info->WinType.dwStyles & WS_CHILD))
+ dwStyles |= WS_OVERLAPPEDWINDOW;
+ }
else
dwStyles = WS_OVERLAPPEDWINDOW | WS_VISIBLE |
WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
height = WINTYPE_DEFAULT_HEIGHT;
}
+ if (!(info->WinType.fsWinProperties & HHWIN_PROP_TRI_PANE) && info->WinType.fNotExpanded)
+ {
+ if (!(info->WinType.fsValidMembers & HHWIN_PARAM_NAV_WIDTH) &&
+ info->WinType.iNavWidth == 0)
+ {
+ info->WinType.iNavWidth = WINTYPE_DEFAULT_NAVWIDTH;
+ }
+
+ x += info->WinType.iNavWidth;
+ width -= info->WinType.iNavWidth;
+ }
+
+
caption = info->WinType.pszCaption;
if (!*caption) caption = info->pCHMInfo->defTitle;
+ if (info->WinType.dwStyles & WS_CHILD)
+ parent = info->WinType.hwndCaller;
+
hWnd = CreateWindowExW(dwExStyles, windowClassW, caption,
- dwStyles, x, y, width, height, NULL, NULL, hhctrl_hinstance, NULL);
+ dwStyles, x, y, width, height, parent, NULL, hhctrl_hinstance, NULL);
if (!hWnd)
return FALSE;
UpdateWindow(hWnd);
/* store the pointer to the HH info struct */
- SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)info);
+ SetWindowLongPtrW(hWnd, 0, (LONG_PTR)info);
info->WinType.hwndHelp = hWnd;
return TRUE;
{
LOGFONTW lf;
- GetObjectW(GetStockObject(ANSI_VAR_FONT), sizeof(LOGFONTW), &lf);
+ GetObjectW(GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONTW), &lf);
lf.lfWeight = FW_NORMAL;
lf.lfItalic = FALSE;
lf.lfUnderline = FALSE;
InitContent(pHHInfo);
InitIndex(pHHInfo);
+ pHHInfo->viewer_initialized = TRUE;
return TRUE;
}
+void wintype_stringsW_free(struct wintype_stringsW *stringsW)
+{
+ heap_free(stringsW->pszType);
+ heap_free(stringsW->pszCaption);
+ heap_free(stringsW->pszToc);
+ heap_free(stringsW->pszIndex);
+ heap_free(stringsW->pszFile);
+ heap_free(stringsW->pszHome);
+ heap_free(stringsW->pszJump1);
+ heap_free(stringsW->pszJump2);
+ heap_free(stringsW->pszUrlJump1);
+ heap_free(stringsW->pszUrlJump2);
+}
+
+void wintype_stringsA_free(struct wintype_stringsA *stringsA)
+{
+ heap_free(stringsA->pszType);
+ heap_free(stringsA->pszCaption);
+ heap_free(stringsA->pszToc);
+ heap_free(stringsA->pszIndex);
+ heap_free(stringsA->pszFile);
+ heap_free(stringsA->pszHome);
+ heap_free(stringsA->pszJump1);
+ heap_free(stringsA->pszJump2);
+ heap_free(stringsA->pszUrlJump1);
+ heap_free(stringsA->pszUrlJump2);
+ heap_free(stringsA->pszCustomTabs);
+}
+
void ReleaseHelpViewer(HHInfo *info)
{
TRACE("(%p)\n", info);
if (!info)
return;
- /* Free allocated strings */
- heap_free(info->pszType);
- heap_free(info->pszCaption);
- heap_free(info->pszToc);
- heap_free(info->pszIndex);
- heap_free(info->pszFile);
- heap_free(info->pszHome);
- heap_free(info->pszJump1);
- heap_free(info->pszJump2);
- heap_free(info->pszUrlJump1);
- heap_free(info->pszUrlJump2);
+ list_remove(&info->entry);
+
+ wintype_stringsA_free(&info->stringsA);
+ wintype_stringsW_free(&info->stringsW);
if (info->pCHMInfo)
CloseCHM(info->pCHMInfo);
ReleaseIndex(info);
ReleaseSearch(info);
+ if(info->contents.hImageList)
+ ImageList_Destroy(info->contents.hImageList);
if(info->WinType.hwndHelp)
DestroyWindow(info->WinType.hwndHelp);
OleUninitialize();
}
-HHInfo *CreateHelpViewer(LPCWSTR filename)
+HHInfo *CreateHelpViewer(HHInfo *info, LPCWSTR filename, HWND caller)
{
- HHInfo *info = heap_alloc_zero(sizeof(HHInfo));
- int i;
+ HHInfo *tmp_info;
+ unsigned int i;
+
+ if(!info)
+ {
+ info = heap_alloc_zero(sizeof(HHInfo));
+ list_add_tail(&window_list, &info->entry);
+ }
/* Set the invalid tab ID (-1) as the default value for all
* of the tabs, this matches a failed TCM_INSERTITEM call.
ReleaseHelpViewer(info);
return NULL;
}
+ info->WinType.hwndCaller = caller;
- if(!CreateViewer(info)) {
+ /* If the window is already open then load the file in that existing window */
+ if ((tmp_info = find_window(info->WinType.pszType)) && tmp_info != info)
+ {
+ ReleaseHelpViewer(info);
+ return CreateHelpViewer(tmp_info, filename, caller);
+ }
+
+ if(!info->viewer_initialized && !CreateViewer(info)) {
ReleaseHelpViewer(info);
return NULL;
}
return info;
}
+
+/*
+ * Search the table of HTML entities and return the corresponding ANSI symbol.
+ */
+static char find_html_symbol(const char *entity, int entity_len)
+{
+ int max = sizeof(html_encoded_symbols)/sizeof(html_encoded_symbols[0])-1;
+ int min = 0, dir;
+
+ while(min <= max)
+ {
+ int pos = (min+max)/2;
+ const char *encoded_symbol = html_encoded_symbols[pos].html_code;
+ dir = strncmp(encoded_symbol, entity, entity_len);
+ if(dir == 0 && !encoded_symbol[entity_len]) return html_encoded_symbols[pos].ansi_symbol;
+ if(dir < 0)
+ min = pos+1;
+ else
+ max = pos-1;
+ }
+ return 0;
+}
+
+/*
+ * Decode a string containing HTML encoded characters into a unicode string.
+ */
+WCHAR *decode_html(const char *html_fragment, int html_fragment_len, UINT code_page)
+{
+ const char *h = html_fragment, *amp, *sem;
+ char symbol, *tmp;
+ int len, tmp_len = 0;
+ WCHAR *unicode_text;
+
+ tmp = heap_alloc(html_fragment_len+1);
+ while(1)
+ {
+ symbol = 0;
+ amp = strchr(h, '&');
+ if(!amp) break;
+ len = amp-h;
+ /* Copy the characters prior to the HTML encoded character */
+ memcpy(&tmp[tmp_len], h, len);
+ tmp_len += len;
+ amp++; /* skip ampersand */
+ sem = strchr(amp, ';');
+ /* Require a semicolon after the ampersand */
+ if(!sem)
+ {
+ h = amp;
+ tmp[tmp_len++] = '&';
+ continue;
+ }
+ /* Find the symbol either by using the ANSI character number (prefixed by the pound symbol)
+ * or by searching the HTML entity table */
+ len = sem-amp;
+ if(amp[0] == '#')
+ {
+ char *endnum = NULL;
+ int tmp;
+
+ tmp = (char) strtol(amp, &endnum, 10);
+ if(endnum == sem)
+ symbol = tmp;
+ }
+ else
+ symbol = find_html_symbol(amp, len);
+ if(!symbol)
+ {
+ FIXME("Failed to translate HTML encoded character '&%.*s;'.\n", len, amp);
+ h = amp;
+ tmp[tmp_len++] = '&';
+ continue;
+ }
+ /* Insert the new symbol */
+ h = sem+1;
+ tmp[tmp_len++] = symbol;
+ }
+ /* Convert any remaining characters */
+ len = html_fragment_len-(h-html_fragment);
+ memcpy(&tmp[tmp_len], h, len);
+ tmp_len += len;
+ tmp[tmp_len++] = 0; /* NULL-terminate the string */
+
+ len = MultiByteToWideChar(code_page, 0, tmp, tmp_len, NULL, 0);
+ unicode_text = heap_alloc(len*sizeof(WCHAR));
+ MultiByteToWideChar(code_page, 0, tmp, tmp_len, unicode_text, len);
+ heap_free(tmp);
+ return unicode_text;
+}
+
+/* Find the HTMLHelp structure for an existing window title */
+HHInfo *find_window(const WCHAR *window)
+{
+ HHInfo *info;
+
+ LIST_FOR_EACH_ENTRY(info, &window_list, HHInfo, entry)
+ {
+ if (strcmpW(info->WinType.pszType, window) == 0)
+ return info;
+ }
+ return NULL;
+}
#include <wine/debug.h>
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "htmlhelp.h"
+#include "ole2.h"
+#include "rpcproxy.h"
+
#define INIT_GUID
#include "hhctrl.h"
HINSTANCE hhctrl_hinstance;
BOOL hh_process = FALSE;
+extern struct list window_list;
+
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, LPVOID lpvReserved)
{
TRACE("(%p,%d,%p)\n", hInstance, fdwReason, lpvReserved);
#undef X
}
-static BOOL resolve_filename(const WCHAR *filename, WCHAR *fullname, DWORD buflen)
+static BOOL resolve_filename(const WCHAR *filename, WCHAR *fullname, DWORD buflen, WCHAR **index, WCHAR **window)
{
+ const WCHAR *extra;
+ WCHAR chm_file[MAX_PATH];
+
static const WCHAR helpW[] = {'\\','h','e','l','p','\\',0};
+ static const WCHAR delimW[] = {':',':',0};
+ static const WCHAR delim2W[] = {'>',0};
+
+ filename = skip_schema(filename);
+
+ /* the format is "helpFile[::/index][>window]" */
+ if (index) *index = NULL;
+ if (window) *window = NULL;
+
+ extra = strstrW(filename, delim2W);
+ if (extra)
+ {
+ memcpy(chm_file, filename, (extra-filename)*sizeof(WCHAR));
+ chm_file[extra-filename] = 0;
+ filename = chm_file;
+ if (window)
+ *window = strdupW(extra+1);
+ }
+
+ extra = strstrW(filename, delimW);
+ if (extra)
+ {
+ if (filename != chm_file)
+ memcpy(chm_file, filename, (extra-filename)*sizeof(WCHAR));
+ chm_file[extra-filename] = 0;
+ filename = chm_file;
+ if (index)
+ *index = strdupW(extra+2);
+ }
GetFullPathNameW(filename, buflen, fullname, NULL);
if (GetFileAttributesW(fullname) == INVALID_FILE_ATTRIBUTES)
{
case HH_DISPLAY_TOPIC:
case HH_DISPLAY_TOC:
+ case HH_DISPLAY_INDEX:
case HH_DISPLAY_SEARCH:{
- static const WCHAR delimW[] = {':',':',0};
- HHInfo *info;
BOOL res;
- WCHAR chm_file[MAX_PATH];
- const WCHAR *index;
-
- FIXME("Not all HH cases handled correctly\n");
+ NMHDR nmhdr;
+ HHInfo *info = NULL;
+ WCHAR *window = NULL;
+ const WCHAR *index = NULL;
+ WCHAR *default_index = NULL;
+ int tab_index = TAB_CONTENTS;
if (!filename)
return NULL;
- index = strstrW(filename, delimW);
- if (index)
- {
- memcpy(chm_file, filename, (index-filename)*sizeof(WCHAR));
- chm_file[index-filename] = 0;
- filename = chm_file;
- index += 2; /* advance beyond "::" for calling NavigateToChm() later */
- }
-
- if (!resolve_filename(filename, fullname, MAX_PATH))
+ if (!resolve_filename(filename, fullname, MAX_PATH, &default_index, &window))
{
WARN("can't find %s\n", debugstr_w(filename));
return 0;
}
+ index = default_index;
+
+ if (window)
+ info = find_window(window);
- info = CreateHelpViewer(fullname);
+ info = CreateHelpViewer(info, fullname, caller);
if(!info)
+ {
+ heap_free(default_index);
+ heap_free(window);
return NULL;
+ }
if(!index)
index = info->WinType.pszFile;
+ if(!info->WinType.pszType)
+ info->WinType.pszType = info->stringsW.pszType = window;
+ else
+ heap_free(window);
+
+ /* called to load a specified topic */
+ switch(command)
+ {
+ case HH_DISPLAY_TOPIC:
+ case HH_DISPLAY_TOC:
+ if (data)
+ index = (const WCHAR *)data;
+ break;
+ }
res = NavigateToChm(info, info->pCHMInfo->szFile, index);
+ heap_free(default_index);
+
if(!res)
{
ReleaseHelpViewer(info);
return NULL;
}
+
+ switch(command)
+ {
+ case HH_DISPLAY_TOPIC:
+ case HH_DISPLAY_TOC:
+ tab_index = TAB_CONTENTS;
+ break;
+ case HH_DISPLAY_INDEX:
+ tab_index = TAB_INDEX;
+ if (data)
+ FIXME("Should select keyword '%s'.\n", debugstr_w((WCHAR *)data));
+ break;
+ case HH_DISPLAY_SEARCH:
+ tab_index = TAB_SEARCH;
+ if (data)
+ FIXME("Should display search specified by HH_FTS_QUERY structure.\n");
+ break;
+ }
+ /* open the requested tab */
+ memset(&nmhdr, 0, sizeof(nmhdr));
+ nmhdr.code = TCN_SELCHANGE;
+ SendMessageW(info->hwndTabCtrl, TCM_SETCURSEL, (WPARAM)info->tabs[tab_index].id, 0);
+ SendMessageW(info->WinType.hwndNavigation, WM_NOTIFY, 0, (LPARAM)&nmhdr);
+
return info->WinType.hwndHelp;
}
case HH_HELP_CONTEXT: {
- HHInfo *info;
+ WCHAR *window = NULL;
+ HHInfo *info = NULL;
LPWSTR url;
if (!filename)
return NULL;
- if (!resolve_filename(filename, fullname, MAX_PATH))
+ if (!resolve_filename(filename, fullname, MAX_PATH, NULL, &window))
{
WARN("can't find %s\n", debugstr_w(filename));
return 0;
}
- info = CreateHelpViewer(fullname);
+ if (window)
+ info = find_window(window);
+
+ info = CreateHelpViewer(info, fullname, caller);
if(!info)
+ {
+ heap_free(window);
return NULL;
+ }
+
+ if(!info->WinType.pszType)
+ info->WinType.pszType = info->stringsW.pszType = window;
+ else
+ heap_free(window);
url = FindContextAlias(info->pCHMInfo, data);
if(!url)
}
return 0;
}
+ case HH_CLOSE_ALL: {
+ HHInfo *info, *next;
+
+ LIST_FOR_EACH_ENTRY_SAFE(info, next, &window_list, HHInfo, entry)
+ {
+ TRACE("Destroying window %s.\n", debugstr_w(info->WinType.pszType));
+ ReleaseHelpViewer(info);
+ }
+ return 0;
+ }
+ case HH_SET_WIN_TYPE: {
+ HH_WINTYPEW *wintype = (HH_WINTYPEW *)data;
+ WCHAR *window = NULL;
+ HHInfo *info = NULL;
+
+ if (!filename && wintype->pszType)
+ window = strdupW(wintype->pszType);
+ else if (!filename || !resolve_filename(filename, fullname, MAX_PATH, NULL, &window) || !window)
+ {
+ WARN("can't find window name: %s\n", debugstr_w(filename));
+ return 0;
+ }
+ info = find_window(window);
+ if (!info)
+ {
+ info = heap_alloc_zero(sizeof(HHInfo));
+ info->WinType.pszType = info->stringsW.pszType = window;
+ list_add_tail(&window_list, &info->entry);
+ }
+ else
+ heap_free(window);
+
+ TRACE("Changing WINTYPE, fsValidMembers=0x%x\n", wintype->fsValidMembers);
+
+ MergeChmProperties(wintype, info, TRUE);
+ UpdateHelpWindow(info);
+ return 0;
+ }
+ case HH_GET_WIN_TYPE: {
+ HH_WINTYPEW *wintype = (HH_WINTYPEW *)data;
+ WCHAR *window = NULL;
+ HHInfo *info = NULL;
+
+ if (!filename || !resolve_filename(filename, fullname, MAX_PATH, NULL, &window) || !window)
+ {
+ WARN("can't find window name: %s\n", debugstr_w(filename));
+ return 0;
+ }
+ info = find_window(window);
+ if (!info)
+ {
+ WARN("Could not find window named %s.\n", debugstr_w(window));
+ heap_free(window);
+ return (HWND)~0;
+ }
+
+ TRACE("Retrieving WINTYPE for %s.\n", debugstr_w(window));
+ *wintype = info->WinType;
+ heap_free(window);
+ return 0;
+ }
default:
FIXME("HH case %s not handled.\n", command_to_string( command ));
}
return 0;
}
+static void wintypeAtoW(const HH_WINTYPEA *data, HH_WINTYPEW *wdata, struct wintype_stringsW *stringsW)
+{
+ memcpy(wdata, data, sizeof(*data));
+ /* convert all of the ANSI strings to Unicode */
+ wdata->pszType = stringsW->pszType = strdupAtoW(data->pszType);
+ wdata->pszCaption = stringsW->pszCaption = strdupAtoW(data->pszCaption);
+ wdata->pszToc = stringsW->pszToc = strdupAtoW(data->pszToc);
+ wdata->pszIndex = stringsW->pszIndex = strdupAtoW(data->pszIndex);
+ wdata->pszFile = stringsW->pszFile = strdupAtoW(data->pszFile);
+ wdata->pszHome = stringsW->pszHome = strdupAtoW(data->pszHome);
+ wdata->pszJump1 = stringsW->pszJump1 = strdupAtoW(data->pszJump1);
+ wdata->pszJump2 = stringsW->pszJump2 = strdupAtoW(data->pszJump2);
+ wdata->pszUrlJump1 = stringsW->pszUrlJump1 = strdupAtoW(data->pszUrlJump1);
+ wdata->pszUrlJump2 = stringsW->pszUrlJump2 = strdupAtoW(data->pszUrlJump2);
+ wdata->pszCustomTabs = stringsW->pszCustomTabs = strdupAtoW(data->pszCustomTabs);
+}
+
+static void wintypeWtoA(const HH_WINTYPEW *wdata, HH_WINTYPEA *data, struct wintype_stringsA *stringsA)
+{
+ memcpy(data, wdata, sizeof(*wdata));
+ /* convert all of the Unicode strings to ANSI */
+ data->pszType = stringsA->pszType = strdupWtoA(wdata->pszType);
+ data->pszCaption = stringsA->pszCaption = strdupWtoA(wdata->pszCaption);
+ data->pszToc = stringsA->pszToc = strdupWtoA(wdata->pszToc);
+ data->pszIndex = stringsA->pszFile = strdupWtoA(wdata->pszIndex);
+ data->pszFile = stringsA->pszFile = strdupWtoA(wdata->pszFile);
+ data->pszHome = stringsA->pszHome = strdupWtoA(wdata->pszHome);
+ data->pszJump1 = stringsA->pszJump1 = strdupWtoA(wdata->pszJump1);
+ data->pszJump2 = stringsA->pszJump2 = strdupWtoA(wdata->pszJump2);
+ data->pszUrlJump1 = stringsA->pszUrlJump1 = strdupWtoA(wdata->pszUrlJump1);
+ data->pszUrlJump2 = stringsA->pszUrlJump2 = strdupWtoA(wdata->pszUrlJump2);
+ data->pszCustomTabs = stringsA->pszCustomTabs = strdupWtoA(wdata->pszCustomTabs);
+}
+
/******************************************************************
* HtmlHelpA (HHCTRL.OCX.14)
*/
HWND WINAPI HtmlHelpA(HWND caller, LPCSTR filename, UINT command, DWORD_PTR data)
{
- WCHAR *wfile = NULL, *wdata = NULL;
- DWORD len;
- HWND result;
-
- if (filename)
- {
- len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
- wfile = heap_alloc(len*sizeof(WCHAR));
- MultiByteToWideChar( CP_ACP, 0, filename, -1, wfile, len );
- }
+ WCHAR *wfile = strdupAtoW( filename );
+ HWND result = 0;
if (data)
{
case HH_DISPLAY_SEARCH:
case HH_DISPLAY_TEXT_POPUP:
case HH_GET_LAST_ERROR:
- case HH_GET_WIN_TYPE:
case HH_KEYWORD_LOOKUP:
- case HH_SET_WIN_TYPE:
case HH_SYNC:
FIXME("structures not handled yet\n");
break;
+ case HH_SET_WIN_TYPE:
+ {
+ struct wintype_stringsW stringsW;
+ HH_WINTYPEW wdata;
+
+ wintypeAtoW((HH_WINTYPEA *)data, &wdata, &stringsW);
+ result = HtmlHelpW( caller, wfile, command, (DWORD_PTR)&wdata );
+ wintype_stringsW_free(&stringsW);
+ goto done;
+ }
+ case HH_GET_WIN_TYPE:
+ {
+ HH_WINTYPEW wdata;
+ HHInfo *info;
+
+ result = HtmlHelpW( caller, wfile, command, (DWORD_PTR)&wdata );
+ if (!wdata.pszType) break;
+ info = find_window(wdata.pszType);
+ if (!info) break;
+ wintype_stringsA_free(&info->stringsA);
+ wintypeWtoA(&wdata, (HH_WINTYPEA *)data, &info->stringsA);
+ goto done;
+ }
+
case HH_DISPLAY_INDEX:
case HH_DISPLAY_TOPIC:
case HH_DISPLAY_TOC:
case HH_GET_WIN_HANDLE:
case HH_SAFE_DISPLAY_TOPIC:
- len = MultiByteToWideChar( CP_ACP, 0, (const char*)data, -1, NULL, 0 );
- wdata = heap_alloc(len*sizeof(WCHAR));
- MultiByteToWideChar( CP_ACP, 0, (const char*)data, -1, wdata, len );
- break;
+ {
+ WCHAR *wdata = strdupAtoW( (const char *)data );
+ result = HtmlHelpW( caller, wfile, command, (DWORD_PTR)wdata );
+ heap_free(wdata);
+ goto done;
+ }
case HH_CLOSE_ALL:
case HH_HELP_CONTEXT:
}
}
- result = HtmlHelpW( caller, wfile, command, wdata ? (DWORD_PTR)wdata : data );
-
+ result = HtmlHelpW( caller, wfile, command, data );
+done:
heap_free(wfile);
- heap_free(wdata);
return result;
}
int len, buflen, mapid = -1;
WCHAR *filename;
char *endq = NULL;
+ HWND hwnd;
hh_process = TRUE;
ptr += strlen("mapid")+1;
space = strchr(ptr, ' ');
+ /* command line ends without number */
+ if (!space)
+ return 0;
memcpy(idtxt, ptr, space-ptr);
idtxt[space-ptr] = '\0';
mapid = atoi(idtxt);
len = endq - szCmdLine;
else
len = strlen(szCmdLine);
+
+ /* no filename given */
+ if (!len)
+ return 0;
+
buflen = MultiByteToWideChar(CP_ACP, 0, szCmdLine, len, NULL, 0) + 1;
filename = heap_alloc(buflen * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, szCmdLine, len, filename, buflen);
/* Open a specific help topic */
if(mapid != -1)
- HtmlHelpW(GetDesktopWindow(), filename, HH_HELP_CONTEXT, mapid);
+ hwnd = HtmlHelpW(GetDesktopWindow(), filename, HH_HELP_CONTEXT, mapid);
else
- HtmlHelpW(GetDesktopWindow(), filename, HH_DISPLAY_TOPIC, 0);
+ hwnd = HtmlHelpW(GetDesktopWindow(), filename, HH_DISPLAY_TOPIC, 0);
heap_free(filename);
+ if (!hwnd)
+ {
+ ERR("Failed to open HTML Help file '%s'.\n", szCmdLine);
+ return 0;
+ }
+
while (GetMessageW(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
FIXME("(%s %s %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
return CLASS_E_CLASSNOTAVAILABLE;
}
+
+/***********************************************************************
+ * DllRegisterServer (HHCTRL.OCX.@)
+ */
+HRESULT WINAPI DllRegisterServer(void)
+{
+ return __wine_register_resources( hhctrl_hinstance );
+}
+
+/***********************************************************************
+ * DllUnregisterServer (HHCTRL.OCX.@)
+ */
+HRESULT WINAPI DllUnregisterServer(void)
+{
+ return __wine_unregister_resources( hhctrl_hinstance );
+}
#include <wine/itss.h>
#include <wine/unicode.h>
+#include <wine/list.h>
#define WB_GOBACK 0
#define WB_GOFORWARD 1
#define WB_SEARCH 3
#define WB_REFRESH 4
#define WB_STOP 5
+#define WB_PRINT 6
typedef struct {
LPWSTR chm_file;
char **strings;
DWORD strings_size;
+ WCHAR *compiledFile;
+ WCHAR *defWindow;
WCHAR *defTopic;
WCHAR *defTitle;
WCHAR *defToc;
+
+ UINT codePage;
} CHMInfo;
#define TAB_CONTENTS 0
#define TAB_INDEX 1
#define TAB_SEARCH 2
#define TAB_FAVORITES 3
+#define TAB_NUMTABS TAB_FAVORITES
typedef struct {
HWND hwnd;
HWND hwndContainer;
} SearchTab;
+typedef struct {
+ HIMAGELIST hImageList;
+} ContentsTab;
+
+struct wintype_stringsW {
+ WCHAR *pszType;
+ WCHAR *pszCaption;
+ WCHAR *pszToc;
+ WCHAR *pszIndex;
+ WCHAR *pszFile;
+ WCHAR *pszHome;
+ WCHAR *pszJump1;
+ WCHAR *pszJump2;
+ WCHAR *pszUrlJump1;
+ WCHAR *pszUrlJump2;
+ WCHAR *pszCustomTabs;
+};
+
+struct wintype_stringsA {
+ char *pszType;
+ char *pszCaption;
+ char *pszToc;
+ char *pszIndex;
+ char *pszFile;
+ char *pszHome;
+ char *pszJump1;
+ char *pszJump2;
+ char *pszUrlJump1;
+ char *pszUrlJump2;
+ char *pszCustomTabs;
+};
+
typedef struct {
IOleClientSite *client_site;
IWebBrowser2 *web_browser;
HH_WINTYPEW WinType;
- LPWSTR pszType;
- LPWSTR pszCaption;
- LPWSTR pszToc;
- LPWSTR pszIndex;
- LPWSTR pszFile;
- LPWSTR pszHome;
- LPWSTR pszJump1;
- LPWSTR pszJump2;
- LPWSTR pszUrlJump1;
- LPWSTR pszUrlJump2;
- LPWSTR pszCustomTabs;
+ struct wintype_stringsA stringsA;
+ struct wintype_stringsW stringsW;
+ struct list entry;
CHMInfo *pCHMInfo;
ContentItem *content;
IndexItem *index;
IndexPopup popup;
SearchTab search;
+ ContentsTab contents;
HWND hwndTabCtrl;
HWND hwndSizeBar;
HFONT hFont;
HHTab tabs[TAB_FAVORITES+1];
+ int viewer_initialized;
DWORD current_tab;
} HHInfo;
-BOOL InitWebBrowser(HHInfo*,HWND);
-void ReleaseWebBrowser(HHInfo*);
-void ResizeWebBrowser(HHInfo*,DWORD,DWORD);
-void DoPageAction(HHInfo*,DWORD);
-
-void InitContent(HHInfo*);
-void ReleaseContent(HHInfo*);
-
-void InitIndex(HHInfo*);
-void ReleaseIndex(HHInfo*);
-
-CHMInfo *OpenCHM(LPCWSTR szFile);
-BOOL LoadWinTypeFromCHM(HHInfo *info);
-CHMInfo *CloseCHM(CHMInfo *pCHMInfo);
-void SetChmPath(ChmPath*,LPCWSTR,LPCWSTR);
-IStream *GetChmStream(CHMInfo*,LPCWSTR,ChmPath*);
-LPWSTR FindContextAlias(CHMInfo*,DWORD);
-
-HHInfo *CreateHelpViewer(LPCWSTR);
-void ReleaseHelpViewer(HHInfo*);
-BOOL NavigateToUrl(HHInfo*,LPCWSTR);
-BOOL NavigateToChm(HHInfo*,LPCWSTR,LPCWSTR);
-
-void InitSearch(HHInfo *info, const char *needle);
-void ReleaseSearch(HHInfo *info);
+BOOL InitWebBrowser(HHInfo*,HWND) DECLSPEC_HIDDEN;
+void ReleaseWebBrowser(HHInfo*) DECLSPEC_HIDDEN;
+void ResizeWebBrowser(HHInfo*,DWORD,DWORD) DECLSPEC_HIDDEN;
+void DoPageAction(HHInfo*,DWORD) DECLSPEC_HIDDEN;
+
+void InitContent(HHInfo*) DECLSPEC_HIDDEN;
+void ReleaseContent(HHInfo*) DECLSPEC_HIDDEN;
+void ActivateContentTopic(HWND,LPCWSTR,ContentItem *) DECLSPEC_HIDDEN;
+
+void InitIndex(HHInfo*) DECLSPEC_HIDDEN;
+void ReleaseIndex(HHInfo*) DECLSPEC_HIDDEN;
+
+CHMInfo *OpenCHM(LPCWSTR szFile) DECLSPEC_HIDDEN;
+BOOL LoadWinTypeFromCHM(HHInfo *info) DECLSPEC_HIDDEN;
+CHMInfo *CloseCHM(CHMInfo *pCHMInfo) DECLSPEC_HIDDEN;
+void SetChmPath(ChmPath*,LPCWSTR,LPCWSTR) DECLSPEC_HIDDEN;
+IStream *GetChmStream(CHMInfo*,LPCWSTR,ChmPath*) DECLSPEC_HIDDEN;
+LPWSTR FindContextAlias(CHMInfo*,DWORD) DECLSPEC_HIDDEN;
+WCHAR *GetDocumentTitle(CHMInfo*,LPCWSTR) DECLSPEC_HIDDEN;
+
+HHInfo *CreateHelpViewer(HHInfo*,LPCWSTR,HWND) DECLSPEC_HIDDEN;
+void ReleaseHelpViewer(HHInfo*) DECLSPEC_HIDDEN;
+BOOL NavigateToUrl(HHInfo*,LPCWSTR) DECLSPEC_HIDDEN;
+BOOL NavigateToChm(HHInfo*,LPCWSTR,LPCWSTR) DECLSPEC_HIDDEN;
+void MergeChmProperties(HH_WINTYPEW*,HHInfo*,BOOL) DECLSPEC_HIDDEN;
+void UpdateHelpWindow(HHInfo *info) DECLSPEC_HIDDEN;
+
+void InitSearch(HHInfo *info, const char *needle) DECLSPEC_HIDDEN;
+void ReleaseSearch(HHInfo *info) DECLSPEC_HIDDEN;
+
+LPCWSTR skip_schema(LPCWSTR url) DECLSPEC_HIDDEN;
+void wintype_stringsA_free(struct wintype_stringsA *stringsA) DECLSPEC_HIDDEN;
+void wintype_stringsW_free(struct wintype_stringsW *stringsW) DECLSPEC_HIDDEN;
+WCHAR *decode_html(const char *html_fragment, int html_fragment_len, UINT code_page) DECLSPEC_HIDDEN;
+HHInfo *find_window(const WCHAR *window) DECLSPEC_HIDDEN;
/* memory allocation functions */
return strdupnAtoW(str, -1);
}
+static inline LPSTR strdupWtoA(LPCWSTR str)
+{
+ LPSTR ret;
+ DWORD len;
+
+ if(!str)
+ return NULL;
+
+ len = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
+ ret = heap_alloc(len);
+ WideCharToMultiByte(CP_ACP, 0, str, -1, ret, len, NULL, NULL);
+ return ret;
+}
-extern HINSTANCE hhctrl_hinstance;
-extern BOOL hh_process;
+extern HINSTANCE hhctrl_hinstance DECLSPEC_HIDDEN;
+extern BOOL hh_process DECLSPEC_HIDDEN;
#endif
* HTML Help resources
*
* Copyright 2005 James Hawkins
+ * Copyright 2011 Owen Rudge for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
//#include "htmlhelp.h"
//#include "resource.h"
-LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
-
-#include "version.rc"
-
#ifdef LANGUAGE_CS_CZ
#include "Cs.rc"
#endif
#include "Zh.rc"
#endif
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+
+/* @makedep: hhtoolbar.bmp */
+IDB_HHTOOLBAR BITMAP hhtoolbar.bmp
+
+/* @makedep: hhtreeview.bmp */
+IDB_HHTREEVIEW BITMAP hhtreeview.bmp
+
+1 TYPELIB hhctrl_tlb.tlb
+
+#define WINE_FILEDESCRIPTION_STR "Wine htmlhelp OCX"
+#define WINE_FILENAME_STR "hhctrl.ocx"
+#define WINE_FILEVERSION 5,2,3790,2744
+#define WINE_FILEVERSION_STR "5.2.3790.2744"
+#define WINE_PRODUCTVERSION 5,2,3790,2744
+#define WINE_PRODUCTVERSION_STR "5.2.3790.2744"
+
+#include <wine/wine_common_ver.rc>
--- /dev/null
+/*
+ * Typelib for hhctrl
+ *
+ * Copyright 2010 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+import "unknwn.idl";
+import "objidl.idl";
+import "oaidl.idl";
+
+[
+ helpstring("HHCtrl 4.0 Type Library"),
+ version(4.0),
+ uuid(adb880a2-d8ff-11cf-9377-00aa003b7a11)
+]
+library HHCTRLLib
+{
+ importlib("stdole2.tlb");
+
+ [
+ helpstring("IHHCtrl Interface"),
+ odl,
+ dual,
+ oleautomation,
+ uuid(adb880a1-d8ff-11cf-9377-00aa003b7a11)
+ ]
+ interface IHHCtrl : IDispatch
+ {
+ /* FIXME */
+ }
+
+ [
+ helpstring("Event interface for HHCtrl"),
+ uuid(adb880a3-d8ff-11cf-9377-00aa003b7a11)
+ ]
+ dispinterface _HHCtrlEvents
+ {
+ properties:
+ methods:
+ [id(0)] void Click(BSTR ParamString);
+ }
+
+ [
+ helpstring("HHCtrl Object"),
+ progid("Internet.HHCtrl.1"),
+ vi_progid("Internet.HHCtrl"),
+ threading(apartment),
+ version(1.0),
+ uuid(adb880a6-d8ff-11cf-9377-00aa003b7a11)
+ ]
+ coclass OldHHCtrl1
+ {
+ [default] interface IHHCtrl;
+ [default, source] dispinterface _HHCtrlEvents;
+ }
+
+ [
+ helpstring("HHCtrl Object"),
+ progid("Internet.HHCtrl.1"),
+ vi_progid("Internet.HHCtrl"),
+ threading(apartment),
+ version(1.0),
+ uuid(41b23c28-488e-4e5c-ace2-bb0bbabe99e8)
+ ]
+ coclass OldHHCtrl2
+ {
+ [default] interface IHHCtrl;
+ [default, source] dispinterface _HHCtrlEvents;
+ }
+
+ [
+ helpstring("HHCtrl Object"),
+ progid("Internet.HHCtrl.1"),
+ vi_progid("Internet.HHCtrl"),
+ threading(apartment),
+ version(1.0),
+ uuid(52a2aaae-085d-4187-97ea-8c30db990436)
+ ]
+ coclass HHCtrl
+ {
+ [default] interface IHHCtrl;
+ [default, source] dispinterface _HHCtrlEvents;
+ }
+}
}
}
+static void item_realloc(IndexItem *item, int num_items)
+{
+ item->nItems = num_items;
+ item->items = heap_realloc(item->items, sizeof(IndexSubItem)*item->nItems);
+ item->items[item->nItems-1].name = NULL;
+ item->items[item->nItems-1].local = NULL;
+ item->itemFlags = 0x00;
+}
+
/* Parse the attributes correspond to a list item, including sub-topics.
*
* Each list item has, at minimum, a param of type "keyword" and two
* sub-topic then there isn't really a sub-topic, the index will jump
* directly to the requested item.
*/
-static void parse_index_obj_node_param(IndexItem *item, const char *text)
+static void parse_index_obj_node_param(IndexItem *item, const char *text, UINT code_page)
{
const char *ptr;
LPWSTR *param;
- int len, wlen;
+ int len;
ptr = get_attr(text, "name", &len);
if(!ptr) {
/* Allocate a new sub-item, either on the first run or whenever a
* sub-topic has filled out both the "name" and "local" params.
*/
- if(item->itemFlags == 0x11 && (!strncasecmp("name", ptr, len) || !strncasecmp("local", ptr, len))) {
- item->nItems++;
- item->items = heap_realloc(item->items, sizeof(IndexSubItem)*item->nItems);
- item->items[item->nItems-1].name = NULL;
- item->items[item->nItems-1].local = NULL;
- item->itemFlags = 0x00;
- }
+ if(item->itemFlags == 0x11 && (!strncasecmp("name", ptr, len) || !strncasecmp("local", ptr, len)))
+ item_realloc(item, item->nItems+1);
if(!strncasecmp("keyword", ptr, len)) {
param = &item->keyword;
}else if(!item->keyword && !strncasecmp("name", ptr, len)) {
/* Some HTML Help index files use an additional "name" parameter
* rather than the "keyword" parameter. In this case, the first
- * occurance of the "name" parameter is the keyword.
+ * occurrence of the "name" parameter is the keyword.
*/
param = &item->keyword;
}else if(!strncasecmp("name", ptr, len)) {
return;
}
- wlen = MultiByteToWideChar(CP_ACP, 0, ptr, len, NULL, 0);
- *param = heap_alloc((wlen+1)*sizeof(WCHAR));
- MultiByteToWideChar(CP_ACP, 0, ptr, len, *param, wlen);
- (*param)[wlen] = 0;
+ *param = decode_html(ptr, len, code_page);
}
/* Parse the object tag corresponding to a list item.
TRACE("%s\n", node.buf);
if(!strcasecmp(node_name.buf, "param")) {
- parse_index_obj_node_param(item, node.buf);
+ parse_index_obj_node_param(item, node.buf, info->pCHMInfo->codePage);
}else if(!strcasecmp(node_name.buf, "/object")) {
break;
}else {
strbuf_zero(&node);
}
+ if(!ret)
+ FIXME("Failed to parse <li> tag!\n");
strbuf_free(&node);
strbuf_free(&node_name);
TRACE("%s\n", node.buf);
if(!strcasecmp(node_name.buf, "li")) {
- item->next = parse_li(info, &stream);
- item->next->merge = item->merge;
- item = item->next;
- item->indentLevel = indent_level;
+ IndexItem *new_item;
+
+ new_item = parse_li(info, &stream);
+ if(new_item && item->keyword && strcmpW(new_item->keyword, item->keyword) == 0) {
+ int num_items = item->nItems;
+
+ item_realloc(item, num_items+1);
+ memcpy(&item->items[num_items], &new_item->items[0], sizeof(IndexSubItem));
+ heap_free(new_item->keyword);
+ heap_free(new_item->items);
+ heap_free(new_item);
+ } else if(new_item) {
+ item->next = new_item;
+ item->next->merge = item->merge;
+ item = item->next;
+ item->indentLevel = indent_level;
+ }
}else if(!strcasecmp(node_name.buf, "ul")) {
indent_level++;
}else if(!strcasecmp(node_name.buf, "/ul")) {
IndexItem *item = info->index, *next;
int i;
+ if(!item) return;
/* Note: item->merge is identical for all items, only free once */
heap_free(item->merge.chm_file);
heap_free(item->merge.chm_index);
#define IDS_INDEX 2
#define IDS_SEARCH 3
#define IDS_FAVORITES 4
+#define IDS_HIDETABS 5
+#define IDS_SHOWTABS 6
+
+#define MENU_POPUP 1
+
+#define IDB_HHTOOLBAR 1000
+/* IDB_HHTOOLBAR bitmaps: */
+#define HHTB_STOP 0
+#define HHTB_REFRESH 1
+#define HHTB_HOME 2
+#define HHTB_SYNC 3
+#define HHTB_CONTRACT 4
+#define HHTB_EXPAND 5
+#define HHTB_NUMBITMAPS HHTB_EXPAND
+
+#define IDB_HHTREEVIEW 1001
+/* IDB_HHTREEVIEW bitmaps: */
+#define HHTV_DOCUMENT 0
+#define HHTV_FOLDER 1
+#define HHTV_OPENFOLDER 2
+#define HHTV_NUMBITMAPS HHTV_OPENFOLDER
FIXME("Unhandled IStorage stream element.\n");
}
}
+ IEnumSTATSTG_Release(elem);
return item;
}
heap_free(buf->buf);
}
-void strbuf_append(strbuf_t *buf, const char *data, int len)
+static void strbuf_append(strbuf_t *buf, const char *data, int len)
{
if(buf->len+len > buf->size) {
buf->size = buf->len+len;
stream->str = str;
}
-BOOL stream_chr(stream_t *stream, strbuf_t *buf, char c)
+static BOOL stream_chr(stream_t *stream, strbuf_t *buf, char c)
{
BOOL b = TRUE;
ULONG i;
#ifndef HHCTRL_STREAM_H
#define HHCTRL_STREAM_H
-#define BLOCK_SIZE 0x1000
+#define BLOCK_BITS 12
+#define BLOCK_SIZE (1 << BLOCK_BITS)
+#define BLOCK_MASK (BLOCK_SIZE-1)
typedef struct {
char *buf;
ULONG p;
} stream_t;
-void strbuf_init(strbuf_t *buf);
-void strbuf_zero(strbuf_t *buf);
-void strbuf_free(strbuf_t *buf);
-void strbuf_append(strbuf_t *buf, const char *data, int len);
-void stream_init(stream_t *stream, IStream *str);
-BOOL stream_chr(stream_t *stream, strbuf_t *buf, char c);
-void get_node_name(strbuf_t *node, strbuf_t *name);
-BOOL next_content(stream_t *stream, strbuf_t *buf);
-BOOL next_node(stream_t *stream, strbuf_t *buf);
-const char *get_attr(const char *node, const char *name, int *len);
+void strbuf_init(strbuf_t *buf) DECLSPEC_HIDDEN;
+void strbuf_zero(strbuf_t *buf) DECLSPEC_HIDDEN;
+void strbuf_free(strbuf_t *buf) DECLSPEC_HIDDEN;
+void stream_init(stream_t *stream, IStream *str) DECLSPEC_HIDDEN;
+void get_node_name(strbuf_t *node, strbuf_t *name) DECLSPEC_HIDDEN;
+BOOL next_content(stream_t *stream, strbuf_t *buf) DECLSPEC_HIDDEN;
+BOOL next_node(stream_t *stream, strbuf_t *buf) DECLSPEC_HIDDEN;
+const char *get_attr(const char *node, const char *name, int *len) DECLSPEC_HIDDEN;
#endif
+++ /dev/null
-/*
- * Version information for hhctrl.ocx
- *
- * Copyright 2004 Hans Leidekker
- * Copyright 2004 Tom Wickline
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#define WINE_FILEDESCRIPTION_STR "Wine htmlhelp OCX"
-#define WINE_FILENAME_STR "hhctrl.ocx"
-#define WINE_FILEVERSION 5,2,3790,2744
-#define WINE_FILEVERSION_STR "5.2.3790.2744"
-#define WINE_PRODUCTVERSION 5,2,3790,2744
-#define WINE_PRODUCTVERSION_STR "5.2.3790.2744"
-
-#include <wine/wine_common_ver.rc>
WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp);
-#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
-
typedef struct IOleClientSiteImpl
{
- const IOleClientSiteVtbl *lpVtbl;
- const IOleInPlaceSiteVtbl *lpvtblOleInPlaceSite;
- const IOleInPlaceFrameVtbl *lpvtblOleInPlaceFrame;
- const IDocHostUIHandlerVtbl *lpvtblDocHostUIHandler;
+ IOleClientSite IOleClientSite_iface;
+ IOleInPlaceSite IOleInPlaceSite_iface;
+ IOleInPlaceFrame IOleInPlaceFrame_iface;
+ IDocHostUIHandler IDocHostUIHandler_iface;
/* IOleClientSiteImpl data */
IOleObject *pBrowserObject;
HWND hwndWindow;
} IOleClientSiteImpl;
-#define CLIENTSITE(x) ((IOleClientSite*) &(x)->lpVtbl)
-#define DOCHOSTUI(x) ((IDocHostUIHandler*) &(x)->lpvtblDocHostUIHandler)
-#define INPLACESITE(x) ((IOleInPlaceSite*) &(x)->lpvtblOleInPlaceSite)
-#define INPLACEFRAME(x) ((IOleInPlaceFrame*) &(x)->lpvtblOleInPlaceFrame)
+static inline IOleClientSiteImpl *impl_from_IOleClientSite(IOleClientSite *iface)
+{
+ return CONTAINING_RECORD(iface, IOleClientSiteImpl, IOleClientSite_iface);
+}
static HRESULT STDMETHODCALLTYPE Site_QueryInterface(IOleClientSite *iface, REFIID riid, void **ppvObj)
{
- ICOM_THIS_MULTI(IOleClientSiteImpl, lpVtbl, iface);
+ IOleClientSiteImpl *This = impl_from_IOleClientSite(iface);
*ppvObj = NULL;
if (IsEqualIID(riid, &IID_IUnknown)) {
TRACE("(%p)->(IID_IUnknown %p)\n", This, ppvObj);
- *ppvObj = CLIENTSITE(This);
+ *ppvObj = &This->IOleClientSite_iface;
}else if(IsEqualIID(riid, &IID_IOleClientSite)) {
TRACE("(%p)->(IID_IOleClientSite %p)\n", This, ppvObj);
- *ppvObj = CLIENTSITE(This);
+ *ppvObj = &This->IOleClientSite_iface;
}else if (IsEqualIID(riid, &IID_IOleInPlaceSite)) {
TRACE("(%p)->(IID_IOleInPlaceSite %p)\n", This, ppvObj);
- *ppvObj = &(This->lpvtblOleInPlaceSite);
+ *ppvObj = &This->IOleInPlaceSite_iface;
}else if (IsEqualIID(riid, &IID_IOleInPlaceFrame)) {
TRACE("(%p)->(IID_IOleInPlaceFrame %p)\n", This, ppvObj);
- *ppvObj = &(This->lpvtblOleInPlaceSite);
+ *ppvObj = &This->IOleInPlaceSite_iface;
}else if (IsEqualIID(riid, &IID_IDocHostUIHandler)) {
TRACE("(%p)->(IID_IDocHostUIHandler %p)\n", This, ppvObj);
- *ppvObj = &(This->lpvtblDocHostUIHandler);
+ *ppvObj = &This->IDocHostUIHandler_iface;
}else {
TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObj);
return E_NOINTERFACE;
static ULONG STDMETHODCALLTYPE Site_AddRef(IOleClientSite *iface)
{
- ICOM_THIS_MULTI(IOleClientSiteImpl, lpVtbl, iface);
+ IOleClientSiteImpl *This = impl_from_IOleClientSite(iface);
LONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref);
static ULONG STDMETHODCALLTYPE Site_Release(IOleClientSite *iface)
{
- ICOM_THIS_MULTI(IOleClientSiteImpl, lpVtbl, iface);
+ IOleClientSiteImpl *This = impl_from_IOleClientSite(iface);
LONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref);
Site_RequestNewObjectLayout
};
+static inline IOleClientSiteImpl *impl_from_IDocHostUIHandler(IDocHostUIHandler *iface)
+{
+ return CONTAINING_RECORD(iface, IOleClientSiteImpl, IDocHostUIHandler_iface);
+}
+
static HRESULT STDMETHODCALLTYPE UI_QueryInterface(IDocHostUIHandler *iface, REFIID riid, LPVOID *ppvObj)
{
- ICOM_THIS_MULTI(IOleClientSiteImpl, lpvtblDocHostUIHandler, iface);
+ IOleClientSiteImpl *This = impl_from_IDocHostUIHandler(iface);
- return IOleClientSite_QueryInterface(CLIENTSITE(This), riid, ppvObj);
+ return IOleClientSite_QueryInterface(&This->IOleClientSite_iface, riid, ppvObj);
}
static ULONG STDMETHODCALLTYPE UI_AddRef(IDocHostUIHandler *iface)
{
- ICOM_THIS_MULTI(IOleClientSiteImpl, lpvtblDocHostUIHandler, iface);
+ IOleClientSiteImpl *This = impl_from_IDocHostUIHandler(iface);
- return IOleClientSite_AddRef(CLIENTSITE(This));
+ return IOleClientSite_AddRef(&This->IOleClientSite_iface);
}
static ULONG STDMETHODCALLTYPE UI_Release(IDocHostUIHandler * iface)
{
- ICOM_THIS_MULTI(IOleClientSiteImpl, lpvtblDocHostUIHandler, iface);
+ IOleClientSiteImpl *This = impl_from_IDocHostUIHandler(iface);
- return IOleClientSite_Release(CLIENTSITE(This));
+ return IOleClientSite_Release(&This->IOleClientSite_iface);
}
static HRESULT STDMETHODCALLTYPE UI_ShowContextMenu(IDocHostUIHandler *iface, DWORD dwID, POINT *ppt, IUnknown *pcmdtReserved, IDispatch *pdispReserved)
UI_FilterDataObject
};
+static inline IOleClientSiteImpl *impl_from_IOleInPlaceSite(IOleInPlaceSite *iface)
+{
+ return CONTAINING_RECORD(iface, IOleClientSiteImpl, IOleInPlaceSite_iface);
+}
+
static HRESULT STDMETHODCALLTYPE InPlace_QueryInterface(IOleInPlaceSite *iface, REFIID riid, LPVOID *ppvObj)
{
- ICOM_THIS_MULTI(IOleClientSiteImpl, lpvtblOleInPlaceSite, iface);
+ IOleClientSiteImpl *This = impl_from_IOleInPlaceSite(iface);
- return IOleClientSite_QueryInterface(CLIENTSITE(This), riid, ppvObj);
+ return IOleClientSite_QueryInterface(&This->IOleClientSite_iface, riid, ppvObj);
}
static ULONG STDMETHODCALLTYPE InPlace_AddRef(IOleInPlaceSite *iface)
{
- ICOM_THIS_MULTI(IOleClientSiteImpl, lpvtblOleInPlaceSite, iface);
+ IOleClientSiteImpl *This = impl_from_IOleInPlaceSite(iface);
- return IOleClientSite_AddRef(CLIENTSITE(This));
+ return IOleClientSite_AddRef(&This->IOleClientSite_iface);
}
static ULONG STDMETHODCALLTYPE InPlace_Release(IOleInPlaceSite *iface)
{
- ICOM_THIS_MULTI(IOleClientSiteImpl, lpvtblOleInPlaceSite, iface);
+ IOleClientSiteImpl *This = impl_from_IOleInPlaceSite(iface);
- return IOleClientSite_Release(CLIENTSITE(This));
+ return IOleClientSite_Release(&This->IOleClientSite_iface);
}
static HRESULT STDMETHODCALLTYPE InPlace_GetWindow(IOleInPlaceSite *iface, HWND *lphwnd)
{
- ICOM_THIS_MULTI(IOleClientSiteImpl, lpvtblOleInPlaceSite, iface);
+ IOleClientSiteImpl *This = impl_from_IOleInPlaceSite(iface);
*lphwnd = This->hwndWindow;
return S_OK;
static HRESULT STDMETHODCALLTYPE InPlace_GetWindowContext(IOleInPlaceSite *iface, LPOLEINPLACEFRAME *lplpFrame, LPOLEINPLACEUIWINDOW *lplpDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo)
{
- ICOM_THIS_MULTI(IOleClientSiteImpl, lpvtblOleInPlaceSite, iface);
+ IOleClientSiteImpl *This = impl_from_IOleInPlaceSite(iface);
- *lplpFrame = INPLACEFRAME(This);
- IOleInPlaceFrame_AddRef(INPLACEFRAME(This));
+ *lplpFrame = &This->IOleInPlaceFrame_iface;
+ IOleInPlaceFrame_AddRef(&This->IOleInPlaceFrame_iface);
*lplpDoc = NULL;
static HRESULT STDMETHODCALLTYPE InPlace_OnPosRectChange(IOleInPlaceSite *iface, LPCRECT lprcPosRect)
{
- ICOM_THIS_MULTI(IOleClientSiteImpl, lpvtblOleInPlaceSite, iface);
+ IOleClientSiteImpl *This = impl_from_IOleInPlaceSite(iface);
IOleInPlaceObject *inplace;
if (IOleObject_QueryInterface(This->pBrowserObject, &IID_IOleInPlaceObject,
InPlace_OnPosRectChange
};
+static inline IOleClientSiteImpl *impl_from_IOleInPlaceFrame(IOleInPlaceFrame *iface)
+{
+ return CONTAINING_RECORD(iface, IOleClientSiteImpl, IOleInPlaceFrame_iface);
+}
+
static HRESULT STDMETHODCALLTYPE Frame_QueryInterface(IOleInPlaceFrame *iface, REFIID riid, LPVOID *ppvObj)
{
- ICOM_THIS_MULTI(IOleClientSiteImpl, lpvtblOleInPlaceFrame, iface);
+ IOleClientSiteImpl *This = impl_from_IOleInPlaceFrame(iface);
- return IOleClientSite_QueryInterface(CLIENTSITE(This), riid, ppvObj);
+ return IOleClientSite_QueryInterface(&This->IOleClientSite_iface, riid, ppvObj);
}
static ULONG STDMETHODCALLTYPE Frame_AddRef(IOleInPlaceFrame *iface)
{
- ICOM_THIS_MULTI(IOleClientSiteImpl, lpvtblOleInPlaceFrame, iface);
+ IOleClientSiteImpl *This = impl_from_IOleInPlaceFrame(iface);
- return IOleClientSite_AddRef(CLIENTSITE(This));
+ return IOleClientSite_AddRef(&This->IOleClientSite_iface);
}
static ULONG STDMETHODCALLTYPE Frame_Release(IOleInPlaceFrame *iface)
{
- ICOM_THIS_MULTI(IOleClientSiteImpl, lpvtblOleInPlaceFrame, iface);
+ IOleClientSiteImpl *This = impl_from_IOleInPlaceFrame(iface);
- return IOleClientSite_Release(CLIENTSITE(This));
+ return IOleClientSite_Release(&This->IOleClientSite_iface);
}
static HRESULT STDMETHODCALLTYPE Frame_GetWindow(IOleInPlaceFrame *iface, HWND *lphwnd)
{
- ICOM_THIS_MULTI(IOleClientSiteImpl, lpvtblOleInPlaceFrame, iface);
+ IOleClientSiteImpl *This = impl_from_IOleInPlaceFrame(iface);
*lphwnd = This->hwndWindow;
return S_OK;
return FALSE;
iOleClientSiteImpl->ref = 1;
- iOleClientSiteImpl->lpVtbl = &MyIOleClientSiteTable;
- iOleClientSiteImpl->lpvtblOleInPlaceSite = &MyIOleInPlaceSiteTable;
- iOleClientSiteImpl->lpvtblOleInPlaceFrame = &MyIOleInPlaceFrameTable;
+ iOleClientSiteImpl->IOleClientSite_iface.lpVtbl = &MyIOleClientSiteTable;
+ iOleClientSiteImpl->IOleInPlaceSite_iface.lpVtbl = &MyIOleInPlaceSiteTable;
+ iOleClientSiteImpl->IOleInPlaceFrame_iface.lpVtbl = &MyIOleInPlaceFrameTable;
iOleClientSiteImpl->hwndWindow = hwndParent;
- iOleClientSiteImpl->lpvtblDocHostUIHandler = &MyIDocHostUIHandlerTable;
+ iOleClientSiteImpl->IDocHostUIHandler_iface.lpVtbl = &MyIDocHostUIHandlerTable;
hr = OleCreate(&CLSID_WebBrowser, &IID_IOleObject, OLERENDER_DRAW, 0,
- (IOleClientSite *)iOleClientSiteImpl, &MyIStorage,
+ &iOleClientSiteImpl->IOleClientSite_iface, &MyIStorage,
(void **)&browserObject);
- info->client_site = (IOleClientSite *)iOleClientSiteImpl;
+ info->client_site = &iOleClientSiteImpl->IOleClientSite_iface;
info->wb_object = browserObject;
if (FAILED(hr)) goto error;
if (FAILED(hr)) goto error;
hr = IOleObject_DoVerb(browserObject, OLEIVERB_SHOW, NULL,
- (IOleClientSite *)iOleClientSiteImpl,
+ &iOleClientSiteImpl->IOleClientSite_iface,
-1, hwndParent, &rc);
if (FAILED(hr)) goto error;
break;
case WB_REFRESH:
IWebBrowser2_Refresh(pWebBrowser2);
+ break;
case WB_STOP:
IWebBrowser2_Stop(pWebBrowser2);
+ break;
+ case WB_PRINT:
+ IWebBrowser2_ExecWB(pWebBrowser2, OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER, 0, 0);
+ break;
}
}
reactos/dll/win32/faultrep # Synced to Wine-1.5.4
reactos/dll/win32/fusion # Synced to Wine-1.5.4
reactos/dll/win32/gdiplus # Synced to Wine-1.5.4
-reactos/dll/win32/hhctrl.ocx # Autosync
+reactos/dll/win32/hhctrl.ocx # Synced to Wine-1.5.26
reactos/dll/win32/hlink # Synced to Wine-1.5.4
reactos/dll/win32/hnetcfg # Synced to Wine-1.5.4
reactos/dll/win32/httpapi # Synced to Wine-1.5.4