- 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 1995 Martin von Loewis and Cameron Heide
|
||||||
* Copyright 1997 Karl Garrison
|
* Copyright 1997 Karl Garrison
|
||||||
* Copyright 1998 John Richardson
|
* Copyright 1998 John Richardson
|
||||||
* Copyright 1998 Marcus Meissner
|
* Copyright 1998 Marcus Meissner
|
||||||
* Copyright 2001,2002 Eric Pouech
|
* Copyright 2001,2002,2004 Eric Pouech
|
||||||
* Copyright 2001 Alexandre Julliard
|
* Copyright 2001 Alexandre Julliard
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
@ -52,6 +52,7 @@
|
|||||||
#include "excpt.h"
|
#include "excpt.h"
|
||||||
#include "console_private.h"
|
#include "console_private.h"
|
||||||
#include "kernel_private.h"
|
#include "kernel_private.h"
|
||||||
|
#include "thread.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(console);
|
WINE_DEFAULT_DEBUG_CHANNEL(console);
|
||||||
|
|
||||||
@ -1419,20 +1420,14 @@ static BOOL WINAPI CONSOLE_DefaultHandler(DWORD dwCtrlType)
|
|||||||
* RETURNS
|
* RETURNS
|
||||||
* Success: TRUE
|
* Success: TRUE
|
||||||
* Failure: FALSE
|
* 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;
|
PHANDLER_ROUTINE handler;
|
||||||
struct ConsoleHandler* next;
|
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_DefaultConsoleHandler = {CONSOLE_DefaultHandler, NULL};
|
||||||
static struct ConsoleHandler* CONSOLE_Handlers = &CONSOLE_DefaultConsoleHandler;
|
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 WINAPI SetConsoleCtrlHandler(PHANDLER_ROUTINE func, BOOL add)
|
||||||
{
|
{
|
||||||
BOOL ret = TRUE;
|
BOOL ret = TRUE;
|
||||||
|
|
||||||
FIXME("(%p,%i) - no error checking or testing yet\n", func, add);
|
TRACE("(%p,%i)\n", func, add);
|
||||||
|
|
||||||
if (!func)
|
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)
|
else if (add)
|
||||||
{
|
{
|
||||||
@ -1472,7 +1475,7 @@ BOOL WINAPI SetConsoleCtrlHandler(PHANDLER_ROUTINE func, BOOL add)
|
|||||||
{
|
{
|
||||||
struct ConsoleHandler** ch;
|
struct ConsoleHandler** ch;
|
||||||
RtlEnterCriticalSection(&CONSOLE_CritSect);
|
RtlEnterCriticalSection(&CONSOLE_CritSect);
|
||||||
for (ch = &CONSOLE_Handlers; *ch; *ch = (*ch)->next)
|
for (ch = &CONSOLE_Handlers; *ch; ch = &(*ch)->next)
|
||||||
{
|
{
|
||||||
if ((*ch)->handler == func) break;
|
if ((*ch)->handler == func) break;
|
||||||
}
|
}
|
||||||
@ -1484,18 +1487,19 @@ BOOL WINAPI SetConsoleCtrlHandler(PHANDLER_ROUTINE func, BOOL add)
|
|||||||
if (rch == &CONSOLE_DefaultConsoleHandler)
|
if (rch == &CONSOLE_DefaultConsoleHandler)
|
||||||
{
|
{
|
||||||
ERR("Who's trying to remove default handler???\n");
|
ERR("Who's trying to remove default handler???\n");
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rch = *ch;
|
*ch = rch->next;
|
||||||
*ch = (*ch)->next;
|
|
||||||
HeapFree(GetProcessHeap(), 0, rch);
|
HeapFree(GetProcessHeap(), 0, rch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WARN("Attempt to remove non-installed CtrlHandler %p\n", func);
|
WARN("Attempt to remove non-installed CtrlHandler %p\n", func);
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
}
|
}
|
||||||
RtlLeaveCriticalSection(&CONSOLE_CritSect);
|
RtlLeaveCriticalSection(&CONSOLE_CritSect);
|
||||||
@ -1509,18 +1513,42 @@ static WINE_EXCEPTION_FILTER(CONSOLE_CtrlEventHandler)
|
|||||||
return EXCEPTION_EXECUTE_HANDLER;
|
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;
|
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 */
|
/* the debugger didn't continue... so, pass to ctrl handlers */
|
||||||
|
}
|
||||||
|
RtlEnterCriticalSection(&CONSOLE_CritSect);
|
||||||
for (ch = CONSOLE_Handlers; ch; ch = ch->next)
|
for (ch = CONSOLE_Handlers; ch; ch = ch->next)
|
||||||
{
|
{
|
||||||
if (ch->handler((DWORD)pmt)) break;
|
if (ch->handler(event)) break;
|
||||||
}
|
}
|
||||||
RtlLeaveCriticalSection(&CONSOLE_CritSect);
|
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 ??? */
|
/* FIXME: better test whether a console is attached to this process ??? */
|
||||||
extern unsigned CONSOLE_GetNumHistoryEntries(void);
|
extern unsigned CONSOLE_GetNumHistoryEntries(void);
|
||||||
if (CONSOLE_GetNumHistoryEntries() == (unsigned)-1) return 0;
|
if (CONSOLE_GetNumHistoryEntries() == (unsigned)-1) return 0;
|
||||||
if (CONSOLE_IgnoreCtrlC) return 1;
|
|
||||||
|
|
||||||
/* try to pass the exception to the debugger
|
/* check if we have to ignore ctrl-C events */
|
||||||
* if it continues, there's nothing more to do
|
if (!(NtCurrentTeb()->Peb->ProcessParameters->ConsoleFlags & 1))
|
||||||
* otherwise, we need to send the ctrl-event to the handlers
|
|
||||||
*/
|
|
||||||
__TRY
|
|
||||||
{
|
{
|
||||||
RaiseException( DBG_CONTROL_C, 0, 0, NULL );
|
/* Create a separate thread to signal all the events.
|
||||||
}
|
* This is needed because:
|
||||||
__EXCEPT(CONSOLE_CtrlEventHandler)
|
* - this function can be called in an Unix signal handler (hence on an
|
||||||
{
|
* different stack than the thread that's running). This breaks the
|
||||||
/* Create a separate thread to signal all the events. This would allow to
|
* Win32 exception mechanisms (where the thread's stack is checked).
|
||||||
* synchronize between setting the handlers and actually calling them
|
* - 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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1586,6 +1611,10 @@ BOOL WINAPI GenerateConsoleCtrlEvent(DWORD dwCtrlEvent,
|
|||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Unit tests for console API
|
* 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
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* 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);
|
testWriteWrappedProcessed(hCon, sbSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void testScroll(HANDLE hCon, COORD sbSize)
|
static void testScroll(HANDLE hCon, COORD sbSize)
|
||||||
{
|
{
|
||||||
SMALL_RECT scroll, clip;
|
SMALL_RECT scroll, clip;
|
||||||
@ -477,6 +476,7 @@ static void testScroll(HANDLE hCon, COORD sbSize)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
/* clipping, src & dst rect do overlap */
|
/* clipping, src & dst rect do overlap */
|
||||||
resetContent(hCon, sbSize, TRUE);
|
resetContent(hCon, sbSize, TRUE);
|
||||||
|
|
||||||
@ -511,8 +511,46 @@ static void testScroll(HANDLE hCon, COORD sbSize)
|
|||||||
else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
|
else okCHAR(hCon, c, CONTENT(c), DEFAULT_ATTRIB);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#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)
|
START_TEST(console)
|
||||||
{
|
{
|
||||||
@ -553,9 +591,9 @@ START_TEST(console)
|
|||||||
/* testBottomScroll(); */
|
/* testBottomScroll(); */
|
||||||
/* will test all the scrolling operations */
|
/* will test all the scrolling operations */
|
||||||
/* this one is disabled for now, Wine's result are way too bad */
|
/* 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... */
|
/* will test sb creation / modification... */
|
||||||
/* testScreenBuffer() */
|
/* testScreenBuffer() */
|
||||||
|
testCtrlHandler();
|
||||||
/* still to be done: events generation, access rights & access on objects */
|
/* 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->AllocationSize = total_size;
|
||||||
params->Size = size;
|
params->Size = size;
|
||||||
params->Flags = PROCESS_PARAMS_FLAG_NORMALIZED;
|
params->Flags = PROCESS_PARAMS_FLAG_NORMALIZED;
|
||||||
params->ProcessGroup = cur_params->ProcessGroup;
|
params->ConsoleFlags = cur_params->ConsoleFlags;
|
||||||
params->Environment = Environment;
|
params->Environment = Environment;
|
||||||
/* all other fields are zero */
|
/* all other fields are zero */
|
||||||
|
|
||||||
|
@ -101,8 +101,8 @@ typedef struct _RTL_USER_PROCESS_PARAMETERS
|
|||||||
ULONG Size;
|
ULONG Size;
|
||||||
ULONG Flags;
|
ULONG Flags;
|
||||||
ULONG DebugFlags;
|
ULONG DebugFlags;
|
||||||
HANDLE hConsole;
|
HANDLE ConsoleHandle;
|
||||||
ULONG ProcessGroup;
|
ULONG ConsoleFlags;
|
||||||
HANDLE hStdInput;
|
HANDLE hStdInput;
|
||||||
HANDLE hStdOutput;
|
HANDLE hStdOutput;
|
||||||
HANDLE hStdError;
|
HANDLE hStdError;
|
||||||
|
@ -386,7 +386,8 @@ static struct console_input* console_input_get( obj_handle_t handle, unsigned ac
|
|||||||
return console;
|
return console;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct console_signal_info {
|
struct console_signal_info
|
||||||
|
{
|
||||||
struct console_input *console;
|
struct console_input *console;
|
||||||
process_id_t group;
|
process_id_t group;
|
||||||
int signal;
|
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 &&
|
if (process->console == csi->console && process->running_threads &&
|
||||||
(!csi->group || process->group_id == csi->group))
|
(!csi->group || process->group_id == csi->group))
|
||||||
{
|
{
|
||||||
struct thread *thread = process->thread_list;
|
/* find a suitable thread to signal */
|
||||||
|
struct thread *thread;
|
||||||
while (thread)
|
for (thread = process->thread_list; thread; thread = thread->proc_next)
|
||||||
{
|
{
|
||||||
struct thread *next = thread->proc_next;
|
if (send_thread_signal( thread, csi->signal )) break;
|
||||||
send_thread_signal( thread, csi->signal );
|
|
||||||
thread = next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -324,8 +324,8 @@ static void dump_varargs_startup_info( size_t size )
|
|||||||
fprintf( stderr, "Size=%lx,", params.Size );
|
fprintf( stderr, "Size=%lx,", params.Size );
|
||||||
fprintf( stderr, "Flags=%lx,", params.Flags );
|
fprintf( stderr, "Flags=%lx,", params.Flags );
|
||||||
fprintf( stderr, "DebugFlags=%lx,", params.DebugFlags );
|
fprintf( stderr, "DebugFlags=%lx,", params.DebugFlags );
|
||||||
fprintf( stderr, "Console=%p,", params.hConsole );
|
fprintf( stderr, "ConsoleHandle=%p,", params.ConsoleHandle );
|
||||||
fprintf( stderr, "ProcessGroup=%lx,", params.ProcessGroup );
|
fprintf( stderr, "ConsoleFlags=%lx,", params.ConsoleFlags );
|
||||||
fprintf( stderr, "hStdInput=%p,", params.hStdInput );
|
fprintf( stderr, "hStdInput=%p,", params.hStdInput );
|
||||||
fprintf( stderr, "hStdOutput=%p,", params.hStdOutput );
|
fprintf( stderr, "hStdOutput=%p,", params.hStdOutput );
|
||||||
fprintf( stderr, "hStdError=%p,", params.hStdError );
|
fprintf( stderr, "hStdError=%p,", params.hStdError );
|
||||||
|
Loading…
x
Reference in New Issue
Block a user