- ctrl-c enabling flag is now inherited
- fixed console-related fields in RTL_USER_PROCESS_PARAMETERS - various clean-up in kernel32.SetConsoleCtrlHandler - only send a console event once to a process and not to all the process' threads
This commit is contained in:
parent
fe442b21f7
commit
440ad8ccf2
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* Win32 kernel functions
|
||||
* Win32 console functions
|
||||
*
|
||||
* Copyright 1995 Martin von Loewis and Cameron Heide
|
||||
* Copyright 1997 Karl Garrison
|
||||
* Copyright 1998 John Richardson
|
||||
* Copyright 1998 Marcus Meissner
|
||||
* Copyright 2001,2002 Eric Pouech
|
||||
* Copyright 2001,2002,2004 Eric Pouech
|
||||
* Copyright 2001 Alexandre Julliard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
|
@ -52,6 +52,7 @@
|
|||
#include "excpt.h"
|
||||
#include "console_private.h"
|
||||
#include "kernel_private.h"
|
||||
#include "thread.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(console);
|
||||
|
||||
|
@ -1419,20 +1420,14 @@ static BOOL WINAPI CONSOLE_DefaultHandler(DWORD dwCtrlType)
|
|||
* RETURNS
|
||||
* Success: TRUE
|
||||
* Failure: FALSE
|
||||
*
|
||||
* CHANGED
|
||||
* James Sutherland (JamesSutherland@gmx.de)
|
||||
* Added global variables console_ignore_ctrl_c and handlers[]
|
||||
* Does not yet do any error checking, or set LastError if failed.
|
||||
* This doesn't yet matter, since these handlers are not yet called...!
|
||||
*/
|
||||
|
||||
struct ConsoleHandler {
|
||||
struct ConsoleHandler
|
||||
{
|
||||
PHANDLER_ROUTINE handler;
|
||||
struct ConsoleHandler* next;
|
||||
};
|
||||
|
||||
static unsigned int CONSOLE_IgnoreCtrlC = 0; /* FIXME: this should be inherited somehow */
|
||||
static struct ConsoleHandler CONSOLE_DefaultConsoleHandler = {CONSOLE_DefaultHandler, NULL};
|
||||
static struct ConsoleHandler* CONSOLE_Handlers = &CONSOLE_DefaultConsoleHandler;
|
||||
|
||||
|
@ -1447,15 +1442,23 @@ static CRITICAL_SECTION CONSOLE_CritSect = { &critsect_debug, -1, 0, 0, 0, 0 };
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/******************************************************************
|
||||
* SetConsoleCtrlHandler (KERNEL32.@)
|
||||
*/
|
||||
BOOL WINAPI SetConsoleCtrlHandler(PHANDLER_ROUTINE func, BOOL add)
|
||||
{
|
||||
BOOL ret = TRUE;
|
||||
|
||||
FIXME("(%p,%i) - no error checking or testing yet\n", func, add);
|
||||
TRACE("(%p,%i)\n", func, add);
|
||||
|
||||
if (!func)
|
||||
{
|
||||
CONSOLE_IgnoreCtrlC = add;
|
||||
RtlEnterCriticalSection(&CONSOLE_CritSect);
|
||||
if (add)
|
||||
NtCurrentTeb()->Peb->ProcessParameters->ConsoleFlags |= 1;
|
||||
else
|
||||
NtCurrentTeb()->Peb->ProcessParameters->ConsoleFlags &= ~1;
|
||||
RtlLeaveCriticalSection(&CONSOLE_CritSect);
|
||||
}
|
||||
else if (add)
|
||||
{
|
||||
|
@ -1472,7 +1475,7 @@ BOOL WINAPI SetConsoleCtrlHandler(PHANDLER_ROUTINE func, BOOL add)
|
|||
{
|
||||
struct ConsoleHandler** ch;
|
||||
RtlEnterCriticalSection(&CONSOLE_CritSect);
|
||||
for (ch = &CONSOLE_Handlers; *ch; *ch = (*ch)->next)
|
||||
for (ch = &CONSOLE_Handlers; *ch; ch = &(*ch)->next)
|
||||
{
|
||||
if ((*ch)->handler == func) break;
|
||||
}
|
||||
|
@ -1484,18 +1487,19 @@ BOOL WINAPI SetConsoleCtrlHandler(PHANDLER_ROUTINE func, BOOL add)
|
|||
if (rch == &CONSOLE_DefaultConsoleHandler)
|
||||
{
|
||||
ERR("Who's trying to remove default handler???\n");
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
ret = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
rch = *ch;
|
||||
*ch = (*ch)->next;
|
||||
*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);
|
||||
|
@ -1509,18 +1513,42 @@ static WINE_EXCEPTION_FILTER(CONSOLE_CtrlEventHandler)
|
|||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
static DWORD WINAPI CONSOLE_HandleCtrlCEntry(void* pmt)
|
||||
/******************************************************************
|
||||
* CONSOLE_SendEventThread
|
||||
*
|
||||
* Internal helper to pass an event to the list on installed handlers
|
||||
*/
|
||||
static DWORD WINAPI CONSOLE_SendEventThread(void* pmt)
|
||||
{
|
||||
DWORD event = (DWORD)pmt;
|
||||
struct ConsoleHandler* ch;
|
||||
|
||||
RtlEnterCriticalSection(&CONSOLE_CritSect);
|
||||
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((DWORD)pmt)) break;
|
||||
if (ch->handler(event)) break;
|
||||
}
|
||||
RtlLeaveCriticalSection(&CONSOLE_CritSect);
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
|
@ -1533,24 +1561,21 @@ int CONSOLE_HandleCtrlC(unsigned sig)
|
|||
/* FIXME: better test whether a console is attached to this process ??? */
|
||||
extern unsigned CONSOLE_GetNumHistoryEntries(void);
|
||||
if (CONSOLE_GetNumHistoryEntries() == (unsigned)-1) return 0;
|
||||
if (CONSOLE_IgnoreCtrlC) return 1;
|
||||
|
||||
/* try to pass the exception to the debugger
|
||||
* if it continues, there's nothing more to do
|
||||
* otherwise, we need to send the ctrl-event to the handlers
|
||||
*/
|
||||
__TRY
|
||||
/* check if we have to ignore ctrl-C events */
|
||||
if (!(NtCurrentTeb()->Peb->ProcessParameters->ConsoleFlags & 1))
|
||||
{
|
||||
RaiseException( DBG_CONTROL_C, 0, 0, NULL );
|
||||
}
|
||||
__EXCEPT(CONSOLE_CtrlEventHandler)
|
||||
{
|
||||
/* Create a separate thread to signal all the events. This would allow to
|
||||
* synchronize between setting the handlers and actually calling them
|
||||
/* Create a separate thread to signal all the events.
|
||||
* This is needed because:
|
||||
* - this function can be called in an Unix signal handler (hence on an
|
||||
* different stack than the thread that's running). This breaks the
|
||||
* Win32 exception mechanisms (where the thread's stack is checked).
|
||||
* - since the current thread, while processing the signal, can hold the
|
||||
* console critical section, we need another execution environment where
|
||||
* we can wait on this critical section
|
||||
*/
|
||||
CreateThread(NULL, 0, CONSOLE_HandleCtrlCEntry, (void*)CTRL_C_EVENT, 0, NULL);
|
||||
CreateThread(NULL, 0, CONSOLE_SendEventThread, (void*)CTRL_C_EVENT, 0, NULL);
|
||||
}
|
||||
__ENDTRY;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1586,6 +1611,10 @@ BOOL WINAPI GenerateConsoleCtrlEvent(DWORD dwCtrlEvent,
|
|||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
/* FIXME: shall this function be synchronous, ie only return when all events
|
||||
* have been handled by all processes in the given group ?
|
||||
* As of today, we don't wait...
|
||||
*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Unit tests for console API
|
||||
*
|
||||
* Copyright (c) 2003 Eric Pouech
|
||||
* Copyright (c) 2003,2004 Eric Pouech
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -360,7 +360,6 @@ static void testWrite(HANDLE hCon, COORD sbSize)
|
|||
testWriteWrappedProcessed(hCon, sbSize);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void testScroll(HANDLE hCon, COORD sbSize)
|
||||
{
|
||||
SMALL_RECT scroll, clip;
|
||||
|
@ -477,6 +476,7 @@ static void testScroll(HANDLE hCon, COORD sbSize)
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* clipping, src & dst rect do overlap */
|
||||
resetContent(hCon, sbSize, TRUE);
|
||||
|
||||
|
@ -511,8 +511,46 @@ static void testScroll(HANDLE hCon, COORD sbSize)
|
|||
else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int mch_count;
|
||||
/* we need the event as Wine console event generation isn't synchronous
|
||||
* (ie GenerateConsoleCtrlEvent returns before all ctrl-handlers in all
|
||||
* processes have been called).
|
||||
*/
|
||||
static HANDLE mch_event;
|
||||
static BOOL WINAPI mch(DWORD event)
|
||||
{
|
||||
mch_count++;
|
||||
SetEvent(mch_event);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void testCtrlHandler(void)
|
||||
{
|
||||
ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %lu\n", GetLastError());
|
||||
ok(SetConsoleCtrlHandler(mch, TRUE), "Couldn't set handler\n");
|
||||
/* wine requires the event for the test, as we cannot insure, so far, that event
|
||||
* are processed synchronously in GenerateConsoleCtrlEvent()
|
||||
*/
|
||||
mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
mch_count = 0;
|
||||
ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
|
||||
todo_wine ok(mch_count == 1, "Event isn't synchronous\n");
|
||||
ok(WaitForSingleObject(mch_event, 3000) == WAIT_OBJECT_0, "event sending didn't work\n");
|
||||
CloseHandle(mch_event);
|
||||
ok(SetConsoleCtrlHandler(NULL, TRUE), "Couldn't turn off ctrl-c handling\n");
|
||||
mch_event = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
mch_count = 0;
|
||||
ok(GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0), "Couldn't send ctrl-c event\n");
|
||||
ok(WaitForSingleObject(mch_event, 3000) == WAIT_TIMEOUT && mch_count == 0, "Event shouldn't have been sent\n");
|
||||
CloseHandle(mch_event);
|
||||
ok(SetConsoleCtrlHandler(mch, FALSE), "Couldn't remove handler\n");
|
||||
ok(!SetConsoleCtrlHandler(mch, FALSE), "Shouldn't succeed\n");
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Bad error %lu\n", GetLastError());
|
||||
}
|
||||
|
||||
START_TEST(console)
|
||||
{
|
||||
|
@ -553,9 +591,9 @@ START_TEST(console)
|
|||
/* testBottomScroll(); */
|
||||
/* will test all the scrolling operations */
|
||||
/* this one is disabled for now, Wine's result are way too bad */
|
||||
/* testScroll(hCon, sbi.dwSize); */
|
||||
testScroll(hConOut, sbi.dwSize);
|
||||
/* will test sb creation / modification... */
|
||||
/* testScreenBuffer() */
|
||||
|
||||
/* still to be done: events generation, access rights & access on objects */
|
||||
testCtrlHandler();
|
||||
/* still to be done: access rights & access on objects */
|
||||
}
|
||||
|
|
|
@ -453,7 +453,7 @@ NTSTATUS WINAPI RtlCreateProcessParameters( RTL_USER_PROCESS_PARAMETERS **result
|
|||
params->AllocationSize = total_size;
|
||||
params->Size = size;
|
||||
params->Flags = PROCESS_PARAMS_FLAG_NORMALIZED;
|
||||
params->ProcessGroup = cur_params->ProcessGroup;
|
||||
params->ConsoleFlags = cur_params->ConsoleFlags;
|
||||
params->Environment = Environment;
|
||||
/* all other fields are zero */
|
||||
|
||||
|
|
|
@ -101,8 +101,8 @@ typedef struct _RTL_USER_PROCESS_PARAMETERS
|
|||
ULONG Size;
|
||||
ULONG Flags;
|
||||
ULONG DebugFlags;
|
||||
HANDLE hConsole;
|
||||
ULONG ProcessGroup;
|
||||
HANDLE ConsoleHandle;
|
||||
ULONG ConsoleFlags;
|
||||
HANDLE hStdInput;
|
||||
HANDLE hStdOutput;
|
||||
HANDLE hStdError;
|
||||
|
|
|
@ -386,7 +386,8 @@ static struct console_input* console_input_get( obj_handle_t handle, unsigned ac
|
|||
return console;
|
||||
}
|
||||
|
||||
struct console_signal_info {
|
||||
struct console_signal_info
|
||||
{
|
||||
struct console_input *console;
|
||||
process_id_t group;
|
||||
int signal;
|
||||
|
@ -399,13 +400,11 @@ static int propagate_console_signal_cb(struct process *process, void *user)
|
|||
if (process->console == csi->console && process->running_threads &&
|
||||
(!csi->group || process->group_id == csi->group))
|
||||
{
|
||||
struct thread *thread = process->thread_list;
|
||||
|
||||
while (thread)
|
||||
/* find a suitable thread to signal */
|
||||
struct thread *thread;
|
||||
for (thread = process->thread_list; thread; thread = thread->proc_next)
|
||||
{
|
||||
struct thread *next = thread->proc_next;
|
||||
send_thread_signal( thread, csi->signal );
|
||||
thread = next;
|
||||
if (send_thread_signal( thread, csi->signal )) break;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
|
|
|
@ -324,8 +324,8 @@ static void dump_varargs_startup_info( size_t size )
|
|||
fprintf( stderr, "Size=%lx,", params.Size );
|
||||
fprintf( stderr, "Flags=%lx,", params.Flags );
|
||||
fprintf( stderr, "DebugFlags=%lx,", params.DebugFlags );
|
||||
fprintf( stderr, "Console=%p,", params.hConsole );
|
||||
fprintf( stderr, "ProcessGroup=%lx,", params.ProcessGroup );
|
||||
fprintf( stderr, "ConsoleHandle=%p,", params.ConsoleHandle );
|
||||
fprintf( stderr, "ConsoleFlags=%lx,", params.ConsoleFlags );
|
||||
fprintf( stderr, "hStdInput=%p,", params.hStdInput );
|
||||
fprintf( stderr, "hStdOutput=%p,", params.hStdOutput );
|
||||
fprintf( stderr, "hStdError=%p,", params.hStdError );
|
||||
|
|
Loading…
Reference in New Issue