[PATCH v9 0/1] MR11400: winhlp32: MACRO_PopupContext for bug #56516
https://bugs.winehq.org/show_bug.cgi?id=56516#c1 -- v9: winhlp32: MACRO_PopupContext for bug #56516 https://gitlab.winehq.org/wine/wine/-/merge_requests/11400
From: Stian Low <wineryyyyy@gmail.com> --- programs/winhlp32/macro.c | 24 +++++++++++++++++++++++- programs/winhlp32/winhelp.c | 24 ++++++++++++++---------- programs/winhlp32/winhelp.h | 1 + 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/programs/winhlp32/macro.c b/programs/winhlp32/macro.c index 36bda654afd..2a39464fd1e 100644 --- a/programs/winhlp32/macro.c +++ b/programs/winhlp32/macro.c @@ -671,7 +671,29 @@ static void CALLBACK MACRO_NoShow(void) void CALLBACK MACRO_PopupContext(LPCSTR str, LONG u) { - WINE_FIXME("(%s, %lu)\n", debugstr_a(str), u); + HLPFILE_WINDOWINFO* wi; + HLPFILE *hlpfile; + POINT origin; + + WINE_TRACE("(%s, %lu)\n", debugstr_a(str), u); + + if (!(hlpfile = WINHELP_LookupHelpFile(str))) + { + WINE_ERR("Failed to load .hlp file.\n"); + return; + } + + if (!GetCursorPos(&origin)) + WINE_FIXME("GetCursorPos failed so popup context help may appear misplaced.\n"); + + if (!MACRO_CurrentWindow()->page) + { + WINHELP_WNDPAGE wpage; + MACRO_CurrentWindow()->page = HLPFILE_PageByMap(hlpfile, u, &wpage.relative); + } + + wi = WINHELP_GetPopupWindowInfo(hlpfile, MACRO_CurrentWindow(), MAKELPARAM(origin.x, origin.y)); + WINHELP_OpenHelpWindow(HLPFILE_PageByMap, hlpfile, u, wi, SW_NORMAL); } static void CALLBACK MACRO_PopupHash(LPCSTR str, LONG u) diff --git a/programs/winhlp32/winhelp.c b/programs/winhlp32/winhelp.c index 1c112f08aaf..eb19dfc0c59 100644 --- a/programs/winhlp32/winhelp.c +++ b/programs/winhlp32/winhelp.c @@ -293,7 +293,7 @@ HLPFILE_WINDOWINFO* WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name) * * */ -static HLPFILE_WINDOWINFO* WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile, +HLPFILE_WINDOWINFO* WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile, WINHELP_WINDOW* parent, LPARAM mouse) { static HLPFILE_WINDOWINFO wi; @@ -304,12 +304,13 @@ static HLPFILE_WINDOWINFO* WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile, /* 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 borders are taken into account while computing */ + wi.size.cx = (parent_rect.right - parent_rect.left) / 5; + wi.size.cy = (parent_rect.bottom - parent_rect.top) / 5; wi.origin.x = (short)LOWORD(mouse); wi.origin.y = (short)HIWORD(mouse); ClientToScreen(parent->hMainWnd, &wi.origin); + wi.origin.y = (short)HIWORD(mouse) + 20; 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); @@ -800,6 +801,7 @@ BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE* wpage, int nCmdShow, BOOL remembe if (!bReUsed) { + RECT rect = { 0, 0, 0, 0 }; win->hMainWnd = CreateWindowExA((bPopup) ? WS_EX_TOOLWINDOW : 0, MAIN_WIN_CLASS_NAME, WINHELP_GetCaption(wpage), bPrimary ? WS_OVERLAPPEDWINDOW : wpage->wininfo->win_style, @@ -812,10 +814,17 @@ BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE* wpage, int nCmdShow, BOOL remembe /* Create button box and text Window */ CreateWindowA(BUTTON_BOX_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_BUTTON, Globals.hInstance, NULL); + else + rect = (RECT) { + wpage->wininfo->origin.x, + wpage->wininfo->origin.y, + wpage->wininfo->size.cx, + wpage->wininfo->size.cy, + }; hTextWnd = CreateWindowA(RICHEDIT_CLASS20A, 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); + rect.left, rect.top, rect.right, rect.bottom, win->hMainWnd, (HMENU)CTL_ID_TEXT, Globals.hInstance, NULL); SendMessageW(hTextWnd, EM_SETEVENTMASK, 0, SendMessageW(hTextWnd, EM_GETEVENTMASK, 0, 0) | ENM_MOUSEEVENTS); win->origRicheditWndProc = (WNDPROC)SetWindowLongPtrA(hTextWnd, GWLP_WNDPROC, @@ -848,16 +857,11 @@ BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE* wpage, int nCmdShow, BOOL remembe if (bPopup) { - DWORD mask = SendMessageW(hTextWnd, EM_GETEVENTMASK, 0, 0); - - win->font_scale = Globals.active_win->font_scale; + win->font_scale = 2; WINHELP_SetupText(hTextWnd, win, wpage->relative); /* we need the window to be shown for richedit to compute the size */ ShowWindow(win->hMainWnd, nCmdShow); - SendMessageW(hTextWnd, EM_SETEVENTMASK, 0, mask | ENM_REQUESTRESIZE); - SendMessageW(hTextWnd, EM_REQUESTRESIZE, 0, 0); - SendMessageW(hTextWnd, EM_SETEVENTMASK, 0, mask); } else { diff --git a/programs/winhlp32/winhelp.h b/programs/winhlp32/winhelp.h index 519dec215a9..6d2f0ebc01f 100644 --- a/programs/winhlp32/winhelp.h +++ b/programs/winhlp32/winhelp.h @@ -170,6 +170,7 @@ BOOL WINHELP_CreateIndexWindow(BOOL); void WINHELP_DeleteBackSet(WINHELP_WINDOW*); HLPFILE* WINHELP_LookupHelpFile(LPCSTR lpszFile); HLPFILE_WINDOWINFO* WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name); +HLPFILE_WINDOWINFO* WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile, WINHELP_WINDOW* parent, LPARAM mouse); void WINHELP_LayoutMainWindow(WINHELP_WINDOW* win); WINHELP_WINDOW* WINHELP_GrabWindow(WINHELP_WINDOW*); BOOL WINHELP_ReleaseWindow(WINHELP_WINDOW*); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11400
eric pouech (@epo) commented about programs/winhlp32/macro.c:
+ + WINE_TRACE("(%s, %lu)\n", debugstr_a(str), u); + + if (!(hlpfile = WINHELP_LookupHelpFile(str))) + { + WINE_ERR("Failed to load .hlp file.\n"); + return; + } + + if (!GetCursorPos(&origin)) + WINE_FIXME("GetCursorPos failed so popup context help may appear misplaced.\n"); + + if (!MACRO_CurrentWindow()->page) + { + WINHELP_WNDPAGE wpage; + MACRO_CurrentWindow()->page = HLPFILE_PageByMap(hlpfile, u, &wpage.relative); this doesn't make sense as you're setting the page of current window, while the target window is (potentially) not created yet and it's the one supposed to get that page
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/11400#note_146026
eric pouech (@epo) commented about programs/winhlp32/winhelp.c:
/* Create button box and text Window */ CreateWindowA(BUTTON_BOX_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_BUTTON, Globals.hInstance, NULL); + else + rect = (RECT) { + wpage->wininfo->origin.x, + wpage->wininfo->origin.y, + wpage->wininfo->size.cx, + wpage->wininfo->size.cy, + };
this will break the support of most of the popup using an oversized window does this work better: ``` diff --git a/dlls/riched20/wrap.c b/dlls/riched20/wrap.c index a4d638aec3d..d5807475c00 100644 --- a/dlls/riched20/wrap.c +++ b/dlls/riched20/wrap.c @@ -1150,8 +1150,8 @@ ME_SendRequestResize(ME_TextEditor *editor, BOOL force) info.nmhdr.idFrom = 0; info.nmhdr.code = EN_REQUESTRESIZE; info.rc = rc; - info.rc.right = editor->nTotalWidth; - info.rc.bottom = editor->nTotalLength; + info.rc.right = rc.left + editor->nTotalWidth; + info.rc.bottom = rc.right + editor->nTotalLength; editor->nEventMask &= ~ENM_REQUESTRESIZE; ITextHost_TxNotify(editor->texthost, info.nmhdr.code, &info); ``` (not sure it's the right fix, still need to investigate why the rc.top is at 1) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11400#note_146027
eric pouech (@epo) commented about programs/winhlp32/winhelp.c:
if (bPopup) { - DWORD mask = SendMessageW(hTextWnd, EM_GETEVENTMASK, 0, 0); - - win->font_scale = Globals.active_win->font_scale; + win->font_scale = 2;
font_scale is a user driven parameter, so it doesn't make sense to have a fixed value here -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11400#note_146028
can you share one of the WinHelp trace call so that I can look at invocation? TIA -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11400#note_146030
On Sat Jul 18 19:03:41 2026 +0000, eric pouech wrote:
can you share one of the WinHelp trace call so that I can look at invocation? TIA with vanilla wine 11.13
0124:trace:winhelp:WINHELP_GrabWindow Grab 00116500\#0++ 0124:trace:winhelp:WINHELP_GrabWindow Grab 00116500\#1++ 0124:trace:winhelp:WINHELP_ReleaseWindow Release 00116500\#2-- 0124:trace:winhelp:WINHELP_HandleCommand Got[83]: cmd=8 data=00031603 fn="Z:\\home\\walrus\\.wine\\drive_c\\GOG Games\\HoMM 3 Complete\\h3maped.HLP" 0124:fixme:winhelp:MACRO_PopupContext ("Z:\\home\\walrus\\.wine\\drive_c\\GOG Games\\HoMM 3 Complete\\h3maped.HLP", 202243) with this patch copypasted from gitlab because [i don't know how to git](https://xkcd.com/1597/) [some kinda wall of text](/uploads/c78fece982d10d3f512f7fc0443cdd75/e.log) winhlp's command line (per ps -ef) walrus 296775 1 0 20:56 ? 00:00:00 winhlp32.exe -x pid does not change if I open multiple help popups -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11400#note_146031
On Sat Jul 18 19:03:41 2026 +0000, Alfred Agrell wrote:
with vanilla wine 11.13 0124:trace:winhelp:WINHELP_GrabWindow Grab 00116500\#0++ 0124:trace:winhelp:WINHELP_GrabWindow Grab 00116500\#1++ 0124:trace:winhelp:WINHELP_ReleaseWindow Release 00116500\#2-- 0124:trace:winhelp:WINHELP_HandleCommand Got[83]: cmd=8 data=00031603 fn="Z:\\home\\walrus\\.wine\\drive_c\\GOG Games\\HoMM 3 Complete\\h3maped.HLP" 0124:fixme:winhelp:MACRO_PopupContext ("Z:\\home\\walrus\\.wine\\drive_c\\GOG Games\\HoMM 3 Complete\\h3maped.HLP", 202243) with this patch copypasted from gitlab because [i don't know how to git](https://xkcd.com/1597/) [some kinda wall of text](/uploads/c78fece982d10d3f512f7fc0443cdd75/e.log) winhlp's command line (per ps -ef) walrus 296775 1 0 20:56 ? 00:00:00 winhlp32.exe -x pid does not change if I open multiple help popups [wine-mr-11400-winhelp-trace.log](/uploads/fd4184571321cc608ef81933a03d2f49/wine-mr-11400-winhelp-trace.log)
WINEDEBUG=+winhelp for just right click popup for Pikeman shown in screenshots. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11400#note_146041
On Sun Jul 19 05:55:29 2026 +0000, Stian Low wrote:
[wine-mr-11400-winhelp-trace.log](/uploads/fd4184571321cc608ef81933a03d2f49/wine-mr-11400-winhelp-trace.log) WINEDEBUG=+winhelp for just right click popup for Pikeman shown in screenshots. Backtrace for MACRO_PopupContext to figure out where `WINHELP_WINDOW page` nullptr may need to be fixed:
``` Backtracing for thread 01a0 in process 019c (C:\windows\syswow64\winhlp32.exe): Backtrace: =>0 0x0000000040c401 MACRO_PopupContext+0x1(str="Z:\home\any\wine_stianlow_wow64_new_pfx_heros_mightmagit_iii_complete\drive_c\GOG Games\HoMM 3 Complete\h3maped.HLP", u=0x31600) [/home/any/tmp/wine_stianlow_wow6 4_old_build_32/../wine_stianlow/programs/winhlp32/macro.c:673] in winhlp32 (0x000000006af718) 1 0x0000000041089f WINHELP_HandleCommand+0x5df(hSrcWnd=<internal error>, lParam=<internal error>) [/home/any/tmp/wine_stianlow_wow64_old_build_32/../wine_stianlow/programs/winhlp32/winhelp.c:402] in winhlp32 ( 0x000000006af718) 2 0x0000000041089f WINHELP_MainWndProc+0x88b(hWnd=<internal error>, msg=<internal error>, wParam=<internal error>, lParam=<internal error>) [/home/any/tmp/wine_stianlow_wow64_old_build_32/../wine_stianlow/prog rams/winhlp32/winhelp.c:1433] in winhlp32 (0x000000006af718) 3 0x0000000041089f WINHELP_MainWndProc+0x8bf(hWnd=0000000000010134, msg=0x4a, wParam=0x1009c, lParam=0x6afd74) [/home/any/tmp/wine_stianlow_wow64_old_build_32/../wine_stianlow/programs/winhlp32/winhelp.c:1530] in winhlp32 (0x000000006af718) 4 0x0000007993a528 in user32 (+0xa528) (0x000000006af748) 5 0x0000007998fcd9 call_window_proc+0x39(hwnd=0000000000010134, msg=0x4a, wp=0x1009c, lp=0x6afd74, result=00000000006AFC5C, arg=000000000040FFE0) [/home/any/tmp/wine_stianlow_wow64_old_build_32/../wine_stianlo w/dlls/user32/winproc.c:107] in user32 (0x000000006af788) 6 0x0000007998a038 WINPROC_CallProcWtoA+0x548(callback=000000007998FCA0, hwnd=<register EDI not accessible in this frame>, msg=<register EBX not accessible in this frame>, wParam=0x1009c, lParam=0x6afd74, resu lt=00000000006AFC5C, arg=000000000040FFE0) [/home/any/tmp/wine_stianlow_wow64_old_build_32/../wine_stianlow/dlls/user32/winproc.c:695] in user32 (0x000000006afc30) 7 0x00000079995cf1 dispatch_win_proc_params+0x71(params=00000000006AFD44) [/home/any/tmp/wine_stianlow_wow64_old_build_32/../wine_stianlow/dlls/user32/winproc.c:728] in user32 (0x000000006afc6c) 8 0x00000079981e66 User32CallWinProc+0x86(args=00000000006AFD44, size=0xc0) [/home/any/tmp/wine_stianlow_wow64_old_build_32/../wine_stianlow/dlls/user32/winproc.c:826] in user32 (0x000000006afc98) 9 0x0000007bcf72d9 dispatch_user_callback+0x99(args=00000000006AFD44, len=0xc0, id=0x4) [/home/any/tmp/wine_stianlow_wow64_old_build_32/../wine_stianlow/dlls/ntdll/exception.c:296] in ntdll (0x000000006afd10) 10 0x0000007bcc1aff KiUserCallbackDispatcher+0x1f(id=0x4, args=00000000006AFD44, len=0xc0) [/home/any/tmp/wine_stianlow_wow64_old_build_32/../wine_stianlow/dlls/ntdll/signal_i386.c:205] in ntdll (0x000000006af d24) 11 0x000000798e1248 in win32u (+0x11248) (0000000000000000) 12 0x00000000000004 (0000000000000000) 024c:fixme:dbghelp:elf_search_auxv can't find symbol in module 024c:fixme:dbghelp:elf_search_auxv can't find symbol in module 0x0000007bcbe289 ntdll+0xe289: retl ``` -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11400#note_146043
thx for the various traces: - basically user32.WinHelp is called with filename=H3MAPED.HLP and command = popup-context - which starts 'winhlp32.exe -x' (-x: invisible) - then sends the command to winhlp32.exe which opens the popup (hence without a page being displayed) it seems to me that it would be better to have something like (giving priority to displayed hlpfile popup color): ``` diff --git a/programs/winhlp32/winhelp.c b/programs/winhlp32/winhelp.c index 1c112f08aaf..fde3837dcf6 100644 --- a/programs/winhlp32/winhelp.c +++ b/programs/winhlp32/winhelp.c @@ -293,8 +293,8 @@ HLPFILE_WINDOWINFO* WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name) * * */ -static HLPFILE_WINDOWINFO* WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile, - WINHELP_WINDOW* parent, LPARAM mouse) +HLPFILE_WINDOWINFO* WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile, + WINHELP_WINDOW* parent, LPARAM mouse) { static HLPFILE_WINDOWINFO wi; @@ -316,7 +316,9 @@ static HLPFILE_WINDOWINFO* WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile, wi.style = SW_SHOW; wi.win_style = WS_POPUP | WS_BORDER; - if (parent->page->file->has_popup_color) + if (hlpfile->has_popup_color) + wi.sr_color = hlpfile->popup_color; + else if (parent->page && parent->page->file->has_popup_color) wi.sr_color = parent->page->file->popup_color; else wi.sr_color = parent->info->sr_color; ``` (side note: there's still a couple of other places in winhlp32 code that assumes that there's always a page) now looking into richedit -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11400#note_146055
participants (4)
-
Alfred Agrell (@Alcaro) -
eric pouech (@epo) -
Stian Low -
Stian Low (@stianlow)