wget2
wget2 copied to clipboard
fix(windows): restore console modes before exit
On Windows, the console modes are altered by wget2 (via SetupConsoleHandlein libwget), to enable virtual terminal sequences.
However it's not restored before exit; this causes problems such as key binds not working properly, even after the wget2 process exits (#311).
This PR addresses the problem by saving the console modes at the start of main, and then restoring them before main returns.
I'm not well versed in C let alone this code base, so the PR might not be up to the project's standards. Do let me know if I should change anything.
Fixes: #311
What if a CTRL_C_EVENT or CTRL_BREAK_EVENT gets raised?
AFAICS, there's no call to SetConsoleCtrlHandler() to trap and restore the terminal-state.
Actually cancelling a download in that fashion still seems to trigger the code that restores console modes, maybe it's not necessary to call SetConsoleCtrlHandler?
I cannot determine why this works when ctrl-c/break gets issued. It still ends up restoring console modes.
It still ends up restoring console modes.
Are you sure? Neither SetConsoleCtrlHandler() nor SetConsoleMode() are called in Wget2.
And there's a difference in how conhost.exe handles Ctrl-C vs. Ctrl-Break:
https://learn.microsoft.com/en-us/windows/console/ctrl-c-and-ctrl-break-signals
Ah, you're right: ctrl-break still leaves the console modified; however ctrl-c does not.
So the solution is SetConsoleCtrlHandler, however since it takes a handler function, how should I go about not duplicating the cleanup code at the end of main? Also it looks like the previous console modes have to become globals now, which I'm not a fan of.
As a side note I'm still not sure why the patch works for ctrl-c.
Also SetConsoleMode is actually called indirectly:
initinsrc/options.c- calls
log_initinsrc/log.c - calls
wget_console_initinlibwget/console.c - calls
SetupConsoleHandlealso inlibwget/console.c - which finally calls
SetConsoleMode
That's how i diagnosed the issue at first: commenting out SetConsoleMode calls inside SetupConsoleHandle, which worked but is of course undesirable.
Are there any suggestions on how to proceed?
I think you should add your code to the global constructor and the global destructor.
The destructor should be called at program exit. Please test it and give a feedback.
Sorry for the delay; I got hit with the seasonal flu.
I've moved the cleanup to libwget/init.c as you suggested:
- The initial console modes are obtained and stored in
INITIALIZER(). - A handler is registered via
SetConsoleCtrlHandler(), also inINITIALIZER(). - The handler simply calls
exit(2)if the signal isctrl+corctrl+break; it ignores other signals, letting any other handler, if any, handle them. This triggers whatever's registered withatexit(), including our destructorglobal_exit(). - The console modes are restored in
global_exit().
Let me know if I should change anything.
Oh also I've tested this and it works for both ctrl+c and ctrl+break.
Thanks for your contribution, manually pushed (changed the commit message).