diff --git a/dlls/kernel32/console.c b/dlls/kernel32/console.c index 980ebef8eddd78c1e40fe120f0be23a44f95e97a..4e1c15cb7188c7bd5972888af9668ff02ec75d7a 100644 --- a/dlls/kernel32/console.c +++ b/dlls/kernel32/console.c @@ -889,151 +889,6 @@ BOOL WINAPI GetNumberOfConsoleMouseButtons(LPDWORD nrofbuttons) return TRUE; } -/****************************************************************** - * CONSOLE_DefaultHandler - * - * Final control event handler - */ -static BOOL WINAPI CONSOLE_DefaultHandler(DWORD dwCtrlType) -{ - FIXME("Terminating process %x on event %x\n", GetCurrentProcessId(), dwCtrlType); - ExitProcess(0); - /* should never go here */ - return TRUE; -} - -/****************************************************************************** - * SetConsoleCtrlHandler [KERNEL32.@] Adds function to calling process list - * - * PARAMS - * func [I] Address of handler function - * add [I] Handler to add or remove - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ - -struct ConsoleHandler -{ - PHANDLER_ROUTINE handler; - struct ConsoleHandler* next; -}; - -static struct ConsoleHandler CONSOLE_DefaultConsoleHandler = {CONSOLE_DefaultHandler, NULL}; -static struct ConsoleHandler* CONSOLE_Handlers = &CONSOLE_DefaultConsoleHandler; - -/*****************************************************************************/ - -/****************************************************************** - * SetConsoleCtrlHandler (KERNEL32.@) - */ -BOOL WINAPI SetConsoleCtrlHandler(PHANDLER_ROUTINE func, BOOL add) -{ - BOOL ret = TRUE; - - TRACE("(%p,%i)\n", func, add); - - if (!func) - { - RtlEnterCriticalSection(&CONSOLE_CritSect); - if (add) - NtCurrentTeb()->Peb->ProcessParameters->ConsoleFlags |= 1; - else - NtCurrentTeb()->Peb->ProcessParameters->ConsoleFlags &= ~1; - RtlLeaveCriticalSection(&CONSOLE_CritSect); - } - else if (add) - { - struct ConsoleHandler* ch = HeapAlloc(GetProcessHeap(), 0, sizeof(struct ConsoleHandler)); - - if (!ch) return FALSE; - ch->handler = func; - RtlEnterCriticalSection(&CONSOLE_CritSect); - ch->next = CONSOLE_Handlers; - CONSOLE_Handlers = ch; - RtlLeaveCriticalSection(&CONSOLE_CritSect); - } - else - { - struct ConsoleHandler** ch; - RtlEnterCriticalSection(&CONSOLE_CritSect); - for (ch = &CONSOLE_Handlers; *ch; ch = &(*ch)->next) - { - if ((*ch)->handler == func) break; - } - if (*ch) - { - struct ConsoleHandler* rch = *ch; - - /* sanity check */ - if (rch == &CONSOLE_DefaultConsoleHandler) - { - ERR("Who's trying to remove default handler???\n"); - SetLastError(ERROR_INVALID_PARAMETER); - ret = FALSE; - } - else - { - *ch = rch->next; - HeapFree(GetProcessHeap(), 0, rch); - } - } - else - { - WARN("Attempt to remove non-installed CtrlHandler %p\n", func); - SetLastError(ERROR_INVALID_PARAMETER); - ret = FALSE; - } - RtlLeaveCriticalSection(&CONSOLE_CritSect); - } - return ret; -} - -static LONG WINAPI CONSOLE_CtrlEventHandler(EXCEPTION_POINTERS *eptr) -{ - TRACE("(%x)\n", eptr->ExceptionRecord->ExceptionCode); - return EXCEPTION_EXECUTE_HANDLER; -} - -/****************************************************************** - * CONSOLE_SendEventThread - * - * Internal helper to pass an event to the list on installed handlers - */ -static DWORD WINAPI CONSOLE_SendEventThread(void* pmt) -{ - DWORD_PTR event = (DWORD_PTR)pmt; - struct ConsoleHandler* ch; - - if (event == CTRL_C_EVENT) - { - BOOL caught_by_dbg = TRUE; - /* First, try to pass the ctrl-C event to the debugger (if any) - * If it continues, there's nothing more to do - * Otherwise, we need to send the ctrl-C event to the handlers - */ - __TRY - { - RaiseException( DBG_CONTROL_C, 0, 0, NULL ); - } - __EXCEPT(CONSOLE_CtrlEventHandler) - { - caught_by_dbg = FALSE; - } - __ENDTRY; - if (caught_by_dbg) return 0; - /* the debugger didn't continue... so, pass to ctrl handlers */ - } - RtlEnterCriticalSection(&CONSOLE_CritSect); - for (ch = CONSOLE_Handlers; ch; ch = ch->next) - { - if (ch->handler(event)) break; - } - RtlLeaveCriticalSection(&CONSOLE_CritSect); - return 1; -} - /****************************************************************** * CONSOLE_HandleCtrlC * @@ -1041,6 +896,7 @@ static DWORD WINAPI CONSOLE_SendEventThread(void* pmt) */ int CONSOLE_HandleCtrlC(unsigned sig) { + extern DWORD WINAPI CtrlRoutine( void *arg ); HANDLE thread; /* FIXME: better test whether a console is attached to this process ??? */ @@ -1059,7 +915,7 @@ int CONSOLE_HandleCtrlC(unsigned sig) * console critical section, we need another execution environment where * we can wait on this critical section */ - thread = CreateThread(NULL, 0, CONSOLE_SendEventThread, (void*)CTRL_C_EVENT, 0, NULL); + thread = CreateThread(NULL, 0, CtrlRoutine, (void*)CTRL_C_EVENT, 0, NULL); if (thread == NULL) return 0; diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 8645d48d7737bd1d0d3dff247d540929d23c7aea..17322bcd904df4b5b432bd638716dc183d504ba3 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -345,7 +345,7 @@ @ stdcall CreateWaitableTimerExA(ptr str long long) @ stdcall -import CreateWaitableTimerExW(ptr wstr long long) @ stdcall -import CreateWaitableTimerW(ptr long wstr) -# @ stub CtrlRoutine +@ stdcall CtrlRoutine(ptr) kernelbase.CtrlRoutine @ stdcall -import DeactivateActCtx(long long) @ stdcall -import DebugActiveProcess(long) @ stdcall -import DebugActiveProcessStop(long) @@ -1349,7 +1349,7 @@ @ stdcall -import SetConsoleCP(long) # @ stub SetConsoleHistoryInfo @ stub SetConsoleCommandHistoryMode -@ stdcall SetConsoleCtrlHandler(ptr long) +@ stdcall -import SetConsoleCtrlHandler(ptr long) @ stub SetConsoleCursor @ stdcall -import SetConsoleCursorInfo(long ptr) @ stub SetConsoleCursorMode diff --git a/dlls/kernelbase/console.c b/dlls/kernelbase/console.c index 7dabc91e67c714d858259cadd9bd4c17f1585071..3171933b1221c246d864349ae400e542228cf559 100644 --- a/dlls/kernelbase/console.c +++ b/dlls/kernelbase/console.c @@ -55,6 +55,21 @@ static CRITICAL_SECTION console_section = { &critsect_debug, -1, 0, 0, 0, 0 }; static WCHAR input_exe[MAX_PATH + 1]; +struct ctrl_handler +{ + PHANDLER_ROUTINE func; + struct ctrl_handler *next; +}; + +static BOOL WINAPI default_ctrl_handler( DWORD type ) +{ + FIXME( "Terminating process %x on event %x\n", GetCurrentProcessId(), type ); + RtlExitUserProcess( 0 ); + return TRUE; +} + +static struct ctrl_handler default_handler = { default_ctrl_handler, NULL }; +static struct ctrl_handler *ctrl_handlers = &default_handler; /* map a kernel32 console handle onto a real wineserver handle */ static inline obj_handle_t console_handle_unmap( HANDLE h ) @@ -239,6 +254,45 @@ HANDLE WINAPI DECLSPEC_HOTPATCH CreateConsoleScreenBuffer( DWORD access, DWORD s } +/****************************************************************************** + * CtrlRoutine (kernelbase.@) + */ +DWORD WINAPI CtrlRoutine( void *arg ) +{ + DWORD_PTR event = (DWORD_PTR)arg; + struct ctrl_handler *handler; + + if (event == CTRL_C_EVENT) + { + BOOL caught_by_dbg = TRUE; + /* First, try to pass the ctrl-C event to the debugger (if any) + * If it continues, there's nothing more to do + * Otherwise, we need to send the ctrl-C event to the handlers + */ + __TRY + { + RaiseException( DBG_CONTROL_C, 0, 0, NULL ); + } + __EXCEPT_ALL + { + caught_by_dbg = FALSE; + } + __ENDTRY + if (caught_by_dbg) return 0; + } + + if (NtCurrentTeb()->Peb->ProcessParameters->ConsoleFlags & 1) return 0; + + RtlEnterCriticalSection( &console_section ); + for (handler = ctrl_handlers; handler; handler = handler->next) + { + if (handler->func( event )) break; + } + RtlLeaveCriticalSection( &console_section ); + return 1; +} + + /****************************************************************************** * FillConsoleOutputAttribute (kernelbase.@) */ @@ -985,6 +1039,57 @@ BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleCP( UINT cp ) } +/****************************************************************************** + * SetConsoleCtrlHandler (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleCtrlHandler( PHANDLER_ROUTINE func, BOOL add ) +{ + struct ctrl_handler *handler; + BOOL ret = FALSE; + + TRACE( "(%p,%d)\n", func, add ); + + RtlEnterCriticalSection( &console_section ); + + if (!func) + { + if (add) NtCurrentTeb()->Peb->ProcessParameters->ConsoleFlags |= 1; + else NtCurrentTeb()->Peb->ProcessParameters->ConsoleFlags &= ~1; + ret = TRUE; + } + else if (add) + { + if ((handler = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*handler) ))) + { + handler->func = func; + handler->next = ctrl_handlers; + ctrl_handlers = handler; + ret = TRUE; + } + } + else + { + struct ctrl_handler **p_handler; + + for (p_handler = &ctrl_handlers; *p_handler; p_handler = &(*p_handler)->next) + { + if ((*p_handler)->func == func) break; + } + if (*p_handler && *p_handler != &default_handler) + { + handler = *p_handler; + *p_handler = handler->next; + RtlFreeHeap( GetProcessHeap(), 0, handler ); + ret = TRUE; + } + else SetLastError( ERROR_INVALID_PARAMETER ); + } + + RtlLeaveCriticalSection( &console_section ); + return ret; +} + + /****************************************************************************** * SetConsoleCursorInfo (kernelbase.@) */ diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index 10de1821d1c9e424f659a92c9428e7c2b219599d..5e177a4932703b25ef5e3a279cd3a2eb0d52811c 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -234,7 +234,7 @@ @ stdcall CreateWaitableTimerExW(ptr wstr long long) @ stdcall CreateWaitableTimerW(ptr long wstr) @ stdcall CreateWellKnownSid(long ptr ptr ptr) -# @ stub CtrlRoutine +@ stdcall CtrlRoutine(ptr) # @ stub CveEventWrite @ stdcall DeactivateActCtx(long long) @ stdcall DebugActiveProcess(long) @@ -1404,7 +1404,7 @@ @ stdcall SetComputerNameW(wstr) @ stdcall SetConsoleActiveScreenBuffer(long) @ stdcall SetConsoleCP(long) -@ stdcall SetConsoleCtrlHandler(ptr long) kernel32.SetConsoleCtrlHandler +@ stdcall SetConsoleCtrlHandler(ptr long) @ stdcall SetConsoleCursorInfo(long ptr) @ stdcall SetConsoleCursorPosition(long long) @ stdcall SetConsoleInputExeNameA(str)