- Merge from trunk up to r45543
[reactos.git] / base / applications / winhlp32 / winhelp.c
index 91f68c2..fb05aeb 100644 (file)
-/*\r
- * Help Viewer\r
- *\r
- * Copyright    1996 Ulrich Schmid <uschmid@mail.hh.provi.de>\r
- *              2002 Sylvain Petreolle <spetreolle@yahoo.fr>\r
- *              2002, 2008 Eric Pouech <eric.pouech@wanadoo.fr>\r
- *              2004 Ken Belleau <jamez@ivic.qc.ca>\r
- *              2008 Kirill K. Smirnov <lich@math.spbu.ru>\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\r
- */\r
-\r
-#include <assert.h>\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include <stdarg.h>\r
-#include <stdlib.h>\r
-\r
-#define NONAMELESSUNION\r
-#define NONAMELESSSTRUCT\r
-\r
-#include "windef.h"\r
-#include "winbase.h"\r
-#include "wingdi.h"\r
-#include "winuser.h"\r
-#include "commdlg.h"\r
-#include "winhelp.h"\r
-#include "winhelp_res.h"\r
-#include "shellapi.h"\r
-#include "richedit.h"\r
-#include "commctrl.h"\r
-\r
-#include "wine/debug.h"\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(winhelp);\r
-\r
-static BOOL    WINHELP_RegisterWinClasses(void);\r
-static LRESULT CALLBACK WINHELP_MainWndProc(HWND, UINT, WPARAM, LPARAM);\r
-static LRESULT CALLBACK WINHELP_ButtonBoxWndProc(HWND, UINT, WPARAM, LPARAM);\r
-static LRESULT CALLBACK WINHELP_ButtonWndProc(HWND, UINT, WPARAM, LPARAM);\r
-static LRESULT CALLBACK WINHELP_HistoryWndProc(HWND, UINT, WPARAM, LPARAM);\r
-static LRESULT CALLBACK WINHELP_ShadowWndProc(HWND, UINT, WPARAM, LPARAM);\r
-static BOOL    WINHELP_CheckPopup(HWND, UINT, WPARAM, LPARAM, LRESULT*);\r
-static void    WINHELP_InitFonts(HWND hWnd);\r
-static void    WINHELP_DeleteWindow(WINHELP_WINDOW*);\r
-static void    WINHELP_DeleteButtons(WINHELP_WINDOW*);\r
-static void    WINHELP_SetupText(HWND hWnd, WINHELP_WINDOW *win, ULONG relative);\r
-static void    WINHELP_DeletePageLinks(HLPFILE_PAGE* page);\r
-\r
-WINHELP_GLOBALS Globals = {3, NULL, TRUE, NULL, NULL, NULL, NULL, NULL, {{{NULL,NULL}},0}, NULL};\r
-\r
-#define CTL_ID_BUTTON   0x700\r
-#define CTL_ID_TEXT     0x701\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_GetOpenFileName\r
- */\r
-BOOL WINHELP_GetOpenFileName(LPSTR lpszFile, int len)\r
-{\r
-    OPENFILENAME openfilename;\r
-    CHAR szDir[MAX_PATH];\r
-    CHAR szzFilter[2 * MAX_STRING_LEN + 100];\r
-    LPSTR p = szzFilter;\r
-\r
-    WINE_TRACE("()\n");\r
-\r
-    LoadString(Globals.hInstance, STID_HELP_FILES_HLP, p, MAX_STRING_LEN);\r
-    p += strlen(p) + 1;\r
-    lstrcpy(p, "*.hlp");\r
-    p += strlen(p) + 1;\r
-    LoadString(Globals.hInstance, STID_ALL_FILES, p, MAX_STRING_LEN);\r
-    p += strlen(p) + 1;\r
-    lstrcpy(p, "*.*");\r
-    p += strlen(p) + 1;\r
-    *p = '\0';\r
-\r
-    GetCurrentDirectory(sizeof(szDir), szDir);\r
-\r
-    lpszFile[0]='\0';\r
-\r
-    openfilename.lStructSize       = sizeof(OPENFILENAME);\r
-    openfilename.hwndOwner         = NULL;\r
-    openfilename.hInstance         = Globals.hInstance;\r
-    openfilename.lpstrFilter       = szzFilter;\r
-    openfilename.lpstrCustomFilter = 0;\r
-    openfilename.nMaxCustFilter    = 0;\r
-    openfilename.nFilterIndex      = 1;\r
-    openfilename.lpstrFile         = lpszFile;\r
-    openfilename.nMaxFile          = len;\r
-    openfilename.lpstrFileTitle    = 0;\r
-    openfilename.nMaxFileTitle     = 0;\r
-    openfilename.lpstrInitialDir   = szDir;\r
-    openfilename.lpstrTitle        = 0;\r
-    openfilename.Flags             = 0;\r
-    openfilename.nFileOffset       = 0;\r
-    openfilename.nFileExtension    = 0;\r
-    openfilename.lpstrDefExt       = 0;\r
-    openfilename.lCustData         = 0;\r
-    openfilename.lpfnHook          = 0;\r
-    openfilename.lpTemplateName    = 0;\r
-\r
-    return GetOpenFileName(&openfilename);\r
-}\r
-\r
-static char* WINHELP_GetCaption(WINHELP_WNDPAGE* wpage)\r
-{\r
-    if (wpage->wininfo->caption[0]) return wpage->wininfo->caption;\r
-    return wpage->page->file->lpszTitle;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_LookupHelpFile\r
- */\r
-HLPFILE* WINHELP_LookupHelpFile(LPCSTR lpszFile)\r
-{\r
-    HLPFILE*        hlpfile;\r
-    char szFullName[MAX_PATH];\r
-    char szAddPath[MAX_PATH];\r
-    char *p;\r
-\r
-    /*\r
-     * NOTE: This is needed by popup windows only.\r
-     * In other cases it's not needed but does not hurt though.\r
-     */\r
-    if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file)\r
-    {\r
-        strcpy(szAddPath, Globals.active_win->page->file->lpszPath);\r
-        p = strrchr(szAddPath, '\\');\r
-        if (p) *p = 0;\r
-    }\r
-\r
-    /*\r
-     * FIXME: Should we swap conditions?\r
-     */\r
-    if (!SearchPath(NULL, lpszFile, ".hlp", MAX_PATH, szFullName, NULL) &&\r
-        !SearchPath(szAddPath, lpszFile, ".hlp", MAX_PATH, szFullName, NULL))\r
-    {\r
-        if (WINHELP_MessageBoxIDS_s(STID_FILE_NOT_FOUND_s, lpszFile, STID_WHERROR,\r
-                                    MB_YESNO|MB_ICONQUESTION) != IDYES)\r
-            return NULL;\r
-        if (!WINHELP_GetOpenFileName(szFullName, MAX_PATH))\r
-            return NULL;\r
-    }\r
-    hlpfile = HLPFILE_ReadHlpFile(szFullName);\r
-    if (!hlpfile)\r
-        WINHELP_MessageBoxIDS_s(STID_HLPFILE_ERROR_s, lpszFile,\r
-                                STID_WHERROR, MB_OK|MB_ICONSTOP);\r
-    return hlpfile;\r
-}\r
-\r
-/******************************************************************\r
- *             WINHELP_GetWindowInfo\r
- *\r
- *\r
- */\r
-HLPFILE_WINDOWINFO*     WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name)\r
-{\r
-    static      HLPFILE_WINDOWINFO      mwi;\r
-    unsigned int     i;\r
-\r
-    if (!name || !name[0])\r
-        name = Globals.active_win->lpszName;\r
-\r
-    if (hlpfile)\r
-        for (i = 0; i < hlpfile->numWindows; i++)\r
-            if (!strcmp(hlpfile->windows[i].name, name))\r
-                return &hlpfile->windows[i];\r
-\r
-    if (strcmp(name, "main") != 0)\r
-    {\r
-        WINE_FIXME("Couldn't find window info for %s\n", name);\r
-        assert(0);\r
-        return NULL;\r
-    }\r
-    if (!mwi.name[0])\r
-    {\r
-        strcpy(mwi.type, "primary");\r
-        strcpy(mwi.name, "main");\r
-        if (!LoadString(Globals.hInstance, STID_WINE_HELP, \r
-                        mwi.caption, sizeof(mwi.caption)))\r
-            strcpy(mwi.caption, hlpfile->lpszTitle);\r
-        mwi.origin.x = mwi.origin.y = mwi.size.cx = mwi.size.cy = CW_USEDEFAULT;\r
-        mwi.style = SW_SHOW;\r
-        mwi.win_style = WS_OVERLAPPEDWINDOW;\r
-        mwi.sr_color = mwi.sr_color = 0xFFFFFF;\r
-    }\r
-    return &mwi;\r
-}\r
-\r
-/******************************************************************\r
- *             HLPFILE_GetPopupWindowInfo\r
- *\r
- *\r
- */\r
-static HLPFILE_WINDOWINFO*     WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile,\r
-                                                          WINHELP_WINDOW* parent, LPARAM mouse)\r
-{\r
-    static      HLPFILE_WINDOWINFO      wi;\r
-\r
-    RECT parent_rect;\r
-    \r
-    wi.type[0] = wi.name[0] = wi.caption[0] = '\0';\r
-\r
-    /* Calculate horizontal size and position of a popup window */\r
-    GetWindowRect(parent->hMainWnd, &parent_rect);\r
-    wi.size.cx = (parent_rect.right  - parent_rect.left) / 2;\r
-    wi.size.cy = 10; /* need a non null value, so that border are taken into account while computing */\r
-\r
-    wi.origin.x = (short)LOWORD(mouse);\r
-    wi.origin.y = (short)HIWORD(mouse);\r
-    ClientToScreen(parent->hMainWnd, &wi.origin);\r
-    wi.origin.x -= wi.size.cx / 2;\r
-    wi.origin.x  = min(wi.origin.x, GetSystemMetrics(SM_CXSCREEN) - wi.size.cx);\r
-    wi.origin.x  = max(wi.origin.x, 0);\r
-\r
-    wi.style = SW_SHOW;\r
-    wi.win_style = WS_POPUP | WS_BORDER;\r
-    if (parent->page->file->has_popup_color)\r
-        wi.sr_color = parent->page->file->popup_color;\r
-    else\r
-        wi.sr_color = parent->info->sr_color;\r
-    wi.nsr_color = 0xFFFFFF;\r
-\r
-    return &wi;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WinMain\r
- */\r
-int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)\r
-{\r
-    MSG                 msg;\r
-    LONG                lHash = 0;\r
-    HLPFILE*            hlpfile;\r
-    static CHAR         default_wndname[] = "main";\r
-    LPSTR               wndname = default_wndname;\r
-    WINHELP_DLL*        dll;\r
-\r
-    Globals.hInstance = hInstance;\r
-\r
-    if (LoadLibrary("riched20.dll") == NULL)\r
-        return MessageBox(0, MAKEINTRESOURCE(STID_NO_RICHEDIT),\r
-                          MAKEINTRESOURCE(STID_WHERROR), MB_OK);\r
-\r
-    /* Get options */\r
-    while (*cmdline && (*cmdline == ' ' || *cmdline == '-'))\r
-    {\r
-        CHAR   option;\r
-        LPCSTR topic_id;\r
-        if (*cmdline++ == ' ') continue;\r
-\r
-        option = *cmdline;\r
-        if (option) cmdline++;\r
-        while (*cmdline && *cmdline == ' ') cmdline++;\r
-        switch (option)\r
-       {\r
-       case 'i':\r
-       case 'I':\r
-            topic_id = cmdline;\r
-            while (*cmdline && *cmdline != ' ') cmdline++;\r
-            if (*cmdline) *cmdline++ = '\0';\r
-            lHash = HLPFILE_Hash(topic_id);\r
-            break;\r
-\r
-       case '3':\r
-       case '4':\r
-            Globals.wVersion = option - '0';\r
-            break;\r
-\r
-        case 'x':\r
-            show = SW_HIDE; \r
-            Globals.isBook = FALSE;\r
-            break;\r
-\r
-        default:\r
-            WINE_FIXME("Unsupported cmd line: %s\n", cmdline);\r
-            break;\r
-       }\r
-    }\r
-\r
-    /* Create primary window */\r
-    if (!WINHELP_RegisterWinClasses())\r
-    {\r
-        WINE_FIXME("Couldn't register classes\n");\r
-        return 0;\r
-    }\r
-\r
-    if (*cmdline)\r
-    {\r
-        char*   ptr;\r
-        if ((*cmdline == '"') && (ptr = strchr(cmdline+1, '"')))\r
-        {\r
-            cmdline++;\r
-            *ptr = '\0';\r
-        }\r
-        if ((ptr = strchr(cmdline, '>')))\r
-        {\r
-            *ptr = '\0';\r
-            wndname = ptr + 1;\r
-        }\r
-        hlpfile = WINHELP_LookupHelpFile(cmdline);\r
-        if (!hlpfile) return 0;\r
-    }\r
-    else hlpfile = NULL;\r
-    WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, lHash,\r
-                           WINHELP_GetWindowInfo(hlpfile, wndname), show);\r
-\r
-    /* Message loop */\r
-    while (GetMessage(&msg, 0, 0, 0))\r
-    {\r
-        TranslateMessage(&msg);\r
-        DispatchMessage(&msg);\r
-    }\r
-    for (dll = Globals.dlls; dll; dll = dll->next)\r
-    {\r
-        if (dll->class & DC_INITTERM) dll->handler(DW_TERM, 0, 0);\r
-    }\r
-    return 0;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           RegisterWinClasses\r
- */\r
-static BOOL WINHELP_RegisterWinClasses(void)\r
-{\r
-    WNDCLASS class_main, class_button_box, class_shadow, class_history;\r
-\r
-    class_main.style               = CS_HREDRAW | CS_VREDRAW;\r
-    class_main.lpfnWndProc         = WINHELP_MainWndProc;\r
-    class_main.cbClsExtra          = 0;\r
-    class_main.cbWndExtra          = sizeof(LONG);\r
-    class_main.hInstance           = Globals.hInstance;\r
-    class_main.hIcon               = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_WINHELP));\r
-    class_main.hCursor             = LoadCursor(0, IDC_ARROW);\r
-    class_main.hbrBackground       = (HBRUSH)(COLOR_WINDOW+1);\r
-    class_main.lpszMenuName        = 0;\r
-    class_main.lpszClassName       = MAIN_WIN_CLASS_NAME;\r
-\r
-    class_button_box               = class_main;\r
-    class_button_box.lpfnWndProc   = WINHELP_ButtonBoxWndProc;\r
-    class_button_box.cbWndExtra    = 0;\r
-    class_button_box.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);\r
-    class_button_box.lpszClassName = BUTTON_BOX_WIN_CLASS_NAME;\r
-\r
-    class_shadow                   = class_main;\r
-    class_shadow.lpfnWndProc       = WINHELP_ShadowWndProc;\r
-    class_shadow.cbWndExtra        = 0;\r
-    class_shadow.hbrBackground     = (HBRUSH)(COLOR_3DDKSHADOW+1);\r
-    class_shadow.lpszClassName     = SHADOW_WIN_CLASS_NAME;\r
-\r
-    class_history                  = class_main;\r
-    class_history.lpfnWndProc      = WINHELP_HistoryWndProc;\r
-    class_history.lpszClassName    = HISTORY_WIN_CLASS_NAME;\r
-\r
-    return (RegisterClass(&class_main) &&\r
-            RegisterClass(&class_button_box) &&\r
-            RegisterClass(&class_shadow) &&\r
-            RegisterClass(&class_history));\r
-}\r
-\r
-typedef struct\r
-{\r
-    WORD size;\r
-    WORD command;\r
-    LONG data;\r
-    LONG reserved;\r
-    WORD ofsFilename;\r
-    WORD ofsData;\r
-} WINHELP,*LPWINHELP;\r
-\r
-static BOOL WINHELP_HasWorkingWindow(void)\r
-{\r
-    if (!Globals.active_win) return FALSE;\r
-    if (Globals.active_win->next || Globals.win_list != Globals.active_win) return TRUE;\r
-    return Globals.active_win->page != NULL && Globals.active_win->page->file != NULL;\r
-}\r
-\r
-/******************************************************************\r
- *             WINHELP_HandleCommand\r
- *\r
- *\r
- */\r
-static LRESULT  WINHELP_HandleCommand(HWND hSrcWnd, LPARAM lParam)\r
-{\r
-    COPYDATASTRUCT*     cds = (COPYDATASTRUCT*)lParam;\r
-    WINHELP*            wh;\r
-\r
-    if (cds->dwData != 0xA1DE505)\r
-    {\r
-        WINE_FIXME("Wrong magic number (%08lx)\n", cds->dwData);\r
-        return 0;\r
-    }\r
-\r
-    wh = (WINHELP*)cds->lpData;\r
-\r
-    if (wh)\r
-    {\r
-        char*   ptr = (wh->ofsFilename) ? (LPSTR)wh + wh->ofsFilename : NULL;\r
-\r
-        WINE_TRACE("Got[%u]: cmd=%u data=%08x fn=%s\n",\r
-                   wh->size, wh->command, wh->data, ptr);\r
-        switch (wh->command)\r
-        {\r
-        case HELP_CONTEXT:\r
-            if (ptr)\r
-            {\r
-                MACRO_JumpContext(ptr, "main", wh->data);\r
-            }\r
-            if (!WINHELP_HasWorkingWindow()) MACRO_Exit();\r
-            break;\r
-        case HELP_QUIT:\r
-            MACRO_Exit();\r
-            break;\r
-        case HELP_CONTENTS:\r
-            if (ptr)\r
-            {\r
-                MACRO_JumpContents(ptr, "main");\r
-            }\r
-            if (!WINHELP_HasWorkingWindow()) MACRO_Exit();\r
-            break;\r
-        case HELP_HELPONHELP:\r
-            MACRO_HelpOn();\r
-            if (!WINHELP_HasWorkingWindow()) MACRO_Exit();\r
-            break;\r
-        /* case HELP_SETINDEX: */\r
-        case HELP_SETCONTENTS:\r
-            if (ptr)\r
-            {\r
-                MACRO_SetContents(ptr, wh->data);\r
-            }\r
-            break;\r
-        case HELP_CONTEXTPOPUP:\r
-            if (ptr)\r
-            {\r
-                MACRO_PopupContext(ptr, wh->data);\r
-            }\r
-            break;\r
-        /* case HELP_FORCEFILE:*/\r
-        /* case HELP_CONTEXTMENU: */\r
-        case HELP_FINDER:\r
-            /* in fact, should be the topic dialog box */\r
-            WINE_FIXME("HELP_FINDER: stub\n");\r
-            if (ptr)\r
-            {\r
-                MACRO_JumpHash(ptr, "main", 0);\r
-            }\r
-            break;\r
-        /* case HELP_WM_HELP: */\r
-        /* case HELP_SETPOPUP_POS: */\r
-        /* case HELP_KEY: */\r
-        /* case HELP_COMMAND: */\r
-        /* case HELP_PARTIALKEY: */\r
-        /* case HELP_MULTIKEY: */\r
-        /* case HELP_SETWINPOS: */\r
-        default:\r
-            WINE_FIXME("Unhandled command (%x) for remote winhelp control\n", wh->command);\r
-            break;\r
-        }\r
-    }\r
-    /* Always return success for now */\r
-    return 1;\r
-}\r
-\r
-void            WINHELP_LayoutMainWindow(WINHELP_WINDOW* win)\r
-{\r
-    RECT        rect, button_box_rect;\r
-    INT         text_top = 0;\r
-    HWND        hButtonBoxWnd = GetDlgItem(win->hMainWnd, CTL_ID_BUTTON);\r
-    HWND        hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);\r
-\r
-    GetClientRect(win->hMainWnd, &rect);\r
-\r
-    /* Update button box and text Window */\r
-    SetWindowPos(hButtonBoxWnd, HWND_TOP,\r
-                 rect.left, rect.top,\r
-                 rect.right - rect.left,\r
-                 rect.bottom - rect.top, 0);\r
-\r
-    if (GetWindowRect(hButtonBoxWnd, &button_box_rect))\r
-        text_top = rect.top + button_box_rect.bottom - button_box_rect.top;\r
-\r
-    SetWindowPos(hTextWnd, HWND_TOP,\r
-                 rect.left, text_top,\r
-                 rect.right - rect.left,\r
-                 rect.bottom - text_top, 0);\r
-\r
-}\r
-\r
-static void     WINHELP_RememberPage(WINHELP_WINDOW* win, WINHELP_WNDPAGE* wpage)\r
-{\r
-    unsigned        num;\r
-\r
-    if (!Globals.history.index || Globals.history.set[0].page != wpage->page)\r
-    {\r
-        num = sizeof(Globals.history.set) / sizeof(Globals.history.set[0]);\r
-        /* we're full, remove latest entry */\r
-        if (Globals.history.index == num)\r
-        {\r
-            HLPFILE_FreeHlpFile(Globals.history.set[num - 1].page->file);\r
-            Globals.history.index--;\r
-        }\r
-        memmove(&Globals.history.set[1], &Globals.history.set[0],\r
-                Globals.history.index * sizeof(Globals.history.set[0]));\r
-        Globals.history.set[0] = *wpage;\r
-        Globals.history.index++;\r
-        wpage->page->file->wRefCount++;\r
-    }\r
-    if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE);\r
-\r
-    num = sizeof(win->back.set) / sizeof(win->back.set[0]);\r
-    if (win->back.index == num)\r
-    {\r
-        /* we're full, remove latest entry */\r
-        HLPFILE_FreeHlpFile(win->back.set[0].page->file);\r
-        memmove(&win->back.set[0], &win->back.set[1],\r
-                (num - 1) * sizeof(win->back.set[0]));\r
-        win->back.index--;\r
-    }\r
-    win->back.set[win->back.index++] = *wpage;\r
-    wpage->page->file->wRefCount++;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_CreateHelpWindow\r
- */\r
-BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE* wpage, int nCmdShow, BOOL remember)\r
-{\r
-    WINHELP_WINDOW*     win = NULL;\r
-    BOOL                bPrimary, bPopup, bReUsed = FALSE;\r
-    LPSTR               name;\r
-    HICON               hIcon;\r
-    HWND                hTextWnd = NULL;\r
-\r
-    bPrimary = !lstrcmpi(wpage->wininfo->name, "main");\r
-    bPopup = !bPrimary && (wpage->wininfo->win_style & WS_POPUP);\r
-\r
-    if (!bPopup)\r
-    {\r
-        for (win = Globals.win_list; win; win = win->next)\r
-        {\r
-            if (!lstrcmpi(win->lpszName, wpage->wininfo->name))\r
-            {\r
-                POINT   pt = {0, 0};\r
-                SIZE    sz = {0, 0};\r
-                DWORD   flags = SWP_NOSIZE | SWP_NOMOVE;\r
-\r
-                WINHELP_DeleteButtons(win);\r
-                bReUsed = TRUE;\r
-                SetWindowText(win->hMainWnd, WINHELP_GetCaption(wpage));\r
-                if (wpage->wininfo->origin.x != CW_USEDEFAULT &&\r
-                    wpage->wininfo->origin.y != CW_USEDEFAULT)\r
-                {\r
-                    pt = wpage->wininfo->origin;\r
-                    flags &= ~SWP_NOSIZE;\r
-                }\r
-                if (wpage->wininfo->size.cx != CW_USEDEFAULT &&\r
-                    wpage->wininfo->size.cy != CW_USEDEFAULT)\r
-                {\r
-                    sz = wpage->wininfo->size;\r
-                    flags &= ~SWP_NOMOVE;\r
-                }\r
-                SetWindowPos(win->hMainWnd, HWND_TOP, pt.x, pt.y, sz.cx, sz.cy, flags);\r
-\r
-                if (wpage->page && win->page && wpage->page->file != win->page->file)\r
-                    WINHELP_DeleteBackSet(win);\r
-                WINHELP_InitFonts(win->hMainWnd);\r
-\r
-                win->page = wpage->page;\r
-                win->info = wpage->wininfo;\r
-                hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);\r
-                WINHELP_SetupText(hTextWnd, win, wpage->relative);\r
-\r
-                InvalidateRect(win->hMainWnd, NULL, TRUE);\r
-                if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE);\r
-\r
-                break;\r
-            }\r
-        }\r
-    }\r
-\r
-    if (!win)\r
-    {\r
-        /* Initialize WINHELP_WINDOW struct */\r
-        win = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,\r
-                        sizeof(WINHELP_WINDOW) + strlen(wpage->wininfo->name) + 1);\r
-        if (!win) return FALSE;\r
-        win->next = Globals.win_list;\r
-        Globals.win_list = win;\r
-\r
-        name = (char*)win + sizeof(WINHELP_WINDOW);\r
-        lstrcpy(name, wpage->wininfo->name);\r
-        win->lpszName = name;\r
-        win->hHandCur = LoadCursorW(0, (LPWSTR)IDC_HAND);\r
-        win->back.index = 0;\r
-        win->font_scale = 1;\r
-    }\r
-    win->page = wpage->page;\r
-    win->info = wpage->wininfo;\r
-\r
-    if (!bPopup && wpage->page && remember)\r
-    {\r
-        WINHELP_RememberPage(win, wpage);\r
-    }\r
-\r
-    if (bPopup)\r
-        Globals.active_popup = win;\r
-    else\r
-        Globals.active_win = win;\r
-\r
-    /* Initialize default pushbuttons */\r
-    if (bPrimary && wpage->page)\r
-    {\r
-        CHAR    buffer[MAX_STRING_LEN];\r
-\r
-        LoadString(Globals.hInstance, STID_CONTENTS, buffer, sizeof(buffer));\r
-        MACRO_CreateButton("BTN_CONTENTS", buffer, "Contents()");\r
-        LoadString(Globals.hInstance, STID_INDEX, buffer, sizeof(buffer));\r
-        MACRO_CreateButton("BTN_INDEX", buffer, "Finder()");\r
-        LoadString(Globals.hInstance, STID_BACK, buffer, sizeof(buffer));\r
-        MACRO_CreateButton("BTN_BACK", buffer, "Back()");\r
-        if (win->back.index <= 1) MACRO_DisableButton("BTN_BACK");\r
-    }\r
-\r
-    if (!bReUsed)\r
-    {\r
-        win->hMainWnd = CreateWindowEx((bPopup) ? WS_EX_TOOLWINDOW : 0, MAIN_WIN_CLASS_NAME,\r
-                                       WINHELP_GetCaption(wpage),\r
-                                       bPrimary ? WS_OVERLAPPEDWINDOW : wpage->wininfo->win_style,\r
-                                       wpage->wininfo->origin.x, wpage->wininfo->origin.y,\r
-                                       wpage->wininfo->size.cx, wpage->wininfo->size.cy,\r
-                                       bPopup ? Globals.active_win->hMainWnd : NULL,\r
-                                       bPrimary ? LoadMenu(Globals.hInstance, MAKEINTRESOURCE(MAIN_MENU)) : 0,\r
-                                       Globals.hInstance, win);\r
-        if (!bPopup)\r
-            /* Create button box and text Window */\r
-            CreateWindow(BUTTON_BOX_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE,\r
-                         0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_BUTTON, Globals.hInstance, NULL);\r
-\r
-        hTextWnd = CreateWindow(RICHEDIT_CLASS, NULL,\r
-                                ES_MULTILINE | ES_READONLY | WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE,\r
-                                0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_TEXT, Globals.hInstance, NULL);\r
-        SendMessage(hTextWnd, EM_SETEVENTMASK, 0,\r
-                    SendMessage(hTextWnd, EM_GETEVENTMASK, 0, 0) | ENM_MOUSEEVENTS);\r
-    }\r
-\r
-    hIcon = (wpage->page) ? wpage->page->file->hIcon : NULL;\r
-    if (!hIcon) hIcon = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_WINHELP));\r
-    SendMessage(win->hMainWnd, WM_SETICON, ICON_SMALL, (DWORD_PTR)hIcon);\r
-\r
-    /* Initialize file specific pushbuttons */\r
-    if (!(wpage->wininfo->win_style & WS_POPUP) && wpage->page)\r
-    {\r
-        HLPFILE_MACRO  *macro;\r
-        for (macro = wpage->page->file->first_macro; macro; macro = macro->next)\r
-            MACRO_ExecuteMacro(macro->lpszMacro);\r
-\r
-        for (macro = wpage->page->first_macro; macro; macro = macro->next)\r
-            MACRO_ExecuteMacro(macro->lpszMacro);\r
-    }\r
-\r
-    if (bPopup)\r
-    {\r
-        DWORD   mask = SendMessage(hTextWnd, EM_GETEVENTMASK, 0, 0);\r
-        RECT    rect;\r
-\r
-        win->font_scale = Globals.active_win->font_scale;\r
-        WINHELP_SetupText(hTextWnd, win, wpage->relative);\r
-\r
-        /* we need the window to be shown for richedit to compute the size */\r
-        ShowWindow(win->hMainWnd, nCmdShow);\r
-        SendMessage(hTextWnd, EM_SETEVENTMASK, 0, mask | ENM_REQUESTRESIZE);\r
-        SendMessage(hTextWnd, EM_REQUESTRESIZE, 0, 0);\r
-        SendMessage(hTextWnd, EM_SETEVENTMASK, 0, mask);\r
-\r
-        GetWindowRect(win->hMainWnd, &rect);\r
-        win->hShadowWnd = CreateWindowEx(WS_EX_TOOLWINDOW, SHADOW_WIN_CLASS_NAME,\r
-                                         "", WS_POPUP | WS_VISIBLE,\r
-                                         rect.left + SHADOW_DX, rect.top + SHADOW_DY,\r
-                                         rect.right - rect.left,\r
-                                         rect.bottom - rect.top,\r
-                                         Globals.active_win->hMainWnd, 0,\r
-                                         Globals.hInstance, NULL);\r
-        SetWindowPos(win->hMainWnd, win->hShadowWnd, 0, 0, 0, 0,\r
-                     SWP_NOSIZE | SWP_NOMOVE);\r
-    }\r
-    else\r
-    {\r
-        WINHELP_SetupText(hTextWnd, win, wpage->relative);\r
-        WINHELP_LayoutMainWindow(win);\r
-        ShowWindow(win->hMainWnd, nCmdShow);\r
-    }\r
-\r
-    return TRUE;\r
-}\r
-\r
-/******************************************************************\r
- *             WINHELP_OpenHelpWindow\r
- * Main function to search for a page and display it in a window\r
- */\r
-BOOL WINHELP_OpenHelpWindow(HLPFILE_PAGE* (*lookup)(HLPFILE*, LONG, ULONG*),\r
-                            HLPFILE* hlpfile, LONG val, HLPFILE_WINDOWINFO* wi,\r
-                            int nCmdShow)\r
-{\r
-    WINHELP_WNDPAGE     wpage;\r
-\r
-    wpage.page = lookup(hlpfile, val, &wpage.relative);\r
-    if (wpage.page) wpage.page->file->wRefCount++;\r
-    wpage.wininfo = wi;\r
-    return WINHELP_CreateHelpWindow(&wpage, nCmdShow, TRUE);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_FindLink\r
- */\r
-static HLPFILE_LINK* WINHELP_FindLink(WINHELP_WINDOW* win, LPARAM pos)\r
-{\r
-    HLPFILE_LINK*           link;\r
-    POINTL                  mouse_ptl, char_ptl, char_next_ptl;\r
-    DWORD                   cp;\r
-\r
-    if (!win->page) return NULL;\r
-\r
-    mouse_ptl.x = (short)LOWORD(pos);\r
-    mouse_ptl.y = (short)HIWORD(pos);\r
-    cp = SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_CHARFROMPOS,\r
-                      0, (LPARAM)&mouse_ptl);\r
-\r
-    for (link = win->page->first_link; link; link = link->next)\r
-    {\r
-        if (link->cpMin <= cp && cp <= link->cpMax)\r
-        {\r
-            /* check whether we're at end of line */\r
-            SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR,\r
-                         (LPARAM)&char_ptl, cp);\r
-            SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR,\r
-                         (LPARAM)&char_next_ptl, cp + 1);\r
-            if (char_next_ptl.y != char_ptl.y || mouse_ptl.x >= char_next_ptl.x)\r
-                link = NULL;\r
-            break;\r
-        }\r
-    }\r
-    return link;\r
-}\r
-\r
-/******************************************************************\r
- *             WINHELP_HandleTextMouse\r
- *\r
- */\r
-static BOOL WINHELP_HandleTextMouse(WINHELP_WINDOW* win, UINT msg, LPARAM lParam)\r
-{\r
-    HLPFILE*                hlpfile;\r
-    HLPFILE_LINK*           link;\r
-    BOOL                    ret = FALSE;\r
-\r
-    switch (msg)\r
-    {\r
-    case WM_MOUSEMOVE:\r
-        if (WINHELP_FindLink(win, lParam))\r
-            SetCursor(win->hHandCur);\r
-        else\r
-            SetCursor(LoadCursor(0, IDC_ARROW));\r
-        break;\r
-\r
-     case WM_LBUTTONDOWN:\r
-         if ((win->current_link = WINHELP_FindLink(win, lParam)))\r
-             ret = TRUE;\r
-         break;\r
-\r
-    case WM_LBUTTONUP:\r
-        if ((link = WINHELP_FindLink(win, lParam)) && link == win->current_link)\r
-        {\r
-            HLPFILE_WINDOWINFO*     wi;\r
-\r
-            switch (link->cookie)\r
-            {\r
-            case hlp_link_link:\r
-                if ((hlpfile = WINHELP_LookupHelpFile(link->string)))\r
-                {\r
-                    if (link->window == -1)\r
-                        wi = win->info;\r
-                    else if (link->window < hlpfile->numWindows)\r
-                        wi = &hlpfile->windows[link->window];\r
-                    else\r
-                    {\r
-                        WINE_WARN("link to window %d/%d\n", link->window, hlpfile->numWindows);\r
-                        break;\r
-                    }\r
-                    WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash, wi, SW_NORMAL);\r
-                }\r
-                break;\r
-            case hlp_link_popup:\r
-                if ((hlpfile = WINHELP_LookupHelpFile(link->string)))\r
-                    WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash,\r
-                                           WINHELP_GetPopupWindowInfo(hlpfile, win, lParam),\r
-                                           SW_NORMAL);\r
-                break;\r
-            case hlp_link_macro:\r
-                MACRO_ExecuteMacro(link->string);\r
-                break;\r
-            default:\r
-                WINE_FIXME("Unknown link cookie %d\n", link->cookie);\r
-            }\r
-            ret = TRUE;\r
-        }\r
-        win->current_link = NULL;\r
-        break;\r
-    }\r
-    return ret;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_MainWndProc\r
- */\r
-static LRESULT CALLBACK WINHELP_MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
-    WINHELP_WINDOW *win;\r
-    WINHELP_BUTTON *button;\r
-    RECT rect;\r
-    INT  curPos, min, max, dy, keyDelta;\r
-    HWND hTextWnd;\r
-    LRESULT ret;\r
-\r
-    if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, &ret)) return ret;\r
-\r
-    switch (msg)\r
-    {\r
-    case WM_NCCREATE:\r
-        win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams;\r
-        SetWindowLongPtr(hWnd, 0, (ULONG_PTR) win);\r
-        if (!win->page && Globals.isBook)\r
-            PostMessage(hWnd, WM_COMMAND, MNID_FILE_OPEN, 0);\r
-        win->hMainWnd = hWnd;\r
-        break;\r
-\r
-    case WM_WINDOWPOSCHANGED:\r
-        WINHELP_LayoutMainWindow((WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0));\r
-        break;\r
-\r
-    case WM_COMMAND:\r
-        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-        switch (wParam)\r
-       {\r
-            /* Menu FILE */\r
-       case MNID_FILE_OPEN:    MACRO_FileOpen();       break;\r
-       case MNID_FILE_PRINT:   MACRO_Print();          break;\r
-       case MNID_FILE_SETUP:   MACRO_PrinterSetup();   break;\r
-       case MNID_FILE_EXIT:    MACRO_Exit();           break;\r
-\r
-            /* Menu EDIT */\r
-       case MNID_EDIT_COPYDLG:\r
-            SendMessage(GetDlgItem(hWnd, CTL_ID_TEXT), WM_COPY, 0, 0);\r
-            break;\r
-       case MNID_EDIT_ANNOTATE:MACRO_Annotate();       break;\r
-\r
-            /* Menu Bookmark */\r
-       case MNID_BKMK_DEFINE:  MACRO_BookmarkDefine(); break;\r
-\r
-            /* Menu Help */\r
-       case MNID_HELP_HELPON:  MACRO_HelpOn();         break;\r
-       case MNID_HELP_HELPTOP: MACRO_HelpOnTop();      break;\r
-       case MNID_HELP_ABOUT:   MACRO_About();          break;\r
-       case MNID_HELP_WINE:    ShellAbout(hWnd, "WINE", "Help", 0); break;\r
-\r
-            /* Context help */\r
-        case MNID_CTXT_ANNOTATE:MACRO_Annotate();       break;\r
-        case MNID_CTXT_COPY:    MACRO_CopyDialog();     break;\r
-        case MNID_CTXT_PRINT:   MACRO_Print();          break;\r
-        case MNID_OPTS_HISTORY: MACRO_History();        break;\r
-        case MNID_OPTS_FONTS_SMALL:\r
-        case MNID_CTXT_FONTS_SMALL:\r
-            win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-            if (win->font_scale != 0)\r
-            {\r
-                win->font_scale = 0;\r
-                WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);\r
-            }\r
-            break;\r
-        case MNID_OPTS_FONTS_NORMAL:\r
-        case MNID_CTXT_FONTS_NORMAL:\r
-            win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);\r
-            if (win->font_scale != 1)\r
-            {\r
-                win->font_scale = 1;\r
-                WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);\r
-            }\r
-            break;\r
-        case MNID_OPTS_FONTS_LARGE:\r
-        case MNID_CTXT_FONTS_LARGE:\r
-            win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);\r
-            if (win->font_scale != 2)\r
-            {\r
-                win->font_scale = 2;\r
-                WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);\r
-            }\r
-            break;\r
-        case MNID_OPTS_HELP_DEFAULT:\r
-        case MNID_OPTS_HELP_VISIBLE:\r
-        case MNID_OPTS_HELP_NONVISIBLE:\r
-        case MNID_OPTS_SYSTEM_COLORS:\r
-        case MNID_CTXT_HELP_DEFAULT:\r
-        case MNID_CTXT_HELP_VISIBLE:\r
-        case MNID_CTXT_HELP_NONVISIBLE:\r
-        case MNID_CTXT_SYSTEM_COLORS:\r
-            /* FIXME: NIY */\r
-\r
-       default:\r
-            /* Buttons */\r
-            for (button = win->first_button; button; button = button->next)\r
-                if (wParam == button->wParam) break;\r
-            if (button)\r
-                MACRO_ExecuteMacro(button->lpszMacro);\r
-            else if (!HIWORD(wParam))\r
-                MessageBox(0, MAKEINTRESOURCE(STID_NOT_IMPLEMENTED),\r
-                           MAKEINTRESOURCE(STID_WHERROR), MB_OK);\r
-            break;\r
-       }\r
-        break;\r
-/* EPP     case WM_DESTROY: */\r
-/* EPP         if (Globals.hPopupWnd) DestroyWindow(Globals.hPopupWnd); */\r
-/* EPP         break; */\r
-    case WM_COPYDATA:\r
-        return WINHELP_HandleCommand((HWND)wParam, lParam);\r
-\r
-    case WM_CHAR:\r
-        if (wParam == 3)\r
-        {\r
-            SendMessage(GetDlgItem(hWnd, CTL_ID_TEXT), WM_COPY, 0, 0);\r
-            return 0;\r
-        }\r
-        break;\r
-\r
-    case WM_KEYDOWN:\r
-        keyDelta = 0;\r
-\r
-        switch (wParam)\r
-        {\r
-        case VK_UP:\r
-        case VK_DOWN:\r
-            keyDelta = GetSystemMetrics(SM_CXVSCROLL);\r
-            if (wParam == VK_UP)\r
-                keyDelta = -keyDelta;\r
-\r
-        case VK_PRIOR:\r
-        case VK_NEXT:\r
-            win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-            hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);\r
-            curPos = GetScrollPos(hTextWnd, SB_VERT);\r
-            GetScrollRange(hTextWnd, SB_VERT, &min, &max);\r
-\r
-            if (keyDelta == 0)\r
-            {            \r
-                GetClientRect(hTextWnd, &rect);\r
-                keyDelta = (rect.bottom - rect.top) / 2;\r
-                if (wParam == VK_PRIOR)\r
-                    keyDelta = -keyDelta;\r
-            }\r
-\r
-            curPos += keyDelta;\r
-            if (curPos > max)\r
-                 curPos = max;\r
-            else if (curPos < min)\r
-                 curPos = min;\r
-\r
-            dy = GetScrollPos(hTextWnd, SB_VERT) - curPos;\r
-            SetScrollPos(hTextWnd, SB_VERT, curPos, TRUE);\r
-            ScrollWindow(hTextWnd, 0, dy, NULL, NULL);\r
-            UpdateWindow(hTextWnd);\r
-            return 0;\r
-\r
-        case VK_ESCAPE:\r
-            MACRO_Exit();\r
-            return 0;\r
-        }\r
-        break;\r
-\r
-    case WM_NOTIFY:\r
-        if (wParam == CTL_ID_TEXT)\r
-        {\r
-            RECT        rc;\r
-\r
-            switch (((NMHDR*)lParam)->code)\r
-            {\r
-            case EN_MSGFILTER:\r
-                {\r
-                    const MSGFILTER*    msgf = (const MSGFILTER*)lParam;\r
-                    switch (msgf->msg)\r
-                    {\r
-                    case WM_KEYUP:\r
-                        if (msgf->wParam == VK_ESCAPE) DestroyWindow(hWnd);\r
-                        break;\r
-                    case WM_RBUTTONDOWN:\r
-                    {\r
-                        HMENU       hMenu;\r
-                        POINT       pt;\r
-\r
-                        win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);\r
-                        hMenu = LoadMenu(Globals.hInstance, (LPSTR)CONTEXT_MENU);\r
-                        switch (win->font_scale)\r
-                        {\r
-                        case 0:\r
-                            CheckMenuItem(hMenu, MNID_CTXT_FONTS_SMALL,\r
-                                          MF_BYCOMMAND|MF_CHECKED);\r
-                            break;\r
-                        default:\r
-                            WINE_FIXME("Unsupported %d\n", win->font_scale);\r
-                        case 1:\r
-                            CheckMenuItem(hMenu, MNID_CTXT_FONTS_NORMAL,\r
-                                          MF_BYCOMMAND|MF_CHECKED);\r
-                            break;\r
-                        case 2:\r
-                            CheckMenuItem(hMenu, MNID_CTXT_FONTS_LARGE,\r
-                                          MF_BYCOMMAND|MF_CHECKED);\r
-                            break;\r
-                        }\r
-                        pt.x = (int)(short)LOWORD(msgf->lParam);\r
-                        pt.y = (int)(short)HIWORD(msgf->lParam);\r
-                        ClientToScreen(msgf->nmhdr.hwndFrom, &pt);\r
-                        TrackPopupMenu(GetSubMenu(hMenu, 0), TPM_LEFTALIGN|TPM_TOPALIGN,\r
-                                       pt.x, pt.y, 0, hWnd, NULL);\r
-                        DestroyMenu(hMenu);\r
-                    }\r
-                    break;\r
-                    default:\r
-                        return WINHELP_HandleTextMouse((WINHELP_WINDOW*)GetWindowLongPtr(hWnd, 0),\r
-                                                       msgf->msg, msgf->lParam);\r
-                    }\r
-                }\r
-                break;\r
-\r
-            case EN_REQUESTRESIZE:\r
-                rc = ((REQRESIZE*)lParam)->rc;\r
-                win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);\r
-                AdjustWindowRect(&rc, GetWindowLong(win->hMainWnd, GWL_STYLE),\r
-                                 FALSE);\r
-                SetWindowPos(win->hMainWnd, HWND_TOP, 0, 0,\r
-                             rc.right - rc.left, rc.bottom - rc.top,\r
-                             SWP_NOMOVE | SWP_NOZORDER);\r
-                WINHELP_LayoutMainWindow(win);\r
-                break;\r
-            }\r
-        }\r
-        break;\r
-\r
-    case WM_INITMENUPOPUP:\r
-        win = (WINHELP_WINDOW*) GetWindowLong(hWnd, 0);\r
-        CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_SMALL,\r
-                      MF_BYCOMMAND | (win->font_scale == 0) ? MF_CHECKED : 0);\r
-        CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_NORMAL,\r
-                      MF_BYCOMMAND | (win->font_scale == 1) ? MF_CHECKED : 0);\r
-        CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_LARGE,\r
-                      MF_BYCOMMAND | (win->font_scale == 2) ? MF_CHECKED : 0);\r
-        break;\r
-\r
-    case WM_NCDESTROY:\r
-        {\r
-            BOOL bExit;\r
-            win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-            bExit = (Globals.wVersion >= 4 && !lstrcmpi(win->lpszName, "main"));\r
-            WINHELP_DeleteWindow(win);\r
-\r
-            if (bExit) MACRO_Exit();\r
-            if (!Globals.win_list)\r
-                PostQuitMessage(0);\r
-        }\r
-        break;\r
-    }\r
-    return DefWindowProc(hWnd, msg, wParam, lParam);\r
-}\r
-\r
-static DWORD CALLBACK WINHELP_RtfStreamIn(DWORD_PTR cookie, BYTE* buff,\r
-                                          LONG cb, LONG* pcb)\r
-{\r
-    struct RtfData*     rd = (struct RtfData*)cookie;\r
-\r
-    if (rd->where >= rd->ptr) return 1;\r
-    if (rd->where + cb > rd->ptr)\r
-        cb = rd->ptr - rd->where;\r
-    memcpy(buff, rd->where, cb);\r
-    rd->where += cb;\r
-    *pcb = cb;\r
-    return 0;\r
-}\r
-\r
-static void WINHELP_SetupText(HWND hTextWnd, WINHELP_WINDOW* win, ULONG relative)\r
-{\r
-    /* At first clear area - needed by EM_POSFROMCHAR/EM_SETSCROLLPOS */\r
-    SendMessage(hTextWnd, WM_SETTEXT, 0, (LPARAM)"");\r
-    SendMessage(hTextWnd, WM_SETREDRAW, FALSE, 0);\r
-    SendMessage(hTextWnd, EM_SETBKGNDCOLOR, 0, (LPARAM)win->info->sr_color);\r
-    /* set word-wrap to window size (undocumented) */\r
-    SendMessage(hTextWnd, EM_SETTARGETDEVICE, 0, 0);\r
-    if (win->page)\r
-    {\r
-        struct RtfData  rd;\r
-        EDITSTREAM      es;\r
-        unsigned        cp = 0;\r
-        POINTL          ptl;\r
-        POINT           pt;\r
-\r
-\r
-        if (HLPFILE_BrowsePage(win->page, &rd, win->font_scale, relative))\r
-        {\r
-            rd.where = rd.data;\r
-            es.dwCookie = (DWORD_PTR)&rd;\r
-            es.dwError = 0;\r
-            es.pfnCallback = WINHELP_RtfStreamIn;\r
-\r
-            SendMessageW(hTextWnd, EM_STREAMIN, SF_RTF, (LPARAM)&es);\r
-            cp = rd.char_pos_rel;\r
-        }\r
-        /* FIXME: else leaking potentially the rd.first_link chain */\r
-        HeapFree(GetProcessHeap(), 0, rd.data);\r
-        SendMessage(hTextWnd, EM_POSFROMCHAR, (WPARAM)&ptl, cp ? cp - 1 : 0);\r
-        pt.x = 0; pt.y = ptl.y;\r
-        SendMessage(hTextWnd, EM_SETSCROLLPOS, 0, (LPARAM)&pt);\r
-    }\r
-    SendMessage(hTextWnd, WM_SETREDRAW, TRUE, 0);\r
-    InvalidateRect(hTextWnd, NULL, TRUE);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_ButtonBoxWndProc\r
- */\r
-static LRESULT CALLBACK WINHELP_ButtonBoxWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
-    WINDOWPOS      *winpos;\r
-    WINHELP_WINDOW *win;\r
-    WINHELP_BUTTON *button;\r
-    SIZE button_size;\r
-    INT  x, y;\r
-\r
-    if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0L;\r
-\r
-    switch (msg)\r
-    {\r
-    case WM_WINDOWPOSCHANGING:\r
-        winpos = (WINDOWPOS*) lParam;\r
-        win = (WINHELP_WINDOW*) GetWindowLongPtr(GetParent(hWnd), 0);\r
-\r
-        /* Update buttons */\r
-        button_size.cx = 0;\r
-        button_size.cy = 0;\r
-        for (button = win->first_button; button; button = button->next)\r
-       {\r
-            HDC  hDc;\r
-            SIZE textsize;\r
-            if (!button->hWnd)\r
-            {\r
-                button->hWnd = CreateWindow(STRING_BUTTON, button->lpszName,\r
-                                            WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,\r
-                                            0, 0, 0, 0,\r
-                                            hWnd, (HMENU) button->wParam,\r
-                                            Globals.hInstance, 0);\r
-                if (button->hWnd)\r
-                {\r
-                    if (Globals.button_proc == NULL)\r
-                    {\r
-                        NONCLIENTMETRICSW ncm;\r
-                        Globals.button_proc = (WNDPROC) GetWindowLongPtr(button->hWnd, GWLP_WNDPROC);\r
-\r
-                        ncm.cbSize = sizeof(NONCLIENTMETRICSW);\r
-                        SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,\r
-                                              sizeof(NONCLIENTMETRICSW), &ncm, 0);\r
-                        Globals.hButtonFont = CreateFontIndirectW(&ncm.lfMenuFont);\r
-                    }\r
-                    SetWindowLongPtr(button->hWnd, GWLP_WNDPROC, (LONG_PTR) WINHELP_ButtonWndProc);\r
-                    if (Globals.hButtonFont)\r
-                        SendMessage(button->hWnd, WM_SETFONT, (WPARAM)Globals.hButtonFont, TRUE);\r
-                }\r
-            }\r
-            hDc = GetDC(button->hWnd);\r
-            GetTextExtentPoint(hDc, button->lpszName,\r
-                               lstrlen(button->lpszName), &textsize);\r
-            ReleaseDC(button->hWnd, hDc);\r
-\r
-            button_size.cx = max(button_size.cx, textsize.cx + BUTTON_CX);\r
-            button_size.cy = max(button_size.cy, textsize.cy + BUTTON_CY);\r
-       }\r
-\r
-        x = 0;\r
-        y = 0;\r
-        for (button = win->first_button; button; button = button->next)\r
-       {\r
-            SetWindowPos(button->hWnd, HWND_TOP, x, y, button_size.cx, button_size.cy, 0);\r
-\r
-            if (x + 2 * button_size.cx <= winpos->cx)\r
-                x += button_size.cx;\r
-            else\r
-                x = 0, y += button_size.cy;\r
-       }\r
-        winpos->cy = y + (x ? button_size.cy : 0);\r
-        break;\r
-\r
-    case WM_COMMAND:\r
-        SendMessage(GetParent(hWnd), msg, wParam, lParam);\r
-        break;\r
-\r
-    case WM_KEYDOWN:\r
-        switch (wParam)\r
-        {\r
-        case VK_UP:\r
-        case VK_DOWN:\r
-        case VK_PRIOR:\r
-        case VK_NEXT:\r
-        case VK_ESCAPE:\r
-            return SendMessage(GetParent(hWnd), msg, wParam, lParam);\r
-        }\r
-        break;\r
-    }\r
-\r
-    return DefWindowProc(hWnd, msg, wParam, lParam);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_ButtonWndProc\r
- */\r
-static LRESULT CALLBACK WINHELP_ButtonWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
-    if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0;\r
-\r
-    if (msg == WM_KEYDOWN)\r
-    {\r
-        switch (wParam)\r
-        {\r
-        case VK_UP:\r
-        case VK_DOWN:\r
-        case VK_PRIOR:\r
-        case VK_NEXT:\r
-        case VK_ESCAPE:\r
-            return SendMessage(GetParent(hWnd), msg, wParam, lParam);\r
-        }\r
-    }\r
-\r
-    return CallWindowProc(Globals.button_proc, hWnd, msg, wParam, lParam);\r
-}\r
-\r
-/******************************************************************\r
- *             WINHELP_HistoryWndProc\r
- *\r
- *\r
- */\r
-static LRESULT CALLBACK WINHELP_HistoryWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
-    WINHELP_WINDOW*     win;\r
-    PAINTSTRUCT         ps;\r
-    HDC                 hDc;\r
-    TEXTMETRIC          tm;\r
-    unsigned int        i;\r
-    RECT                r;\r
-\r
-    switch (msg)\r
-    {\r
-    case WM_NCCREATE:\r
-        win = (WINHELP_WINDOW*)((LPCREATESTRUCT)lParam)->lpCreateParams;\r
-        SetWindowLongPtr(hWnd, 0, (ULONG_PTR)win);\r
-        win->hHistoryWnd = hWnd;\r
-        break;\r
-    case WM_CREATE:\r
-        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-        hDc = GetDC(hWnd);\r
-        GetTextMetrics(hDc, &tm);\r
-        GetWindowRect(hWnd, &r);\r
-\r
-        r.right = r.left + 30 * tm.tmAveCharWidth;\r
-        r.bottom = r.top + (sizeof(Globals.history.set) / sizeof(Globals.history.set[0])) * tm.tmHeight;\r
-        AdjustWindowRect(&r, GetWindowLong(hWnd, GWL_STYLE), FALSE);\r
-        if (r.left < 0) {r.right -= r.left; r.left = 0;}\r
-        if (r.top < 0) {r.bottom -= r.top; r.top = 0;}\r
-\r
-        MoveWindow(hWnd, r.left, r.top, r.right, r.bottom, TRUE);\r
-        ReleaseDC(hWnd, hDc);\r
-        break;\r
-    case WM_LBUTTONDOWN:\r
-        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-        hDc = GetDC(hWnd);\r
-        GetTextMetrics(hDc, &tm);\r
-        i = HIWORD(lParam) / tm.tmHeight;\r
-        if (i < Globals.history.index)\r
-            WINHELP_CreateHelpWindow(&Globals.history.set[i], SW_SHOW, TRUE);\r
-        ReleaseDC(hWnd, hDc);\r
-        break;\r
-    case WM_PAINT:\r
-        hDc = BeginPaint(hWnd, &ps);\r
-        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-        GetTextMetrics(hDc, &tm);\r
-\r
-        for (i = 0; i < Globals.history.index; i++)\r
-        {\r
-            if (Globals.history.set[i].page->file == Globals.active_win->page->file)\r
-            {\r
-                TextOut(hDc, 0, i * tm.tmHeight,\r
-                        Globals.history.set[i].page->lpszTitle,\r
-                        strlen(Globals.history.set[i].page->lpszTitle));\r
-            }\r
-            else\r
-            {\r
-                char        buffer[1024];\r
-                const char* ptr1;\r
-                const char* ptr2;\r
-                unsigned    len;\r
-\r
-                ptr1 = strrchr(Globals.history.set[i].page->file->lpszPath, '\\');\r
-                if (!ptr1) ptr1 = Globals.history.set[i].page->file->lpszPath;\r
-                else ptr1++;\r
-                ptr2 = strrchr(ptr1, '.');\r
-                len = ptr2 ? ptr2 - ptr1 : strlen(ptr1);\r
-                if (len > sizeof(buffer)) len = sizeof(buffer);\r
-                memcpy(buffer, ptr1, len);\r
-                if (len < sizeof(buffer)) buffer[len++] = ':';\r
-                strncpy(&buffer[len], Globals.history.set[i].page->lpszTitle, sizeof(buffer) - len);\r
-                buffer[sizeof(buffer) - 1] = '\0';\r
-                TextOut(hDc, 0, i * tm.tmHeight, buffer, strlen(buffer));\r
-            }\r
-        }\r
-        EndPaint(hWnd, &ps);\r
-        break;\r
-    case WM_DESTROY:\r
-        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-        if (hWnd == win->hHistoryWnd)\r
-            win->hHistoryWnd = 0;\r
-        break;\r
-    }\r
-    return DefWindowProc(hWnd, msg, wParam, lParam);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_ShadowWndProc\r
- */\r
-static LRESULT CALLBACK WINHELP_ShadowWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
-    if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0;\r
-    return WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL) ? 0L : DefWindowProc(hWnd, msg, wParam, lParam);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_CheckPopup\r
- */\r
-static BOOL WINHELP_CheckPopup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT* lret)\r
-{\r
-    HWND        hPopup;\r
-\r
-    if (!Globals.active_popup) return FALSE;\r
-\r
-    switch (msg)\r
-    {\r
-    case WM_NOTIFY:\r
-        {\r
-            MSGFILTER*  msgf = (MSGFILTER*)lParam;\r
-            if (msgf->nmhdr.code == EN_MSGFILTER)\r
-            {\r
-                if (!WINHELP_CheckPopup(hWnd, msgf->msg, msgf->wParam, msgf->lParam, NULL))\r
-                    return FALSE;\r
-                if (lret) *lret = 1;\r
-                return TRUE;\r
-            }\r
-        }\r
-        break;\r
-    case WM_ACTIVATE:\r
-        if (wParam != WA_INACTIVE || (HWND)lParam == Globals.active_win->hMainWnd ||\r
-            (HWND)lParam == Globals.active_popup->hMainWnd ||\r
-            GetWindow((HWND)lParam, GW_OWNER) == Globals.active_win->hMainWnd)\r
-            break;\r
-    case WM_LBUTTONUP:\r
-    case WM_LBUTTONDOWN:\r
-        if (WINHELP_HandleTextMouse(Globals.active_popup, msg, lParam) && msg == WM_LBUTTONDOWN)\r
-            return FALSE;\r
-        /* fall through */\r
-    case WM_MBUTTONDOWN:\r
-    case WM_RBUTTONDOWN:\r
-    case WM_NCLBUTTONDOWN:\r
-    case WM_NCMBUTTONDOWN:\r
-    case WM_NCRBUTTONDOWN:\r
-        hPopup = Globals.active_popup->hMainWnd;\r
-        Globals.active_popup = NULL;\r
-        DestroyWindow(hPopup);\r
-        return TRUE;\r
-    }\r
-    return FALSE;\r
-}\r
-\r
-/******************************************************************\r
- *             WINHELP_DeleteButtons\r
- *\r
- */\r
-static void WINHELP_DeleteButtons(WINHELP_WINDOW* win)\r
-{\r
-    WINHELP_BUTTON*     b;\r
-    WINHELP_BUTTON*     bp;\r
-\r
-    for (b = win->first_button; b; b = bp)\r
-    {\r
-        DestroyWindow(b->hWnd);\r
-        bp = b->next;\r
-        HeapFree(GetProcessHeap(), 0, b);\r
-    }\r
-    win->first_button = NULL;\r
-}\r
-\r
-/******************************************************************\r
- *             WINHELP_DeleteBackSet\r
- *\r
- */\r
-void WINHELP_DeleteBackSet(WINHELP_WINDOW* win)\r
-{\r
-    unsigned int i;\r
-\r
-    for (i = 0; i < win->back.index; i++)\r
-    {\r
-        HLPFILE_FreeHlpFile(win->back.set[i].page->file);\r
-        win->back.set[i].page = NULL;\r
-    }\r
-    win->back.index = 0;\r
-}\r
-\r
-/******************************************************************\r
- *             WINHELP_DeletePageLinks\r
- *\r
- */\r
-static void WINHELP_DeletePageLinks(HLPFILE_PAGE* page)\r
-{\r
-    HLPFILE_LINK*       curr;\r
-    HLPFILE_LINK*       next;\r
-\r
-    for (curr = page->first_link; curr; curr = next)\r
-    {\r
-        next = curr->next;\r
-        HeapFree(GetProcessHeap(), 0, curr);\r
-    }\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_DeleteWindow\r
- */\r
-static void WINHELP_DeleteWindow(WINHELP_WINDOW* win)\r
-{\r
-    WINHELP_WINDOW**    w;\r
-\r
-    for (w = &Globals.win_list; *w; w = &(*w)->next)\r
-    {\r
-        if (*w == win)\r
-        {\r
-            *w = win->next;\r
-            break;\r
-        }\r
-    }\r
-\r
-    if (Globals.active_win == win)\r
-    {\r
-        Globals.active_win = Globals.win_list;\r
-        if (Globals.win_list)\r
-            SetActiveWindow(Globals.win_list->hMainWnd);\r
-    }\r
-\r
-    if (win == Globals.active_popup)\r
-        Globals.active_popup = NULL;\r
-\r
-    WINHELP_DeleteButtons(win);\r
-\r
-    if (win->page) WINHELP_DeletePageLinks(win->page);\r
-    if (win->hShadowWnd) DestroyWindow(win->hShadowWnd);\r
-    if (win->hHistoryWnd) DestroyWindow(win->hHistoryWnd);\r
-\r
-    DeleteObject(win->hBrush);\r
-\r
-    WINHELP_DeleteBackSet(win);\r
-\r
-    if (win->page) HLPFILE_FreeHlpFile(win->page->file);\r
-    HeapFree(GetProcessHeap(), 0, win);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_InitFonts\r
- */\r
-static void WINHELP_InitFonts(HWND hWnd)\r
-{\r
-    WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-    LOGFONT logfontlist[] = {\r
-        {-10, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},\r
-        {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},\r
-        {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},\r
-        {-12, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},\r
-        {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},\r
-        {-10, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},\r
-        { -8, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}};\r
-#define FONTS_LEN (sizeof(logfontlist)/sizeof(*logfontlist))\r
-\r
-    static HFONT fonts[FONTS_LEN];\r
-    static BOOL init = 0;\r
-\r
-    win->fonts_len = FONTS_LEN;\r
-    win->fonts = fonts;\r
-\r
-    if (!init)\r
-    {\r
-        UINT i;\r
-\r
-        for (i = 0; i < FONTS_LEN; i++)\r
-       {\r
-            fonts[i] = CreateFontIndirect(&logfontlist[i]);\r
-       }\r
-\r
-        init = 1;\r
-    }\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_MessageBoxIDS_s\r
- */\r
-INT WINHELP_MessageBoxIDS_s(UINT ids_text, LPCSTR str, UINT ids_title, WORD type)\r
-{\r
-    CHAR text[MAX_STRING_LEN];\r
-    CHAR newtext[MAX_STRING_LEN + MAX_PATH];\r
-\r
-    LoadString(Globals.hInstance, ids_text, text, sizeof(text));\r
-    wsprintf(newtext, text, str);\r
-\r
-    return MessageBox(0, newtext, MAKEINTRESOURCE(ids_title), type);\r
-}\r
-\r
-/**************************************************************************\r
- * cb_KWBTree\r
- *\r
- * HLPFILE_BPTreeCallback enumeration function for '|KWBTREE' internal file.\r
- *\r
- */\r
-static void cb_KWBTree(void *p, void **next, void *cookie)\r
-{\r
-    HWND hListWnd = (HWND)cookie;\r
-    int count;\r
-\r
-    WINE_TRACE("Adding '%s' to search list\n", (char *)p);\r
-    SendMessage(hListWnd, LB_INSERTSTRING, -1, (LPARAM)p);\r
-    count = SendMessage(hListWnd, LB_GETCOUNT, 0, 0);\r
-    SendMessage(hListWnd, LB_SETITEMDATA, count-1, (LPARAM)p);\r
-    *next = (char*)p + strlen((char*)p) + 7;\r
-}\r
-\r
-struct index_data\r
-{\r
-    HLPFILE*    hlpfile;\r
-    BOOL        jump;\r
-    ULONG       offset;\r
-};\r
-\r
-/**************************************************************************\r
- * WINHELP_IndexDlgProc\r
- *\r
- */\r
-INT_PTR CALLBACK WINHELP_IndexDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
-    static struct index_data* id;\r
-    int sel;\r
-\r
-    switch (msg)\r
-    {\r
-    case WM_INITDIALOG:\r
-        id = (struct index_data*)((PROPSHEETPAGE*)lParam)->lParam;\r
-        HLPFILE_BPTreeEnum(id->hlpfile->kwbtree, cb_KWBTree,\r
-                           GetDlgItem(hWnd, IDC_INDEXLIST));\r
-        id->jump = FALSE;\r
-        id->offset = 1;\r
-        return TRUE;\r
-    case WM_COMMAND:\r
-        switch (HIWORD(wParam))\r
-        {\r
-        case LBN_DBLCLK:\r
-            if (LOWORD(wParam) == IDC_INDEXLIST)\r
-                SendMessage(GetParent(hWnd), PSM_PRESSBUTTON, PSBTN_OK, 0);\r
-            break;\r
-        }\r
-        break;\r
-    case WM_NOTIFY:\r
-       switch (((NMHDR*)lParam)->code)\r
-       {\r
-       case PSN_APPLY:\r
-            sel = SendDlgItemMessage(hWnd, IDC_INDEXLIST, LB_GETCURSEL, 0, 0);\r
-            if (sel != LB_ERR)\r
-            {\r
-                BYTE *p;\r
-                int count;\r
-\r
-                p = (BYTE*)SendDlgItemMessage(hWnd, IDC_INDEXLIST,\r
-                                              LB_GETITEMDATA, sel, 0);\r
-                count = *(short*)((char *)p + strlen((char *)p) + 1);\r
-                if (count > 1)\r
-                {\r
-                    MessageBox(hWnd, "count > 1 not supported yet", "Error", MB_OK | MB_ICONSTOP);\r
-                    SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_INVALID);\r
-                    return TRUE;\r
-                }\r
-                id->offset = *(ULONG*)((char *)p + strlen((char *)p) + 3);\r
-                id->offset = *(long*)(id->hlpfile->kwdata + id->offset + 9);\r
-                if (id->offset == 0xFFFFFFFF)\r
-                {\r
-                    MessageBox(hWnd, "macro keywords not supported yet", "Error", MB_OK | MB_ICONSTOP);\r
-                    SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_INVALID);\r
-                    return TRUE;\r
-                }\r
-                id->jump = TRUE;\r
-                SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR);\r
-            }\r
-            return TRUE;\r
-        default:\r
-            return FALSE;\r
-        }\r
-        break;\r
-    default:\r
-        break;\r
-    }\r
-    return FALSE;\r
-}\r
-\r
-/**************************************************************************\r
- * WINHELP_SearchDlgProc\r
- *\r
- */\r
-INT_PTR CALLBACK WINHELP_SearchDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
-    static struct index_data* id;\r
-\r
-    switch (msg)\r
-    {\r
-    case WM_INITDIALOG:\r
-        id = (struct index_data*)((PROPSHEETPAGE*)lParam)->lParam;\r
-        return TRUE;\r
-    case WM_NOTIFY:\r
-       switch (((NMHDR*)lParam)->code)\r
-       {\r
-       case PSN_APPLY:\r
-            SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR);\r
-            return TRUE;\r
-        default:\r
-            return FALSE;\r
-        }\r
-        break;\r
-    default:\r
-        break;\r
-    }\r
-    return FALSE;\r
-}\r
-\r
-/**************************************************************************\r
- * WINHELP_CreateIndexWindow\r
- *\r
- * Displays a dialog with keywords of current help file.\r
- *\r
- */\r
-BOOL WINHELP_CreateIndexWindow(BOOL is_search)\r
-{\r
-    HPROPSHEETPAGE      psPage[3];\r
-    PROPSHEETPAGE       psp;\r
-    PROPSHEETHEADER     psHead;\r
-    struct index_data   id;\r
-    char                buf[256];\r
-\r
-    if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file)\r
-        id.hlpfile = Globals.active_win->page->file;\r
-    else\r
-        return FALSE;\r
-\r
-    if (id.hlpfile->kwbtree == NULL)\r
-    {\r
-        WINE_TRACE("No index provided\n");\r
-        return FALSE;\r
-    }\r
-\r
-    InitCommonControls();\r
-\r
-    id.jump = FALSE;\r
-    memset(&psp, 0, sizeof(psp));\r
-    psp.dwSize = sizeof(psp);\r
-    psp.dwFlags = 0;\r
-    psp.hInstance = Globals.hInstance;\r
-\r
-    psp.u.pszTemplate = MAKEINTRESOURCE(IDD_INDEX);\r
-    psp.lParam = (LPARAM)&id;\r
-    psp.pfnDlgProc = WINHELP_IndexDlgProc;\r
-    psPage[0] = CreatePropertySheetPage(&psp);\r
-\r
-    psp.u.pszTemplate = MAKEINTRESOURCE(IDD_SEARCH);\r
-    psp.lParam = (LPARAM)&id;\r
-    psp.pfnDlgProc = WINHELP_SearchDlgProc;\r
-    psPage[1] = CreatePropertySheetPage(&psp);\r
-\r
-    memset(&psHead, 0, sizeof(psHead));\r
-    psHead.dwSize = sizeof(psHead);\r
-\r
-    LoadString(Globals.hInstance, STID_PSH_INDEX, buf, sizeof(buf));\r
-    strcat(buf, Globals.active_win->info->caption);\r
-\r
-    psHead.pszCaption = buf;\r
-    psHead.nPages = 2;\r
-    psHead.u2.nStartPage = is_search ? 1 : 0;\r
-    psHead.hwndParent = Globals.active_win->hMainWnd;\r
-    psHead.u3.phpage = psPage;\r
-    psHead.dwFlags = PSH_NOAPPLYNOW;\r
-\r
-    PropertySheet(&psHead);\r
-    if (id.jump)\r
-    {\r
-        WINE_TRACE("got %d as an offset\n", id.offset);\r
-        WINHELP_OpenHelpWindow(HLPFILE_PageByOffset, id.hlpfile, id.offset,\r
-                               Globals.active_win->info, SW_NORMAL);\r
-    }\r
-    return TRUE;\r
-}\r
+/*
+ * Help Viewer
+ *
+ * Copyright    1996 Ulrich Schmid <uschmid@mail.hh.provi.de>
+ *              2002 Sylvain Petreolle <spetreolle@yahoo.fr>
+ *              2002, 2008 Eric Pouech <eric.pouech@wanadoo.fr>
+ *              2004 Ken Belleau <jamez@ivic.qc.ca>
+ *              2008 Kirill K. Smirnov <lich@math.spbu.ru>
+ *
+ * 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
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "commdlg.h"
+#include "winhelp.h"
+#include "winhelp_res.h"
+#include "shellapi.h"
+#include "richedit.h"
+#include "commctrl.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(winhelp);
+
+WINHELP_GLOBALS Globals = {3, NULL, TRUE, NULL, NULL, NULL, NULL, NULL, {{{NULL,NULL}},0}, NULL};
+
+#define CTL_ID_BUTTON   0x700
+#define CTL_ID_TEXT     0x701
+
+
+/***********************************************************************
+ *
+ *           WINHELP_InitFonts
+ */
+static void WINHELP_InitFonts(HWND hWnd)
+{
+    WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+    LOGFONT logfontlist[] = {
+        {-10, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},
+        {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},
+        {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},
+        {-12, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},
+        {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},
+        {-10, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},
+        { -8, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}};
+#define FONTS_LEN (sizeof(logfontlist)/sizeof(*logfontlist))
+
+    static HFONT fonts[FONTS_LEN];
+    static BOOL init = 0;
+
+    win->fonts_len = FONTS_LEN;
+    win->fonts = fonts;
+
+    if (!init)
+    {
+        UINT i;
+
+        for (i = 0; i < FONTS_LEN; i++)
+       {
+            fonts[i] = CreateFontIndirect(&logfontlist[i]);
+       }
+
+        init = 1;
+    }
+}
+
+static DWORD CALLBACK WINHELP_RtfStreamIn(DWORD_PTR cookie, BYTE* buff,
+                                          LONG cb, LONG* pcb)
+{
+    struct RtfData*     rd = (struct RtfData*)cookie;
+
+    if (rd->where >= rd->ptr) return 1;
+    if (rd->where + cb > rd->ptr)
+        cb = rd->ptr - rd->where;
+    memcpy(buff, rd->where, cb);
+    rd->where += cb;
+    *pcb = cb;
+    return 0;
+}
+
+static void WINHELP_SetupText(HWND hTextWnd, WINHELP_WINDOW* win, ULONG relative)
+{
+    /* At first clear area - needed by EM_POSFROMCHAR/EM_SETSCROLLPOS */
+    SendMessage(hTextWnd, WM_SETTEXT, 0, (LPARAM)"");
+    SendMessage(hTextWnd, WM_SETREDRAW, FALSE, 0);
+    SendMessage(hTextWnd, EM_SETBKGNDCOLOR, 0, (LPARAM)win->info->sr_color);
+    /* set word-wrap to window size (undocumented) */
+    SendMessage(hTextWnd, EM_SETTARGETDEVICE, 0, 0);
+    if (win->page)
+    {
+        struct RtfData  rd;
+        EDITSTREAM      es;
+        unsigned        cp = 0;
+        POINTL          ptl;
+        POINT           pt;
+
+
+        if (HLPFILE_BrowsePage(win->page, &rd, win->font_scale, relative))
+        {
+            rd.where = rd.data;
+            es.dwCookie = (DWORD_PTR)&rd;
+            es.dwError = 0;
+            es.pfnCallback = WINHELP_RtfStreamIn;
+
+            SendMessageW(hTextWnd, EM_STREAMIN, SF_RTF, (LPARAM)&es);
+            cp = rd.char_pos_rel;
+        }
+        /* FIXME: else leaking potentially the rd.first_link chain */
+        HeapFree(GetProcessHeap(), 0, rd.data);
+        SendMessage(hTextWnd, EM_POSFROMCHAR, (WPARAM)&ptl, cp ? cp - 1 : 0);
+        pt.x = 0; pt.y = ptl.y;
+        SendMessage(hTextWnd, EM_SETSCROLLPOS, 0, (LPARAM)&pt);
+    }
+    SendMessage(hTextWnd, WM_SETREDRAW, TRUE, 0);
+    RedrawWindow(hTextWnd, NULL, NULL, RDW_FRAME|RDW_INVALIDATE);
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_GetOpenFileName
+ */
+BOOL WINHELP_GetOpenFileName(LPSTR lpszFile, int len)
+{
+    OPENFILENAME openfilename;
+    CHAR szDir[MAX_PATH];
+    CHAR szzFilter[2 * MAX_STRING_LEN + 100];
+    LPSTR p = szzFilter;
+
+    WINE_TRACE("()\n");
+
+    LoadString(Globals.hInstance, STID_HELP_FILES_HLP, p, MAX_STRING_LEN);
+    p += strlen(p) + 1;
+    lstrcpy(p, "*.hlp");
+    p += strlen(p) + 1;
+    LoadString(Globals.hInstance, STID_ALL_FILES, p, MAX_STRING_LEN);
+    p += strlen(p) + 1;
+    lstrcpy(p, "*.*");
+    p += strlen(p) + 1;
+    *p = '\0';
+
+    GetCurrentDirectory(sizeof(szDir), szDir);
+
+    lpszFile[0]='\0';
+
+    openfilename.lStructSize       = sizeof(OPENFILENAME);
+    openfilename.hwndOwner         = (Globals.active_win ? Globals.active_win->hMainWnd : 0);
+    openfilename.hInstance         = Globals.hInstance;
+    openfilename.lpstrFilter       = szzFilter;
+    openfilename.lpstrCustomFilter = 0;
+    openfilename.nMaxCustFilter    = 0;
+    openfilename.nFilterIndex      = 1;
+    openfilename.lpstrFile         = lpszFile;
+    openfilename.nMaxFile          = len;
+    openfilename.lpstrFileTitle    = 0;
+    openfilename.nMaxFileTitle     = 0;
+    openfilename.lpstrInitialDir   = szDir;
+    openfilename.lpstrTitle        = 0;
+    openfilename.Flags             = OFN_ENABLESIZING;
+    openfilename.nFileOffset       = 0;
+    openfilename.nFileExtension    = 0;
+    openfilename.lpstrDefExt       = 0;
+    openfilename.lCustData         = 0;
+    openfilename.lpfnHook          = 0;
+    openfilename.lpTemplateName    = 0;
+
+    return GetOpenFileName(&openfilename);
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_MessageBoxIDS_s
+ */
+static INT WINHELP_MessageBoxIDS_s(UINT ids_text, LPCSTR str, UINT ids_title, WORD type)
+{
+    CHAR text[MAX_STRING_LEN];
+    CHAR newtext[MAX_STRING_LEN + MAX_PATH];
+
+    LoadString(Globals.hInstance, ids_text, text, sizeof(text));
+    wsprintf(newtext, text, str);
+
+    return MessageBox(0, newtext, MAKEINTRESOURCE(ids_title), type);
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_LookupHelpFile
+ */
+HLPFILE* WINHELP_LookupHelpFile(LPCSTR lpszFile)
+{
+    HLPFILE*        hlpfile;
+    char szFullName[MAX_PATH];
+    char szAddPath[MAX_PATH];
+    char *p;
+
+    /*
+     * NOTE: This is needed by popup windows only.
+     * In other cases it's not needed but does not hurt though.
+     */
+    if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file)
+    {
+        strcpy(szAddPath, Globals.active_win->page->file->lpszPath);
+        p = strrchr(szAddPath, '\\');
+        if (p) *p = 0;
+    }
+
+    /*
+     * FIXME: Should we swap conditions?
+     */
+    if (!SearchPath(NULL, lpszFile, ".hlp", MAX_PATH, szFullName, NULL) &&
+        !SearchPath(szAddPath, lpszFile, ".hlp", MAX_PATH, szFullName, NULL))
+    {
+        if (WINHELP_MessageBoxIDS_s(STID_FILE_NOT_FOUND_s, lpszFile, STID_WHERROR,
+                                    MB_YESNO|MB_ICONQUESTION) != IDYES)
+            return NULL;
+        if (!WINHELP_GetOpenFileName(szFullName, MAX_PATH))
+            return NULL;
+    }
+    hlpfile = HLPFILE_ReadHlpFile(szFullName);
+    if (!hlpfile)
+        WINHELP_MessageBoxIDS_s(STID_HLPFILE_ERROR_s, lpszFile,
+                                STID_WHERROR, MB_OK|MB_ICONSTOP);
+    return hlpfile;
+}
+
+/******************************************************************
+ *             WINHELP_GetWindowInfo
+ *
+ *
+ */
+HLPFILE_WINDOWINFO*     WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name)
+{
+    static      HLPFILE_WINDOWINFO      mwi;
+    unsigned int     i;
+
+    if (!name || !name[0])
+        name = Globals.active_win->info->name;
+
+    if (hlpfile)
+        for (i = 0; i < hlpfile->numWindows; i++)
+            if (!lstrcmpi(hlpfile->windows[i].name, name))
+                return &hlpfile->windows[i];
+
+    if (strcmp(name, "main") != 0)
+    {
+        WINE_FIXME("Couldn't find window info for %s\n", name);
+        assert(0);
+        return NULL;
+    }
+    if (!mwi.name[0])
+    {
+        strcpy(mwi.type, "primary");
+        strcpy(mwi.name, "main");
+        if (hlpfile && hlpfile->lpszTitle[0])
+        {
+            char        tmp[128];
+            LoadString(Globals.hInstance, STID_WINE_HELP, tmp, sizeof(tmp));
+            snprintf(mwi.caption, sizeof(mwi.caption), "%s %s - %s",
+                     hlpfile->lpszTitle, tmp, hlpfile->lpszPath);
+        }
+        else
+            LoadString(Globals.hInstance, STID_WINE_HELP, mwi.caption, sizeof(mwi.caption));
+        mwi.origin.x = mwi.origin.y = mwi.size.cx = mwi.size.cy = CW_USEDEFAULT;
+        mwi.style = SW_SHOW;
+        mwi.win_style = WS_OVERLAPPEDWINDOW;
+        mwi.sr_color = mwi.nsr_color = 0xFFFFFF;
+    }
+    return &mwi;
+}
+
+/******************************************************************
+ *             HLPFILE_GetPopupWindowInfo
+ *
+ *
+ */
+static HLPFILE_WINDOWINFO*     WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile,
+                                                          WINHELP_WINDOW* parent, LPARAM mouse)
+{
+    static      HLPFILE_WINDOWINFO      wi;
+
+    RECT parent_rect;
+    
+    wi.type[0] = wi.name[0] = wi.caption[0] = '\0';
+
+    /* Calculate horizontal size and position of a popup window */
+    GetWindowRect(parent->hMainWnd, &parent_rect);
+    wi.size.cx = (parent_rect.right  - parent_rect.left) / 2;
+    wi.size.cy = 10; /* need a non null value, so that border are taken into account while computing */
+
+    wi.origin.x = (short)LOWORD(mouse);
+    wi.origin.y = (short)HIWORD(mouse);
+    ClientToScreen(parent->hMainWnd, &wi.origin);
+    wi.origin.x -= wi.size.cx / 2;
+    wi.origin.x  = min(wi.origin.x, GetSystemMetrics(SM_CXSCREEN) - wi.size.cx);
+    wi.origin.x  = max(wi.origin.x, 0);
+
+    wi.style = SW_SHOW;
+    wi.win_style = WS_POPUP | WS_BORDER;
+    if (parent->page->file->has_popup_color)
+        wi.sr_color = parent->page->file->popup_color;
+    else
+        wi.sr_color = parent->info->sr_color;
+    wi.nsr_color = 0xFFFFFF;
+
+    return &wi;
+}
+
+typedef struct
+{
+    WORD size;
+    WORD command;
+    LONG data;
+    LONG reserved;
+    WORD ofsFilename;
+    WORD ofsData;
+} WINHELP,*LPWINHELP;
+
+static BOOL WINHELP_HasWorkingWindow(void)
+{
+    if (!Globals.active_win) return FALSE;
+    if (Globals.active_win->next || Globals.win_list != Globals.active_win) return TRUE;
+    return Globals.active_win->page != NULL && Globals.active_win->page->file != NULL;
+}
+
+/******************************************************************
+ *             WINHELP_HandleCommand
+ *
+ *
+ */
+static LRESULT  WINHELP_HandleCommand(HWND hSrcWnd, LPARAM lParam)
+{
+    COPYDATASTRUCT*     cds = (COPYDATASTRUCT*)lParam;
+    WINHELP*            wh;
+
+    if (cds->dwData != 0xA1DE505)
+    {
+        WINE_FIXME("Wrong magic number (%08lx)\n", cds->dwData);
+        return 0;
+    }
+
+    wh = cds->lpData;
+
+    if (wh)
+    {
+        char*   ptr = (wh->ofsFilename) ? (LPSTR)wh + wh->ofsFilename : NULL;
+
+        WINE_TRACE("Got[%u]: cmd=%u data=%08x fn=%s\n",
+                   wh->size, wh->command, wh->data, ptr);
+        switch (wh->command)
+        {
+        case HELP_CONTEXT:
+            if (ptr)
+            {
+                MACRO_JumpContext(ptr, "main", wh->data);
+            }
+            if (!WINHELP_HasWorkingWindow()) MACRO_Exit();
+            break;
+        case HELP_QUIT:
+            MACRO_Exit();
+            break;
+        case HELP_CONTENTS:
+            if (ptr)
+            {
+                MACRO_JumpContents(ptr, "main");
+            }
+            if (!WINHELP_HasWorkingWindow()) MACRO_Exit();
+            break;
+        case HELP_HELPONHELP:
+            MACRO_HelpOn();
+            if (!WINHELP_HasWorkingWindow()) MACRO_Exit();
+            break;
+        /* case HELP_SETINDEX: */
+        case HELP_SETCONTENTS:
+            if (ptr)
+            {
+                MACRO_SetContents(ptr, wh->data);
+            }
+            break;
+        case HELP_CONTEXTPOPUP:
+            if (ptr)
+            {
+                MACRO_PopupContext(ptr, wh->data);
+            }
+            break;
+        /* case HELP_FORCEFILE:*/
+        /* case HELP_CONTEXTMENU: */
+        case HELP_FINDER:
+            /* in fact, should be the topic dialog box */
+            WINE_FIXME("HELP_FINDER: stub\n");
+            if (ptr)
+            {
+                MACRO_JumpHash(ptr, "main", 0);
+            }
+            break;
+        /* case HELP_WM_HELP: */
+        /* case HELP_SETPOPUP_POS: */
+        /* case HELP_KEY: */
+        /* case HELP_COMMAND: */
+        /* case HELP_PARTIALKEY: */
+        /* case HELP_MULTIKEY: */
+        /* case HELP_SETWINPOS: */
+        default:
+            WINE_FIXME("Unhandled command (%x) for remote winhelp control\n", wh->command);
+            break;
+        }
+    }
+    /* Always return success for now */
+    return 1;
+}
+
+void            WINHELP_LayoutMainWindow(WINHELP_WINDOW* win)
+{
+    RECT        rect, button_box_rect;
+    INT         text_top = 0;
+    HWND        hButtonBoxWnd = GetDlgItem(win->hMainWnd, CTL_ID_BUTTON);
+    HWND        hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);
+
+    GetClientRect(win->hMainWnd, &rect);
+
+    /* Update button box and text Window */
+    SetWindowPos(hButtonBoxWnd, HWND_TOP,
+                 rect.left, rect.top,
+                 rect.right - rect.left,
+                 rect.bottom - rect.top, 0);
+
+    if (GetWindowRect(hButtonBoxWnd, &button_box_rect))
+        text_top = rect.top + button_box_rect.bottom - button_box_rect.top;
+
+    SetWindowPos(hTextWnd, HWND_TOP,
+                 rect.left, text_top,
+                 rect.right - rect.left,
+                 rect.bottom - text_top, 0);
+
+}
+
+/******************************************************************
+ *             WINHELP_DeleteButtons
+ *
+ */
+static void WINHELP_DeleteButtons(WINHELP_WINDOW* win)
+{
+    WINHELP_BUTTON*     b;
+    WINHELP_BUTTON*     bp;
+
+    for (b = win->first_button; b; b = bp)
+    {
+        DestroyWindow(b->hWnd);
+        bp = b->next;
+        HeapFree(GetProcessHeap(), 0, b);
+    }
+    win->first_button = NULL;
+}
+
+/******************************************************************
+ *             WINHELP_DeleteBackSet
+ *
+ */
+void WINHELP_DeleteBackSet(WINHELP_WINDOW* win)
+{
+    unsigned int i;
+
+    for (i = 0; i < win->back.index; i++)
+    {
+        HLPFILE_FreeHlpFile(win->back.set[i].page->file);
+        win->back.set[i].page = NULL;
+    }
+    win->back.index = 0;
+}
+
+/******************************************************************
+ *             WINHELP_DeletePageLinks
+ *
+ */
+static void WINHELP_DeletePageLinks(HLPFILE_PAGE* page)
+{
+    HLPFILE_LINK*       curr;
+    HLPFILE_LINK*       next;
+
+    for (curr = page->first_link; curr; curr = next)
+    {
+        next = curr->next;
+        HeapFree(GetProcessHeap(), 0, curr);
+    }
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_GrabWindow
+ */
+WINHELP_WINDOW* WINHELP_GrabWindow(WINHELP_WINDOW* win)
+{
+    WINE_TRACE("Grab %p#%d++\n", win, win->ref_count);
+    win->ref_count++;
+    return win;
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_RelaseWindow
+ */
+BOOL WINHELP_ReleaseWindow(WINHELP_WINDOW* win)
+{
+    WINE_TRACE("Release %p#%d--\n", win, win->ref_count);
+
+    if (!--win->ref_count)
+    {
+        DestroyWindow(win->hMainWnd);
+        return FALSE;
+    }
+    return TRUE;
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_DeleteWindow
+ */
+static void WINHELP_DeleteWindow(WINHELP_WINDOW* win)
+{
+    WINHELP_WINDOW**    w;
+    BOOL bExit;
+    HWND hTextWnd;
+
+    for (w = &Globals.win_list; *w; w = &(*w)->next)
+    {
+        if (*w == win)
+        {
+            *w = win->next;
+            break;
+        }
+    }
+    bExit = (Globals.wVersion >= 4 && !lstrcmpi(win->info->name, "main"));
+
+    if (Globals.active_win == win)
+    {
+        Globals.active_win = Globals.win_list;
+        if (Globals.win_list)
+            SetActiveWindow(Globals.win_list->hMainWnd);
+    }
+
+    if (win == Globals.active_popup)
+        Globals.active_popup = NULL;
+
+    hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);
+    SetWindowLongPtr(hTextWnd, GWLP_WNDPROC,
+                     (LONG_PTR)win->origRicheditWndProc);
+
+    WINHELP_DeleteButtons(win);
+
+    if (win->page) WINHELP_DeletePageLinks(win->page);
+    if (win->hShadowWnd) DestroyWindow(win->hShadowWnd);
+    if (win->hHistoryWnd) DestroyWindow(win->hHistoryWnd);
+
+    DeleteObject(win->hBrush);
+
+    WINHELP_DeleteBackSet(win);
+
+    if (win->page) HLPFILE_FreeHlpFile(win->page->file);
+    HeapFree(GetProcessHeap(), 0, win);
+
+    if (bExit) MACRO_Exit();
+    if (!Globals.win_list)
+        PostQuitMessage(0);
+}
+
+static char* WINHELP_GetCaption(WINHELP_WNDPAGE* wpage)
+{
+    if (wpage->wininfo->caption[0]) return wpage->wininfo->caption;
+    return wpage->page->file->lpszTitle;
+}
+
+static void WINHELP_RememberPage(WINHELP_WINDOW* win, WINHELP_WNDPAGE* wpage)
+{
+    unsigned        num;
+
+    if (!Globals.history.index || Globals.history.set[0].page != wpage->page)
+    {
+        num = sizeof(Globals.history.set) / sizeof(Globals.history.set[0]);
+        /* we're full, remove latest entry */
+        if (Globals.history.index == num)
+        {
+            HLPFILE_FreeHlpFile(Globals.history.set[num - 1].page->file);
+            Globals.history.index--;
+        }
+        memmove(&Globals.history.set[1], &Globals.history.set[0],
+                Globals.history.index * sizeof(Globals.history.set[0]));
+        Globals.history.set[0] = *wpage;
+        Globals.history.index++;
+        wpage->page->file->wRefCount++;
+    }
+    if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE);
+
+    num = sizeof(win->back.set) / sizeof(win->back.set[0]);
+    if (win->back.index == num)
+    {
+        /* we're full, remove latest entry */
+        HLPFILE_FreeHlpFile(win->back.set[0].page->file);
+        memmove(&win->back.set[0], &win->back.set[1],
+                (num - 1) * sizeof(win->back.set[0]));
+        win->back.index--;
+    }
+    win->back.set[win->back.index++] = *wpage;
+    wpage->page->file->wRefCount++;
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_FindLink
+ */
+static HLPFILE_LINK* WINHELP_FindLink(WINHELP_WINDOW* win, LPARAM pos)
+{
+    HLPFILE_LINK*           link;
+    POINTL                  mouse_ptl, char_ptl, char_next_ptl;
+    DWORD                   cp;
+
+    if (!win->page) return NULL;
+
+    mouse_ptl.x = (short)LOWORD(pos);
+    mouse_ptl.y = (short)HIWORD(pos);
+    cp = SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_CHARFROMPOS,
+                      0, (LPARAM)&mouse_ptl);
+
+    for (link = win->page->first_link; link; link = link->next)
+    {
+        if (link->cpMin <= cp && cp <= link->cpMax)
+        {
+            /* check whether we're at end of line */
+            SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR,
+                         (LPARAM)&char_ptl, cp);
+            SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR,
+                         (LPARAM)&char_next_ptl, cp + 1);
+            if (link->bHotSpot)
+            {
+                HLPFILE_HOTSPOTLINK*    hslink = (HLPFILE_HOTSPOTLINK*)link;
+                if ((mouse_ptl.x < char_ptl.x + hslink->x) ||
+                    (mouse_ptl.x >= char_ptl.x + hslink->x + hslink->width) ||
+                    (mouse_ptl.y < char_ptl.y + hslink->y) ||
+                    (mouse_ptl.y >= char_ptl.y + hslink->y + hslink->height))
+                    continue;
+                break;
+            }
+            if (char_next_ptl.y != char_ptl.y || mouse_ptl.x >= char_next_ptl.x)
+                link = NULL;
+            break;
+        }
+    }
+    return link;
+}
+
+static LRESULT CALLBACK WINHELP_RicheditWndProc(HWND hWnd, UINT msg,
+                                                WPARAM wParam, LPARAM lParam)
+{
+    WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLongPtr(GetParent(hWnd), 0);
+    DWORD messagePos;
+    POINT pt;
+    switch(msg)
+    {
+        case WM_SETCURSOR:
+            messagePos = GetMessagePos();
+            pt.x = (short)LOWORD(messagePos);
+            pt.y = (short)HIWORD(messagePos);
+            ScreenToClient(hWnd, &pt);
+            if (win->page && WINHELP_FindLink(win, MAKELPARAM(pt.x, pt.y)))
+            {
+                SetCursor(win->hHandCur);
+                return 0;
+            }
+            /* fall through */
+        default:
+            return CallWindowProcA(win->origRicheditWndProc, hWnd, msg, wParam, lParam);
+    }
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_CreateHelpWindow
+ */
+BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE* wpage, int nCmdShow, BOOL remember)
+{
+    WINHELP_WINDOW*     win = NULL;
+    BOOL                bPrimary, bPopup, bReUsed = FALSE;
+    HICON               hIcon;
+    HWND                hTextWnd = NULL;
+
+    bPrimary = !lstrcmpi(wpage->wininfo->name, "main");
+    bPopup = !bPrimary && (wpage->wininfo->win_style & WS_POPUP);
+
+    if (!bPopup)
+    {
+        for (win = Globals.win_list; win; win = win->next)
+        {
+            if (!lstrcmpi(win->info->name, wpage->wininfo->name))
+            {
+                POINT   pt = {0, 0};
+                SIZE    sz = {0, 0};
+                DWORD   flags = SWP_NOSIZE | SWP_NOMOVE;
+
+                WINHELP_DeleteButtons(win);
+                bReUsed = TRUE;
+                SetWindowText(win->hMainWnd, WINHELP_GetCaption(wpage));
+                if (wpage->wininfo->origin.x != CW_USEDEFAULT &&
+                    wpage->wininfo->origin.y != CW_USEDEFAULT)
+                {
+                    pt = wpage->wininfo->origin;
+                    flags &= ~SWP_NOSIZE;
+                }
+                if (wpage->wininfo->size.cx != CW_USEDEFAULT &&
+                    wpage->wininfo->size.cy != CW_USEDEFAULT)
+                {
+                    sz = wpage->wininfo->size;
+                    flags &= ~SWP_NOMOVE;
+                }
+                SetWindowPos(win->hMainWnd, HWND_TOP, pt.x, pt.y, sz.cx, sz.cy, flags);
+
+                if (wpage->page && win->page && wpage->page->file != win->page->file)
+                    WINHELP_DeleteBackSet(win);
+                WINHELP_InitFonts(win->hMainWnd);
+
+                win->page = wpage->page;
+                win->info = wpage->wininfo;
+                hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);
+                WINHELP_SetupText(hTextWnd, win, wpage->relative);
+
+                InvalidateRect(win->hMainWnd, NULL, TRUE);
+                if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE);
+
+                break;
+            }
+        }
+    }
+
+    if (!win)
+    {
+        /* Initialize WINHELP_WINDOW struct */
+        win = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINHELP_WINDOW));
+        if (!win) return FALSE;
+        win->next = Globals.win_list;
+        Globals.win_list = win;
+
+        win->hHandCur = LoadCursorW(0, (LPWSTR)IDC_HAND);
+        win->back.index = 0;
+        win->font_scale = 1;
+        WINHELP_GrabWindow(win);
+    }
+    win->page = wpage->page;
+    win->info = wpage->wininfo;
+    WINHELP_GrabWindow(win);
+
+    if (!bPopup && wpage->page && remember)
+    {
+        WINHELP_RememberPage(win, wpage);
+    }
+
+    if (bPopup)
+        Globals.active_popup = win;
+    else
+        Globals.active_win = win;
+
+    /* Initialize default pushbuttons */
+    if (bPrimary && wpage->page)
+    {
+        CHAR    buffer[MAX_STRING_LEN];
+
+        LoadString(Globals.hInstance, STID_CONTENTS, buffer, sizeof(buffer));
+        MACRO_CreateButton("BTN_CONTENTS", buffer, "Contents()");
+        LoadString(Globals.hInstance, STID_INDEX, buffer, sizeof(buffer));
+        MACRO_CreateButton("BTN_INDEX", buffer, "Finder()");
+        LoadString(Globals.hInstance, STID_BACK, buffer, sizeof(buffer));
+        MACRO_CreateButton("BTN_BACK", buffer, "Back()");
+        if (win->back.index <= 1) MACRO_DisableButton("BTN_BACK");
+    }
+
+    if (!bReUsed)
+    {
+        win->hMainWnd = CreateWindowEx((bPopup) ? WS_EX_TOOLWINDOW : 0, MAIN_WIN_CLASS_NAME,
+                                       WINHELP_GetCaption(wpage),
+                                       bPrimary ? WS_OVERLAPPEDWINDOW : wpage->wininfo->win_style,
+                                       wpage->wininfo->origin.x, wpage->wininfo->origin.y,
+                                       wpage->wininfo->size.cx, wpage->wininfo->size.cy,
+                                       bPopup ? Globals.active_win->hMainWnd : NULL,
+                                       bPrimary ? LoadMenu(Globals.hInstance, MAKEINTRESOURCE(MAIN_MENU)) : 0,
+                                       Globals.hInstance, win);
+        if (!bPopup)
+            /* Create button box and text Window */
+            CreateWindow(BUTTON_BOX_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE,
+                         0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_BUTTON, Globals.hInstance, NULL);
+
+        hTextWnd = CreateWindow(RICHEDIT_CLASS, NULL,
+                                ES_MULTILINE | ES_READONLY | WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE,
+                                0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_TEXT, Globals.hInstance, NULL);
+        SendMessage(hTextWnd, EM_SETEVENTMASK, 0,
+                    SendMessage(hTextWnd, EM_GETEVENTMASK, 0, 0) | ENM_MOUSEEVENTS);
+        win->origRicheditWndProc = (WNDPROC)SetWindowLongPtr(hTextWnd, GWLP_WNDPROC,
+                                                             (LONG_PTR)WINHELP_RicheditWndProc);
+    }
+
+    hIcon = (wpage->page) ? wpage->page->file->hIcon : NULL;
+    if (!hIcon) hIcon = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_WINHELP));
+    SendMessage(win->hMainWnd, WM_SETICON, ICON_SMALL, (DWORD_PTR)hIcon);
+
+    /* Initialize file specific pushbuttons */
+    if (!(wpage->wininfo->win_style & WS_POPUP) && wpage->page)
+    {
+        HLPFILE_MACRO  *macro;
+        for (macro = wpage->page->file->first_macro; macro; macro = macro->next)
+            MACRO_ExecuteMacro(win, macro->lpszMacro);
+
+        for (macro = wpage->page->first_macro; macro; macro = macro->next)
+            MACRO_ExecuteMacro(win, macro->lpszMacro);
+    }
+    /* See #17681, in some cases, the newly created window is closed by the macros it contains
+     * (braindead), so deal with this case
+     */
+    for (win = Globals.win_list; win; win = win->next)
+    {
+        if (!lstrcmpi(win->info->name, wpage->wininfo->name)) break;
+    }
+    if (!win || !WINHELP_ReleaseWindow(win)) return TRUE;
+
+    if (bPopup)
+    {
+        DWORD   mask = SendMessage(hTextWnd, EM_GETEVENTMASK, 0, 0);
+        RECT    rect;
+
+        win->font_scale = Globals.active_win->font_scale;
+        WINHELP_SetupText(hTextWnd, win, wpage->relative);
+
+        /* we need the window to be shown for richedit to compute the size */
+        ShowWindow(win->hMainWnd, nCmdShow);
+        SendMessage(hTextWnd, EM_SETEVENTMASK, 0, mask | ENM_REQUESTRESIZE);
+        SendMessage(hTextWnd, EM_REQUESTRESIZE, 0, 0);
+        SendMessage(hTextWnd, EM_SETEVENTMASK, 0, mask);
+
+        GetWindowRect(win->hMainWnd, &rect);
+        win->hShadowWnd = CreateWindowEx(WS_EX_TOOLWINDOW, SHADOW_WIN_CLASS_NAME,
+                                         "", WS_POPUP | WS_VISIBLE,
+                                         rect.left + SHADOW_DX, rect.top + SHADOW_DY,
+                                         rect.right - rect.left,
+                                         rect.bottom - rect.top,
+                                         Globals.active_win->hMainWnd, 0,
+                                         Globals.hInstance, NULL);
+        SetWindowPos(win->hMainWnd, win->hShadowWnd, 0, 0, 0, 0,
+                     SWP_NOSIZE | SWP_NOMOVE);
+    }
+    else
+    {
+        WINHELP_SetupText(hTextWnd, win, wpage->relative);
+        WINHELP_LayoutMainWindow(win);
+        ShowWindow(win->hMainWnd, nCmdShow);
+    }
+
+    return TRUE;
+}
+
+/******************************************************************
+ *             WINHELP_OpenHelpWindow
+ * Main function to search for a page and display it in a window
+ */
+BOOL WINHELP_OpenHelpWindow(HLPFILE_PAGE* (*lookup)(HLPFILE*, LONG, ULONG*),
+                            HLPFILE* hlpfile, LONG val, HLPFILE_WINDOWINFO* wi,
+                            int nCmdShow)
+{
+    WINHELP_WNDPAGE     wpage;
+
+    wpage.page = lookup(hlpfile, val, &wpage.relative);
+    if (wpage.page) wpage.page->file->wRefCount++;
+    wpage.wininfo = wi;
+    return WINHELP_CreateHelpWindow(&wpage, nCmdShow, TRUE);
+}
+
+/******************************************************************
+ *             WINHELP_HandleTextMouse
+ *
+ */
+static BOOL WINHELP_HandleTextMouse(WINHELP_WINDOW* win, UINT msg, LPARAM lParam)
+{
+    HLPFILE*                hlpfile;
+    HLPFILE_LINK*           link;
+    BOOL                    ret = FALSE;
+
+    switch (msg)
+    {
+    case WM_LBUTTONDOWN:
+        if ((link = WINHELP_FindLink(win, lParam)))
+        {
+            HLPFILE_WINDOWINFO*     wi;
+
+            switch (link->cookie)
+            {
+            case hlp_link_link:
+                if ((hlpfile = WINHELP_LookupHelpFile(link->string)))
+                {
+                    if (link->window == -1)
+                        wi = win->info;
+                    else if (link->window < hlpfile->numWindows)
+                        wi = &hlpfile->windows[link->window];
+                    else
+                    {
+                        WINE_WARN("link to window %d/%d\n", link->window, hlpfile->numWindows);
+                        break;
+                    }
+                    WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash, wi, SW_NORMAL);
+                }
+                break;
+            case hlp_link_popup:
+                if ((hlpfile = WINHELP_LookupHelpFile(link->string)))
+                    WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash,
+                                           WINHELP_GetPopupWindowInfo(hlpfile, win, lParam),
+                                           SW_NORMAL);
+                break;
+            case hlp_link_macro:
+                MACRO_ExecuteMacro(win, link->string);
+                break;
+            default:
+                WINE_FIXME("Unknown link cookie %d\n", link->cookie);
+            }
+            ret = TRUE;
+        }
+        break;
+    }
+    return ret;
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_CheckPopup
+ */
+static BOOL WINHELP_CheckPopup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT* lret)
+{
+    WINHELP_WINDOW*     popup;
+
+    if (!Globals.active_popup) return FALSE;
+
+    switch (msg)
+    {
+    case WM_NOTIFY:
+        {
+            MSGFILTER*  msgf = (MSGFILTER*)lParam;
+            if (msgf->nmhdr.code == EN_MSGFILTER)
+            {
+                if (!WINHELP_CheckPopup(hWnd, msgf->msg, msgf->wParam, msgf->lParam, NULL))
+                    return FALSE;
+                if (lret) *lret = 1;
+                return TRUE;
+            }
+        }
+        break;
+    case WM_ACTIVATE:
+        if (wParam != WA_INACTIVE || (HWND)lParam == Globals.active_win->hMainWnd ||
+            (HWND)lParam == Globals.active_popup->hMainWnd ||
+            GetWindow((HWND)lParam, GW_OWNER) == Globals.active_win->hMainWnd)
+            break;
+    case WM_LBUTTONDOWN:
+        if (WINHELP_HandleTextMouse(Globals.active_popup, msg, lParam))
+            return FALSE;
+        /* fall through */
+    case WM_LBUTTONUP:
+    case WM_MBUTTONDOWN:
+    case WM_RBUTTONDOWN:
+    case WM_NCLBUTTONDOWN:
+    case WM_NCMBUTTONDOWN:
+    case WM_NCRBUTTONDOWN:
+        popup = Globals.active_popup;
+        Globals.active_popup = NULL;
+        WINHELP_ReleaseWindow(popup);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_ButtonWndProc
+ */
+static LRESULT CALLBACK WINHELP_ButtonWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0;
+
+    if (msg == WM_KEYDOWN)
+    {
+        switch (wParam)
+        {
+        case VK_UP:
+        case VK_DOWN:
+        case VK_PRIOR:
+        case VK_NEXT:
+        case VK_ESCAPE:
+            return SendMessage(GetParent(hWnd), msg, wParam, lParam);
+        }
+    }
+
+    return CallWindowProc(Globals.button_proc, hWnd, msg, wParam, lParam);
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_ButtonBoxWndProc
+ */
+static LRESULT CALLBACK WINHELP_ButtonBoxWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    WINDOWPOS      *winpos;
+    WINHELP_WINDOW *win;
+    WINHELP_BUTTON *button;
+    SIZE button_size;
+    INT  x, y;
+
+    if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0L;
+
+    switch (msg)
+    {
+    case WM_WINDOWPOSCHANGING:
+        winpos = (WINDOWPOS*) lParam;
+        win = (WINHELP_WINDOW*) GetWindowLongPtr(GetParent(hWnd), 0);
+
+        /* Update buttons */
+        button_size.cx = 0;
+        button_size.cy = 0;
+        for (button = win->first_button; button; button = button->next)
+       {
+            HDC  hDc;
+            SIZE textsize;
+            if (!button->hWnd)
+            {
+                button->hWnd = CreateWindow(STRING_BUTTON, button->lpszName,
+                                            WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
+                                            0, 0, 0, 0,
+                                            hWnd, (HMENU) button->wParam,
+                                            Globals.hInstance, 0);
+                if (button->hWnd)
+                {
+                    if (Globals.button_proc == NULL)
+                    {
+                        NONCLIENTMETRICSW ncm;
+                        Globals.button_proc = (WNDPROC) GetWindowLongPtr(button->hWnd, GWLP_WNDPROC);
+
+                        ncm.cbSize = sizeof(NONCLIENTMETRICSW);
+                        SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
+                                              sizeof(NONCLIENTMETRICSW), &ncm, 0);
+                        Globals.hButtonFont = CreateFontIndirectW(&ncm.lfMenuFont);
+                    }
+                    SetWindowLongPtr(button->hWnd, GWLP_WNDPROC, (LONG_PTR) WINHELP_ButtonWndProc);
+                    if (Globals.hButtonFont)
+                        SendMessage(button->hWnd, WM_SETFONT, (WPARAM)Globals.hButtonFont, TRUE);
+                }
+            }
+            hDc = GetDC(button->hWnd);
+            GetTextExtentPoint(hDc, button->lpszName,
+                               lstrlen(button->lpszName), &textsize);
+            ReleaseDC(button->hWnd, hDc);
+
+            button_size.cx = max(button_size.cx, textsize.cx + BUTTON_CX);
+            button_size.cy = max(button_size.cy, textsize.cy + BUTTON_CY);
+       }
+
+        x = 0;
+        y = 0;
+        for (button = win->first_button; button; button = button->next)
+       {
+            SetWindowPos(button->hWnd, HWND_TOP, x, y, button_size.cx, button_size.cy, 0);
+
+            if (x + 2 * button_size.cx <= winpos->cx)
+                x += button_size.cx;
+            else
+                x = 0, y += button_size.cy;
+       }
+        winpos->cy = y + (x ? button_size.cy : 0);
+        break;
+
+    case WM_COMMAND:
+        SendMessage(GetParent(hWnd), msg, wParam, lParam);
+        break;
+
+    case WM_KEYDOWN:
+        switch (wParam)
+        {
+        case VK_UP:
+        case VK_DOWN:
+        case VK_PRIOR:
+        case VK_NEXT:
+        case VK_ESCAPE:
+            return SendMessage(GetParent(hWnd), msg, wParam, lParam);
+        }
+        break;
+    }
+
+    return DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+/******************************************************************
+ *             WINHELP_HistoryWndProc
+ *
+ *
+ */
+static LRESULT CALLBACK WINHELP_HistoryWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    WINHELP_WINDOW*     win;
+    PAINTSTRUCT         ps;
+    HDC                 hDc;
+    TEXTMETRIC          tm;
+    unsigned int        i;
+    RECT                r;
+
+    switch (msg)
+    {
+    case WM_NCCREATE:
+        win = (WINHELP_WINDOW*)((LPCREATESTRUCT)lParam)->lpCreateParams;
+        SetWindowLongPtr(hWnd, 0, (ULONG_PTR)win);
+        win->hHistoryWnd = hWnd;
+        break;
+    case WM_CREATE:
+        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+        hDc = GetDC(hWnd);
+        GetTextMetrics(hDc, &tm);
+        GetWindowRect(hWnd, &r);
+
+        r.right = r.left + 30 * tm.tmAveCharWidth;
+        r.bottom = r.top + (sizeof(Globals.history.set) / sizeof(Globals.history.set[0])) * tm.tmHeight;
+        AdjustWindowRect(&r, GetWindowLong(hWnd, GWL_STYLE), FALSE);
+        if (r.left < 0) {r.right -= r.left; r.left = 0;}
+        if (r.top < 0) {r.bottom -= r.top; r.top = 0;}
+
+        MoveWindow(hWnd, r.left, r.top, r.right, r.bottom, TRUE);
+        ReleaseDC(hWnd, hDc);
+        break;
+    case WM_LBUTTONDOWN:
+        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+        hDc = GetDC(hWnd);
+        GetTextMetrics(hDc, &tm);
+        i = HIWORD(lParam) / tm.tmHeight;
+        if (i < Globals.history.index)
+            WINHELP_CreateHelpWindow(&Globals.history.set[i], SW_SHOW, TRUE);
+        ReleaseDC(hWnd, hDc);
+        break;
+    case WM_PAINT:
+        hDc = BeginPaint(hWnd, &ps);
+        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+        GetTextMetrics(hDc, &tm);
+
+        for (i = 0; i < Globals.history.index; i++)
+        {
+            if (Globals.history.set[i].page->file == Globals.active_win->page->file)
+            {
+                TextOut(hDc, 0, i * tm.tmHeight,
+                        Globals.history.set[i].page->lpszTitle,
+                        strlen(Globals.history.set[i].page->lpszTitle));
+            }
+            else
+            {
+                char        buffer[1024];
+                const char* ptr1;
+                const char* ptr2;
+                unsigned    len;
+
+                ptr1 = strrchr(Globals.history.set[i].page->file->lpszPath, '\\');
+                if (!ptr1) ptr1 = Globals.history.set[i].page->file->lpszPath;
+                else ptr1++;
+                ptr2 = strrchr(ptr1, '.');
+                len = ptr2 ? ptr2 - ptr1 : strlen(ptr1);
+                if (len > sizeof(buffer)) len = sizeof(buffer);
+                memcpy(buffer, ptr1, len);
+                if (len < sizeof(buffer)) buffer[len++] = ':';
+                strncpy(&buffer[len], Globals.history.set[i].page->lpszTitle, sizeof(buffer) - len);
+                buffer[sizeof(buffer) - 1] = '\0';
+                TextOut(hDc, 0, i * tm.tmHeight, buffer, strlen(buffer));
+            }
+        }
+        EndPaint(hWnd, &ps);
+        break;
+    case WM_DESTROY:
+        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+        if (hWnd == win->hHistoryWnd)
+            win->hHistoryWnd = 0;
+        break;
+    }
+    return DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_ShadowWndProc
+ */
+static LRESULT CALLBACK WINHELP_ShadowWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0;
+    return WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL) ? 0L : DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+/**************************************************************************
+ * cb_KWBTree
+ *
+ * HLPFILE_BPTreeCallback enumeration function for '|KWBTREE' internal file.
+ *
+ */
+static void cb_KWBTree(void *p, void **next, void *cookie)
+{
+    HWND hListWnd = cookie;
+    int count;
+
+    WINE_TRACE("Adding '%s' to search list\n", (char *)p);
+    SendMessage(hListWnd, LB_INSERTSTRING, -1, (LPARAM)p);
+    count = SendMessage(hListWnd, LB_GETCOUNT, 0, 0);
+    SendMessage(hListWnd, LB_SETITEMDATA, count-1, (LPARAM)p);
+    *next = (char*)p + strlen((char*)p) + 7;
+}
+
+struct index_data
+{
+    HLPFILE*    hlpfile;
+    BOOL        jump;
+    ULONG       offset;
+};
+
+/**************************************************************************
+ * WINHELP_IndexDlgProc
+ *
+ */
+static INT_PTR CALLBACK WINHELP_IndexDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    static struct index_data* id;
+    int sel;
+
+    switch (msg)
+    {
+    case WM_INITDIALOG:
+        id = (struct index_data*)((PROPSHEETPAGE*)lParam)->lParam;
+        HLPFILE_BPTreeEnum(id->hlpfile->kwbtree, cb_KWBTree,
+                           GetDlgItem(hWnd, IDC_INDEXLIST));
+        id->jump = FALSE;
+        id->offset = 1;
+        return TRUE;
+    case WM_COMMAND:
+        switch (HIWORD(wParam))
+        {
+        case LBN_DBLCLK:
+            if (LOWORD(wParam) == IDC_INDEXLIST)
+                SendMessage(GetParent(hWnd), PSM_PRESSBUTTON, PSBTN_OK, 0);
+            break;
+        }
+        break;
+    case WM_NOTIFY:
+       switch (((NMHDR*)lParam)->code)
+       {
+       case PSN_APPLY:
+            sel = SendDlgItemMessage(hWnd, IDC_INDEXLIST, LB_GETCURSEL, 0, 0);
+            if (sel != LB_ERR)
+            {
+                BYTE *p;
+                int count;
+
+                p = (BYTE*)SendDlgItemMessage(hWnd, IDC_INDEXLIST,
+                                              LB_GETITEMDATA, sel, 0);
+                count = *(short*)((char *)p + strlen((char *)p) + 1);
+                if (count > 1)
+                {
+                    MessageBox(hWnd, "count > 1 not supported yet", "Error", MB_OK | MB_ICONSTOP);
+                    SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_INVALID);
+                    return TRUE;
+                }
+                id->offset = *(ULONG*)((char *)p + strlen((char *)p) + 3);
+                id->offset = *(long*)(id->hlpfile->kwdata + id->offset + 9);
+                if (id->offset == 0xFFFFFFFF)
+                {
+                    MessageBox(hWnd, "macro keywords not supported yet", "Error", MB_OK | MB_ICONSTOP);
+                    SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_INVALID);
+                    return TRUE;
+                }
+                id->jump = TRUE;
+                SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR);
+            }
+            return TRUE;
+        default:
+            return FALSE;
+        }
+        break;
+    default:
+        break;
+    }
+    return FALSE;
+}
+
+/**************************************************************************
+ * WINHELP_SearchDlgProc
+ *
+ */
+static INT_PTR CALLBACK WINHELP_SearchDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    static struct index_data* id;
+
+    switch (msg)
+    {
+    case WM_INITDIALOG:
+        id = (struct index_data*)((PROPSHEETPAGE*)lParam)->lParam;
+        return TRUE;
+    case WM_NOTIFY:
+       switch (((NMHDR*)lParam)->code)
+       {
+       case PSN_APPLY:
+            SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR);
+            return TRUE;
+        default:
+            return FALSE;
+        }
+        break;
+    default:
+        break;
+    }
+    return FALSE;
+}
+
+/***********************************************************************
+ *
+ *           WINHELP_MainWndProc
+ */
+static LRESULT CALLBACK WINHELP_MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    WINHELP_WINDOW *win;
+    WINHELP_BUTTON *button;
+    INT  keyDelta;
+    HWND hTextWnd;
+    LRESULT ret;
+
+    if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, &ret)) return ret;
+
+    switch (msg)
+    {
+    case WM_NCCREATE:
+        win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams;
+        SetWindowLongPtr(hWnd, 0, (ULONG_PTR) win);
+        if (!win->page && Globals.isBook)
+            PostMessage(hWnd, WM_COMMAND, MNID_FILE_OPEN, 0);
+        win->hMainWnd = hWnd;
+        break;
+
+    case WM_WINDOWPOSCHANGED:
+        WINHELP_LayoutMainWindow((WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0));
+        break;
+
+    case WM_COMMAND:
+        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+        switch (wParam)
+       {
+            /* Menu FILE */
+       case MNID_FILE_OPEN:    MACRO_FileOpen();       break;
+       case MNID_FILE_PRINT:   MACRO_Print();          break;
+       case MNID_FILE_SETUP:   MACRO_PrinterSetup();   break;
+       case MNID_FILE_EXIT:    MACRO_Exit();           break;
+
+            /* Menu EDIT */
+       case MNID_EDIT_COPYDLG:
+            SendMessage(GetDlgItem(hWnd, CTL_ID_TEXT), WM_COPY, 0, 0);
+            break;
+       case MNID_EDIT_ANNOTATE:MACRO_Annotate();       break;
+
+            /* Menu Bookmark */
+       case MNID_BKMK_DEFINE:  MACRO_BookmarkDefine(); break;
+
+            /* Menu Help */
+       case MNID_HELP_HELPON:  MACRO_HelpOn();         break;
+       case MNID_HELP_HELPTOP: MACRO_HelpOnTop();      break;
+       case MNID_HELP_ABOUT:   MACRO_About();          break;
+       case MNID_HELP_WINE:    ShellAbout(hWnd, "WINE", "Help", 0); break;
+
+            /* Context help */
+        case MNID_CTXT_ANNOTATE:MACRO_Annotate();       break;
+        case MNID_CTXT_COPY:    MACRO_CopyDialog();     break;
+        case MNID_CTXT_PRINT:   MACRO_Print();          break;
+        case MNID_OPTS_HISTORY: MACRO_History();        break;
+        case MNID_OPTS_FONTS_SMALL:
+        case MNID_CTXT_FONTS_SMALL:
+            win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+            if (win->font_scale != 0)
+            {
+                win->font_scale = 0;
+                WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);
+            }
+            break;
+        case MNID_OPTS_FONTS_NORMAL:
+        case MNID_CTXT_FONTS_NORMAL:
+            win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+            if (win->font_scale != 1)
+            {
+                win->font_scale = 1;
+                WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);
+            }
+            break;
+        case MNID_OPTS_FONTS_LARGE:
+        case MNID_CTXT_FONTS_LARGE:
+            win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+            if (win->font_scale != 2)
+            {
+                win->font_scale = 2;
+                WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);
+            }
+            break;
+        case MNID_OPTS_HELP_DEFAULT:
+        case MNID_OPTS_HELP_VISIBLE:
+        case MNID_OPTS_HELP_NONVISIBLE:
+        case MNID_OPTS_SYSTEM_COLORS:
+        case MNID_CTXT_HELP_DEFAULT:
+        case MNID_CTXT_HELP_VISIBLE:
+        case MNID_CTXT_HELP_NONVISIBLE:
+        case MNID_CTXT_SYSTEM_COLORS:
+            /* FIXME: NIY */
+
+       default:
+            /* Buttons */
+            for (button = win->first_button; button; button = button->next)
+                if (wParam == button->wParam) break;
+            if (button)
+                MACRO_ExecuteMacro(win, button->lpszMacro);
+            else if (!HIWORD(wParam))
+                MessageBox(0, MAKEINTRESOURCE(STID_NOT_IMPLEMENTED),
+                           MAKEINTRESOURCE(STID_WHERROR), MB_OK);
+            break;
+       }
+        break;
+/* EPP     case WM_DESTROY: */
+/* EPP         if (Globals.hPopupWnd) DestroyWindow(Globals.hPopupWnd); */
+/* EPP         break; */
+    case WM_COPYDATA:
+        return WINHELP_HandleCommand((HWND)wParam, lParam);
+
+    case WM_CHAR:
+        if (wParam == 3)
+        {
+            SendMessage(GetDlgItem(hWnd, CTL_ID_TEXT), WM_COPY, 0, 0);
+            return 0;
+        }
+        break;
+
+    case WM_KEYDOWN:
+        keyDelta = 0;
+        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+        hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);
+
+        switch (wParam)
+        {
+        case VK_UP:
+            SendMessage(hTextWnd, EM_SCROLL, SB_LINEUP, 0);
+            return 0;
+        case VK_DOWN:
+            SendMessage(hTextWnd, EM_SCROLL, SB_LINEDOWN, 0);
+            return 0;
+        case VK_PRIOR:
+            SendMessage(hTextWnd, EM_SCROLL, SB_PAGEUP, 0);
+            return 0;
+        case VK_NEXT:
+            SendMessage(hTextWnd, EM_SCROLL, SB_PAGEDOWN, 0);
+            return 0;
+        case VK_ESCAPE:
+            MACRO_Exit();
+            return 0;
+        }
+        break;
+
+    case WM_NOTIFY:
+        if (wParam == CTL_ID_TEXT)
+        {
+            RECT        rc;
+
+            switch (((NMHDR*)lParam)->code)
+            {
+            case EN_MSGFILTER:
+                {
+                    const MSGFILTER*    msgf = (const MSGFILTER*)lParam;
+                    switch (msgf->msg)
+                    {
+                    case WM_KEYUP:
+                        if (msgf->wParam == VK_ESCAPE)
+                            WINHELP_ReleaseWindow((WINHELP_WINDOW*)GetWindowLongPtr(hWnd, 0));
+                        break;
+                    case WM_RBUTTONDOWN:
+                    {
+                        HMENU       hMenu;
+                        POINT       pt;
+
+                        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+                        hMenu = LoadMenu(Globals.hInstance, (LPSTR)CONTEXT_MENU);
+                        switch (win->font_scale)
+                        {
+                        case 0:
+                            CheckMenuItem(hMenu, MNID_CTXT_FONTS_SMALL,
+                                          MF_BYCOMMAND|MF_CHECKED);
+                            break;
+                        default:
+                            WINE_FIXME("Unsupported %d\n", win->font_scale);
+                        case 1:
+                            CheckMenuItem(hMenu, MNID_CTXT_FONTS_NORMAL,
+                                          MF_BYCOMMAND|MF_CHECKED);
+                            break;
+                        case 2:
+                            CheckMenuItem(hMenu, MNID_CTXT_FONTS_LARGE,
+                                          MF_BYCOMMAND|MF_CHECKED);
+                            break;
+                        }
+                        pt.x = (int)(short)LOWORD(msgf->lParam);
+                        pt.y = (int)(short)HIWORD(msgf->lParam);
+                        ClientToScreen(msgf->nmhdr.hwndFrom, &pt);
+                        TrackPopupMenu(GetSubMenu(hMenu, 0), TPM_LEFTALIGN|TPM_TOPALIGN,
+                                       pt.x, pt.y, 0, hWnd, NULL);
+                        DestroyMenu(hMenu);
+                    }
+                    break;
+                    default:
+                        return WINHELP_HandleTextMouse((WINHELP_WINDOW*)GetWindowLongPtr(hWnd, 0),
+                                                       msgf->msg, msgf->lParam);
+                    }
+                }
+                break;
+
+            case EN_REQUESTRESIZE:
+                rc = ((REQRESIZE*)lParam)->rc;
+                win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+                AdjustWindowRect(&rc, GetWindowLong(win->hMainWnd, GWL_STYLE),
+                                 FALSE);
+                SetWindowPos(win->hMainWnd, HWND_TOP, 0, 0,
+                             rc.right - rc.left, rc.bottom - rc.top,
+                             SWP_NOMOVE | SWP_NOZORDER);
+                WINHELP_LayoutMainWindow(win);
+                break;
+            }
+        }
+        break;
+
+    case WM_INITMENUPOPUP:
+        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+        CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_SMALL,
+                      MF_BYCOMMAND | (win->font_scale == 0) ? MF_CHECKED : 0);
+        CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_NORMAL,
+                      MF_BYCOMMAND | (win->font_scale == 1) ? MF_CHECKED : 0);
+        CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_LARGE,
+                      MF_BYCOMMAND | (win->font_scale == 2) ? MF_CHECKED : 0);
+        break;
+    case WM_DESTROY:
+        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);
+        WINHELP_DeleteWindow(win);
+        break;
+    }
+    return DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+/**************************************************************************
+ * WINHELP_CreateIndexWindow
+ *
+ * Displays a dialog with keywords of current help file.
+ *
+ */
+BOOL WINHELP_CreateIndexWindow(BOOL is_search)
+{
+    HPROPSHEETPAGE      psPage[3];
+    PROPSHEETPAGE       psp;
+    PROPSHEETHEADER     psHead;
+    struct index_data   id;
+    char                buf[256];
+
+    if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file)
+        id.hlpfile = Globals.active_win->page->file;
+    else
+        return FALSE;
+
+    if (id.hlpfile->kwbtree == NULL)
+    {
+        WINE_TRACE("No index provided\n");
+        return FALSE;
+    }
+
+    InitCommonControls();
+
+    id.jump = FALSE;
+    memset(&psp, 0, sizeof(psp));
+    psp.dwSize = sizeof(psp);
+    psp.dwFlags = 0;
+    psp.hInstance = Globals.hInstance;
+
+    psp.u.pszTemplate = MAKEINTRESOURCE(IDD_INDEX);
+    psp.lParam = (LPARAM)&id;
+    psp.pfnDlgProc = WINHELP_IndexDlgProc;
+    psPage[0] = CreatePropertySheetPage(&psp);
+
+    psp.u.pszTemplate = MAKEINTRESOURCE(IDD_SEARCH);
+    psp.lParam = (LPARAM)&id;
+    psp.pfnDlgProc = WINHELP_SearchDlgProc;
+    psPage[1] = CreatePropertySheetPage(&psp);
+
+    memset(&psHead, 0, sizeof(psHead));
+    psHead.dwSize = sizeof(psHead);
+
+    LoadString(Globals.hInstance, STID_PSH_INDEX, buf, sizeof(buf));
+    strcat(buf, Globals.active_win->info->caption);
+
+    psHead.pszCaption = buf;
+    psHead.nPages = 2;
+    psHead.u2.nStartPage = is_search ? 1 : 0;
+    psHead.hwndParent = Globals.active_win->hMainWnd;
+    psHead.u3.phpage = psPage;
+    psHead.dwFlags = PSH_NOAPPLYNOW;
+
+    PropertySheet(&psHead);
+    if (id.jump)
+    {
+        WINE_TRACE("got %d as an offset\n", id.offset);
+        WINHELP_OpenHelpWindow(HLPFILE_PageByOffset, id.hlpfile, id.offset,
+                               Globals.active_win->info, SW_NORMAL);
+    }
+    return TRUE;
+}
+
+/***********************************************************************
+ *
+ *           RegisterWinClasses
+ */
+static BOOL WINHELP_RegisterWinClasses(void)
+{
+    WNDCLASS class_main, class_button_box, class_shadow, class_history;
+
+    class_main.style               = CS_HREDRAW | CS_VREDRAW;
+    class_main.lpfnWndProc         = WINHELP_MainWndProc;
+    class_main.cbClsExtra          = 0;
+    class_main.cbWndExtra          = sizeof(WINHELP_WINDOW *);
+    class_main.hInstance           = Globals.hInstance;
+    class_main.hIcon               = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_WINHELP));
+    class_main.hCursor             = LoadCursor(0, IDC_ARROW);
+    class_main.hbrBackground       = (HBRUSH)(COLOR_WINDOW+1);
+    class_main.lpszMenuName        = 0;
+    class_main.lpszClassName       = MAIN_WIN_CLASS_NAME;
+
+    class_button_box               = class_main;
+    class_button_box.lpfnWndProc   = WINHELP_ButtonBoxWndProc;
+    class_button_box.cbWndExtra    = 0;
+    class_button_box.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
+    class_button_box.lpszClassName = BUTTON_BOX_WIN_CLASS_NAME;
+
+    class_shadow                   = class_main;
+    class_shadow.lpfnWndProc       = WINHELP_ShadowWndProc;
+    class_shadow.cbWndExtra        = 0;
+    class_shadow.hbrBackground     = (HBRUSH)(COLOR_3DDKSHADOW+1);
+    class_shadow.lpszClassName     = SHADOW_WIN_CLASS_NAME;
+
+    class_history                  = class_main;
+    class_history.lpfnWndProc      = WINHELP_HistoryWndProc;
+    class_history.lpszClassName    = HISTORY_WIN_CLASS_NAME;
+
+    return (RegisterClass(&class_main) &&
+            RegisterClass(&class_button_box) &&
+            RegisterClass(&class_shadow) &&
+            RegisterClass(&class_history));
+}
+
+/***********************************************************************
+ *
+ *           WinMain
+ */
+int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)
+{
+    MSG                 msg;
+    LONG                lHash = 0;
+    HLPFILE*            hlpfile;
+    static CHAR         default_wndname[] = "main";
+    LPSTR               wndname = default_wndname;
+    WINHELP_DLL*        dll;
+
+    Globals.hInstance = hInstance;
+
+    if (LoadLibrary("riched20.dll") == NULL)
+        return MessageBox(0, MAKEINTRESOURCE(STID_NO_RICHEDIT),
+                          MAKEINTRESOURCE(STID_WHERROR), MB_OK);
+
+    /* Get options */
+    while (*cmdline && (*cmdline == ' ' || *cmdline == '-'))
+    {
+        CHAR   option;
+        LPCSTR topic_id;
+        if (*cmdline++ == ' ') continue;
+
+        option = *cmdline;
+        if (option) cmdline++;
+        while (*cmdline && *cmdline == ' ') cmdline++;
+        switch (option)
+       {
+       case 'i':
+       case 'I':
+            topic_id = cmdline;
+            while (*cmdline && *cmdline != ' ') cmdline++;
+            if (*cmdline) *cmdline++ = '\0';
+            lHash = HLPFILE_Hash(topic_id);
+            break;
+
+       case '3':
+       case '4':
+            Globals.wVersion = option - '0';
+            break;
+
+        case 'x':
+            show = SW_HIDE;
+            Globals.isBook = FALSE;
+            break;
+
+        default:
+            WINE_FIXME("Unsupported cmd line: %s\n", cmdline);
+            break;
+       }
+    }
+
+    /* Create primary window */
+    if (!WINHELP_RegisterWinClasses())
+    {
+        WINE_FIXME("Couldn't register classes\n");
+        return 0;
+    }
+
+    if (*cmdline)
+    {
+        char*   ptr;
+        if ((*cmdline == '"') && (ptr = strchr(cmdline+1, '"')))
+        {
+            cmdline++;
+            *ptr = '\0';
+        }
+        if ((ptr = strchr(cmdline, '>')))
+        {
+            *ptr = '\0';
+            wndname = ptr + 1;
+        }
+        hlpfile = WINHELP_LookupHelpFile(cmdline);
+        if (!hlpfile) return 0;
+    }
+    else hlpfile = NULL;
+    WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, lHash,
+                           WINHELP_GetWindowInfo(hlpfile, wndname), show);
+
+    /* Message loop */
+    while ((Globals.win_list || Globals.active_popup) && GetMessage(&msg, 0, 0, 0))
+    {
+        TranslateMessage(&msg);
+        DispatchMessage(&msg);
+    }
+    for (dll = Globals.dlls; dll; dll = dll->next)
+    {
+        if (dll->class & DC_INITTERM) dll->handler(DW_TERM, 0, 0);
+    }
+    return 0;
+}