From aa8b0c6a360d10d2ea87ba14d7020133b041d91a Mon Sep 17 00:00:00 2001 From: Jason Hood Date: Fri, 17 Nov 2017 21:53:58 +1000 Subject: [PATCH] Use the system default sound for the bell Windows 7 uses Beep for the bell, which means if you accidentally view a binary file, the console freezes until all the bells have finished. Windows 10 uses PlaySound, which avoids the freeze, but prevents the sound being played at all if the program immediately exits (in its own host). This uses PlaySound in its own thread, ignoring additional bells whilst one is currently playing and waiting for it to finish before terminating. --- ANSI.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++-- ansicon.c | 2 +- makefile.vc | 2 +- readme.txt | 7 ++++--- 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/ANSI.c b/ANSI.c index 4233e4c..d5afdb6 100644 --- a/ANSI.c +++ b/ANSI.c @@ -152,19 +152,25 @@ remove wcstok, avoiding potential interference with the host; similarly, use a private heap instead of malloc. - v1.80, 26 October to 7 November, 2017: + v1.80, 26 October to 17 November, 2017: fix unloading; revert back to (re)storing buffer cursor position; increase cache to five handles; hook CreateFile & CreateConsoleScreenBuffer to enable readable handles; fix cursor report with duplicated digits (e.g. "11" was just "1"); preserve escape that isn't part of a sequence; - fix escape followed by CRM in control mode. + fix escape followed by CRM in control mode; + use the system default sound for the bell. */ #include "ansicon.h" #include "version.h" #include +#include + +#ifndef SND_SENTRY +#define SND_SENTRY 0x80000 +#endif #define is_digit(c) ('0' <= (c) && (c) <= '9') @@ -175,6 +181,7 @@ WORD orgattr; // original attributes DWORD orgmode; // original mode CONSOLE_CURSOR_INFO orgcci; // original cursor state HANDLE hHeap; // local memory heap +HANDLE hBell; #define CACHE 5 struct @@ -1161,6 +1168,17 @@ void InterpretEscSeq( void ) } } +DWORD WINAPI BellThread( LPVOID param ) +{ + // XP doesn't support SND_SENTRY, so if it fails, try without. + if (!PlaySound( (LPTSTR)SND_ALIAS_SYSTEMDEFAULT, NULL, + SND_SENTRY | SND_ALIAS_ID | SND_SYNC )) + PlaySound( (LPTSTR)SND_ALIAS_SYSTEMDEFAULT, NULL, SND_ALIAS_ID | SND_SYNC ); + CloseHandle( hBell ); + hBell = NULL; + return 0; +} + //----------------------------------------------------------------------------- // ParseAndPrintString(hDev, lpBuffer, nNumberOfBytesToWrite) // Parses the string lpBuffer, interprets the escapes sequences and prints the @@ -1198,6 +1216,11 @@ ParseAndPrintString( HANDLE hDev, get_state(); state = (pState->crm) ? 7 : 2; } + else if (c == BEL) + { + if (hBell == NULL) + hBell = CreateThread( NULL, 4096, BellThread, NULL, 0, NULL ); + } else if (c == SO) shifted = TRUE; else if (c == SI) shifted = FALSE; else PushBuffer( (WCHAR)c ); @@ -2305,6 +2328,36 @@ WINAPI My_lwrite( HFILE hFile, LPCSTR lpBuffer, UINT uBytes ) } +VOID +WINAPI MyExitProcess( UINT uExitCode ) +{ + if (hBell != NULL) + WaitForSingleObject( hBell, INFINITE ); + ExitProcess( uExitCode ); +} + + +DWORD WINAPI FreeLibraryThread( LPVOID param ) +{ + FreeLibraryAndExitThread( hDllInstance, 0 ); + return 0; +} + +BOOL +WINAPI MyFreeLibrary( HMODULE hModule ) +{ + if (hModule == hDllInstance) + { + if (hBell != NULL) + WaitForSingleObject( hBell, INFINITE ); + CloseHandle( CreateThread( NULL, 4096, FreeLibraryThread, NULL, 0, NULL ) ); + return TRUE; + } + + return FreeLibrary( hModule ); +} + + //----------------------------------------------------------------------------- // MyCreate... // Add GENERIC_READ access to enable retrieving console info. @@ -2456,6 +2509,8 @@ HookFn Hooks[] = { { APIConsole, "WriteConsoleW", (PROC)MyWriteConsoleW, NULL, NULL, NULL }, { APIFile, "WriteFile", (PROC)MyWriteFile, NULL, NULL, NULL }, { APIKernel, "_lwrite", (PROC)My_lwrite, NULL, NULL, NULL }, + { APIProcessThreads, "ExitProcess", (PROC)MyExitProcess, NULL, NULL, NULL }, + { APILibraryLoader, "FreeLibrary", (PROC)MyFreeLibrary, NULL, NULL, NULL }, { APIFile, "CreateFileA", (PROC)MyCreateFileA, NULL, NULL, NULL }, { APIFile, "CreateFileW", (PROC)MyCreateFileW, NULL, NULL, NULL }, { APIKernel, "CreateConsoleScreenBuffer", (PROC)MyCreateConsoleScreenBuffer, NULL, NULL, NULL }, diff --git a/ansicon.c b/ansicon.c index 45a3ebf..aa5fe90 100644 --- a/ansicon.c +++ b/ansicon.c @@ -90,7 +90,7 @@ write newline with _putws, not putwchar (fixes redirecting to CON). */ -#define PDATE L"7 November, 2017" +#define PDATE L"17 November, 2017" #include "ansicon.h" #include "version.h" diff --git a/makefile.vc b/makefile.vc index 51c5388..dbd3f40 100644 --- a/makefile.vc +++ b/makefile.vc @@ -60,7 +60,7 @@ SHARE = /MD MT = mt.exe CFLAGS = /nologo /W3 /O2 $(SHARE) /D_CRT_SECURE_NO_WARNINGS -LIBS = advapi32.lib user32.lib $(LIBS64) +LIBS = advapi32.lib user32.lib winmm.lib $(LIBS64) # Identify ansicon.exe using "ANSI" as a version number. LINK = /link /version:20033.18771 diff --git a/readme.txt b/readme.txt index 6e880a3..2f62ddd 100644 --- a/readme.txt +++ b/readme.txt @@ -295,7 +295,7 @@ Version History Legend: + added, - bug-fixed, * changed. - 1.80 - 7 November, 2017: + 1.80 - 17 November, 2017: - fix unloading; - fix -e et al when redirecting to CON; - hook CreateFile and CreateConsoleScreenBuffer to force read/write access @@ -303,7 +303,8 @@ Version History - fix cursor report with duplicated digits (e.g. "11" was only writing "1"); - fix escape followed by CRM in control mode; * go back to saving the buffer cursor position; - * preserve escape that isn't part of a sequence. + * preserve escape that isn't part of a sequence; + + use the system default sound for the bell. 1.72 - 24 December, 2015: - handle STD_OUTPUT_HANDLE & STD_ERROR_HANDLE in WriteFile; @@ -532,4 +533,4 @@ Distribution ============================= -Jason Hood, 7 November, 2017. +Jason Hood, 17 November, 2017.