Implementation for console control events (includes process groups
support).
This commit is contained in:
parent
5e765fb36a
commit
93bfa0d6b1
|
@ -963,17 +963,21 @@ static HANDLER_DEF(fpe_handler)
|
||||||
*/
|
*/
|
||||||
static HANDLER_DEF(int_handler)
|
static HANDLER_DEF(int_handler)
|
||||||
{
|
{
|
||||||
EXCEPTION_RECORD rec;
|
extern int CONSOLE_HandleCtrlC(void);
|
||||||
CONTEXT context;
|
if (!CONSOLE_HandleCtrlC())
|
||||||
|
{
|
||||||
|
EXCEPTION_RECORD rec;
|
||||||
|
CONTEXT context;
|
||||||
|
|
||||||
save_context( &context, HANDLER_CONTEXT );
|
save_context( &context, HANDLER_CONTEXT );
|
||||||
rec.ExceptionCode = CONTROL_C_EXIT;
|
rec.ExceptionCode = CONTROL_C_EXIT;
|
||||||
rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
||||||
rec.ExceptionRecord = NULL;
|
rec.ExceptionRecord = NULL;
|
||||||
rec.ExceptionAddress = (LPVOID)context.Eip;
|
rec.ExceptionAddress = (LPVOID)context.Eip;
|
||||||
rec.NumberParameters = 0;
|
rec.NumberParameters = 0;
|
||||||
EXC_RtlRaiseException( &rec, &context );
|
EXC_RtlRaiseException( &rec, &context );
|
||||||
restore_context( &context, HANDLER_CONTEXT );
|
restore_context( &context, HANDLER_CONTEXT );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -310,17 +310,21 @@ static void fpe_handler( int signal, siginfo_t *info, ucontext_t *ucontext )
|
||||||
*/
|
*/
|
||||||
static void int_handler( int signal, siginfo_t *info, ucontext_t *ucontext )
|
static void int_handler( int signal, siginfo_t *info, ucontext_t *ucontext )
|
||||||
{
|
{
|
||||||
EXCEPTION_RECORD rec;
|
extern int CONSOLE_HandleCtrlC(void);
|
||||||
CONTEXT context;
|
if (!CONSOLE_HandleCtrlC())
|
||||||
|
{
|
||||||
|
EXCEPTION_RECORD rec;
|
||||||
|
CONTEXT context;
|
||||||
|
|
||||||
save_context( &context, ucontext );
|
save_context( &context, ucontext );
|
||||||
rec.ExceptionCode = CONTROL_C_EXIT;
|
rec.ExceptionCode = CONTROL_C_EXIT;
|
||||||
rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
|
||||||
rec.ExceptionRecord = NULL;
|
rec.ExceptionRecord = NULL;
|
||||||
rec.ExceptionAddress = (LPVOID)context.pc;
|
rec.ExceptionAddress = (LPVOID)context.pc;
|
||||||
rec.NumberParameters = 0;
|
rec.NumberParameters = 0;
|
||||||
EXC_RtlRaiseException( &rec, &context );
|
EXC_RtlRaiseException( &rec, &context );
|
||||||
restore_context( &context, ucontext );
|
restore_context( &context, ucontext );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1366,6 +1366,7 @@ struct read_console_output_reply
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct move_console_output_request
|
struct move_console_output_request
|
||||||
{
|
{
|
||||||
struct request_header __header;
|
struct request_header __header;
|
||||||
|
@ -1384,6 +1385,19 @@ struct move_console_output_reply
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct send_console_signal_request
|
||||||
|
{
|
||||||
|
struct request_header __header;
|
||||||
|
int signal;
|
||||||
|
void* group_id;
|
||||||
|
};
|
||||||
|
struct send_console_signal_reply
|
||||||
|
{
|
||||||
|
struct reply_header __header;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct create_change_notification_request
|
struct create_change_notification_request
|
||||||
{
|
{
|
||||||
struct request_header __header;
|
struct request_header __header;
|
||||||
|
@ -2784,6 +2798,7 @@ enum request
|
||||||
REQ_fill_console_output,
|
REQ_fill_console_output,
|
||||||
REQ_read_console_output,
|
REQ_read_console_output,
|
||||||
REQ_move_console_output,
|
REQ_move_console_output,
|
||||||
|
REQ_send_console_signal,
|
||||||
REQ_create_change_notification,
|
REQ_create_change_notification,
|
||||||
REQ_create_mapping,
|
REQ_create_mapping,
|
||||||
REQ_open_mapping,
|
REQ_open_mapping,
|
||||||
|
@ -2946,6 +2961,7 @@ union generic_request
|
||||||
struct fill_console_output_request fill_console_output_request;
|
struct fill_console_output_request fill_console_output_request;
|
||||||
struct read_console_output_request read_console_output_request;
|
struct read_console_output_request read_console_output_request;
|
||||||
struct move_console_output_request move_console_output_request;
|
struct move_console_output_request move_console_output_request;
|
||||||
|
struct send_console_signal_request send_console_signal_request;
|
||||||
struct create_change_notification_request create_change_notification_request;
|
struct create_change_notification_request create_change_notification_request;
|
||||||
struct create_mapping_request create_mapping_request;
|
struct create_mapping_request create_mapping_request;
|
||||||
struct open_mapping_request open_mapping_request;
|
struct open_mapping_request open_mapping_request;
|
||||||
|
@ -3106,6 +3122,7 @@ union generic_reply
|
||||||
struct fill_console_output_reply fill_console_output_reply;
|
struct fill_console_output_reply fill_console_output_reply;
|
||||||
struct read_console_output_reply read_console_output_reply;
|
struct read_console_output_reply read_console_output_reply;
|
||||||
struct move_console_output_reply move_console_output_reply;
|
struct move_console_output_reply move_console_output_reply;
|
||||||
|
struct send_console_signal_reply send_console_signal_reply;
|
||||||
struct create_change_notification_reply create_change_notification_reply;
|
struct create_change_notification_reply create_change_notification_reply;
|
||||||
struct create_mapping_reply create_mapping_reply;
|
struct create_mapping_reply create_mapping_reply;
|
||||||
struct open_mapping_reply open_mapping_reply;
|
struct open_mapping_reply open_mapping_reply;
|
||||||
|
@ -3192,6 +3209,6 @@ union generic_reply
|
||||||
struct get_window_properties_reply get_window_properties_reply;
|
struct get_window_properties_reply get_window_properties_reply;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SERVER_PROTOCOL_VERSION 80
|
#define SERVER_PROTOCOL_VERSION 81
|
||||||
|
|
||||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
|
@ -385,6 +386,54 @@ static int console_input_signaled( struct object *obj, struct thread *thread )
|
||||||
return console->recnum ? 1 : 0;
|
return console->recnum ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct console_signal_info {
|
||||||
|
struct console_input *console;
|
||||||
|
struct process *group;
|
||||||
|
int signal;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int propagate_console_signal_cb(struct process *process, void *user)
|
||||||
|
{
|
||||||
|
struct console_signal_info* csi = (struct console_signal_info*)user;
|
||||||
|
|
||||||
|
if (process->console == csi->console && process->running_threads &&
|
||||||
|
(csi->group == NULL || process->group_id == csi->group))
|
||||||
|
{
|
||||||
|
struct thread *thread = process->thread_list;
|
||||||
|
|
||||||
|
while (thread)
|
||||||
|
{
|
||||||
|
struct thread *next = thread->proc_next;
|
||||||
|
kill( thread->unix_pid, csi->signal );
|
||||||
|
thread = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void propagate_console_signal( struct console_input *console,
|
||||||
|
int sig, void* group_id )
|
||||||
|
{
|
||||||
|
struct console_signal_info csi;
|
||||||
|
|
||||||
|
if (!console)
|
||||||
|
{
|
||||||
|
set_error( STATUS_INVALID_PARAMETER );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* FIXME: should support the other events (like CTRL_BREAK) */
|
||||||
|
if (sig != CTRL_C_EVENT)
|
||||||
|
{
|
||||||
|
set_error( STATUS_NOT_IMPLEMENTED );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
csi.console = console;
|
||||||
|
csi.signal = SIGINT;
|
||||||
|
csi.group = group_id;
|
||||||
|
|
||||||
|
enum_processes(propagate_console_signal_cb, &csi);
|
||||||
|
}
|
||||||
|
|
||||||
static int get_console_mode( obj_handle_t handle )
|
static int get_console_mode( obj_handle_t handle )
|
||||||
{
|
{
|
||||||
struct object *obj;
|
struct object *obj;
|
||||||
|
@ -443,8 +492,31 @@ static int write_console_input( struct console_input* console, int count,
|
||||||
}
|
}
|
||||||
console->records = new_rec;
|
console->records = new_rec;
|
||||||
memcpy( new_rec + console->recnum, records, count * sizeof(INPUT_RECORD) );
|
memcpy( new_rec + console->recnum, records, count * sizeof(INPUT_RECORD) );
|
||||||
console->recnum += count;
|
|
||||||
|
|
||||||
|
if (console->mode & ENABLE_PROCESSED_INPUT)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while (i < count)
|
||||||
|
{
|
||||||
|
if (records[i].EventType == KEY_EVENT &&
|
||||||
|
records[i].Event.KeyEvent.uChar.UnicodeChar == 'C' - 64 &&
|
||||||
|
!(records[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
|
||||||
|
{
|
||||||
|
if (i != count - 1)
|
||||||
|
memcpy( &console->records[console->recnum + i],
|
||||||
|
&console->records[console->recnum + i + 1],
|
||||||
|
(count - i - 1) * sizeof(INPUT_RECORD) );
|
||||||
|
count--;
|
||||||
|
if (records[i].Event.KeyEvent.bKeyDown)
|
||||||
|
{
|
||||||
|
/* send SIGINT to all processes attached to this console */
|
||||||
|
propagate_console_signal( console, CTRL_C_EVENT, NULL );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console->recnum += count;
|
||||||
/* wake up all waiters */
|
/* wake up all waiters */
|
||||||
wake_up( &console->obj, 0 );
|
wake_up( &console->obj, 0 );
|
||||||
return count;
|
return count;
|
||||||
|
@ -1385,3 +1457,18 @@ DECL_HANDLER(move_console_output)
|
||||||
scroll_console_output( req->handle, req->x_src, req->y_src, req->x_dst, req->y_dst,
|
scroll_console_output( req->handle, req->x_src, req->y_src, req->x_dst, req->y_dst,
|
||||||
req->w, req->h );
|
req->w, req->h );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* sends a signal to a console (process, group...) */
|
||||||
|
DECL_HANDLER(send_console_signal)
|
||||||
|
{
|
||||||
|
void* group;
|
||||||
|
|
||||||
|
group = req->group_id ? req->group_id : current->process->group_id;
|
||||||
|
|
||||||
|
if (!group)
|
||||||
|
set_error( STATUS_INVALID_PARAMETER);
|
||||||
|
else
|
||||||
|
propagate_console_signal( current->process->console, req->signal, group );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -218,6 +218,7 @@ struct thread *create_process( int fd )
|
||||||
process->exe.dbg_size = 0;
|
process->exe.dbg_size = 0;
|
||||||
process->exe.namelen = 0;
|
process->exe.namelen = 0;
|
||||||
process->exe.filename = NULL;
|
process->exe.filename = NULL;
|
||||||
|
process->group_id = NULL;
|
||||||
|
|
||||||
gettimeofday( &process->start_time, NULL );
|
gettimeofday( &process->start_time, NULL );
|
||||||
if ((process->next = first_process) != NULL) process->next->prev = process;
|
if ((process->next = first_process) != NULL) process->next->prev = process;
|
||||||
|
@ -285,6 +286,7 @@ static struct startup_info *init_process( int ppid, struct init_process_reply *r
|
||||||
/* set the process console */
|
/* set the process console */
|
||||||
if (!set_process_console( process, parent_thread, info, reply )) return NULL;
|
if (!set_process_console( process, parent_thread, info, reply )) return NULL;
|
||||||
|
|
||||||
|
process->group_id = process;
|
||||||
if (parent)
|
if (parent)
|
||||||
{
|
{
|
||||||
/* attach to the debugger if requested */
|
/* attach to the debugger if requested */
|
||||||
|
@ -292,6 +294,8 @@ static struct startup_info *init_process( int ppid, struct init_process_reply *r
|
||||||
set_process_debugger( process, parent_thread );
|
set_process_debugger( process, parent_thread );
|
||||||
else if (parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS))
|
else if (parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS))
|
||||||
set_process_debugger( process, parent->debugger );
|
set_process_debugger( process, parent->debugger );
|
||||||
|
if (!(process->create_flags & CREATE_NEW_PROCESS_GROUP))
|
||||||
|
process->group_id = parent->group_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* thread will be actually suspended in init_done */
|
/* thread will be actually suspended in init_done */
|
||||||
|
@ -614,6 +618,16 @@ void detach_debugged_processes( struct thread *debugger )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void enum_processes( int (*cb)(struct process*, void*), void *user )
|
||||||
|
{
|
||||||
|
struct process *process;
|
||||||
|
for (process = first_process; process; process = process->next)
|
||||||
|
{
|
||||||
|
if ((cb)(process, user)) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* get all information about a process */
|
/* get all information about a process */
|
||||||
static void get_process_info( struct process *process, struct get_process_info_reply *reply )
|
static void get_process_info( struct process *process, struct get_process_info_reply *reply )
|
||||||
{
|
{
|
||||||
|
|
|
@ -72,6 +72,7 @@ struct process
|
||||||
struct process_dll exe; /* main exe file */
|
struct process_dll exe; /* main exe file */
|
||||||
void *ldt_copy; /* pointer to LDT copy in client addr space */
|
void *ldt_copy; /* pointer to LDT copy in client addr space */
|
||||||
void *ldt_flags; /* pointer to LDT flags in client addr space */
|
void *ldt_flags; /* pointer to LDT flags in client addr space */
|
||||||
|
void *group_id; /* group ID of the process */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct process_snapshot
|
struct process_snapshot
|
||||||
|
@ -110,6 +111,7 @@ extern void kill_debugged_processes( struct thread *debugger, int exit_code );
|
||||||
extern void detach_debugged_processes( struct thread *debugger );
|
extern void detach_debugged_processes( struct thread *debugger );
|
||||||
extern struct process_snapshot *process_snap( int *count );
|
extern struct process_snapshot *process_snap( int *count );
|
||||||
extern struct module_snapshot *module_snap( struct process *process, int *count );
|
extern struct module_snapshot *module_snap( struct process *process, int *count );
|
||||||
|
extern void enum_processes( int (*cb)(struct process*, void*), void *user);
|
||||||
|
|
||||||
inline static void *get_process_id( struct process *process ) { return process; }
|
inline static void *get_process_id( struct process *process ) { return process; }
|
||||||
inline static int is_process_init_done( struct process *process )
|
inline static int is_process_init_done( struct process *process )
|
||||||
|
|
|
@ -1009,6 +1009,7 @@ enum char_info_mode
|
||||||
VARARG(data,bytes);
|
VARARG(data,bytes);
|
||||||
@END
|
@END
|
||||||
|
|
||||||
|
|
||||||
/* move a rect (of data) in screen buffer content */
|
/* move a rect (of data) in screen buffer content */
|
||||||
@REQ(move_console_output)
|
@REQ(move_console_output)
|
||||||
obj_handle_t handle; /* handle to the console output */
|
obj_handle_t handle; /* handle to the console output */
|
||||||
|
@ -1021,6 +1022,13 @@ enum char_info_mode
|
||||||
@END
|
@END
|
||||||
|
|
||||||
|
|
||||||
|
/* Sends a signal to a process group */
|
||||||
|
@REQ(send_console_signal)
|
||||||
|
int signal; /* the signal to send */
|
||||||
|
void* group_id; /* the group to send the signal to */
|
||||||
|
@END
|
||||||
|
|
||||||
|
|
||||||
/* Create a change notification */
|
/* Create a change notification */
|
||||||
@REQ(create_change_notification)
|
@REQ(create_change_notification)
|
||||||
int subtree; /* watch all the subtree */
|
int subtree; /* watch all the subtree */
|
||||||
|
|
|
@ -172,6 +172,7 @@ DECL_HANDLER(write_console_output);
|
||||||
DECL_HANDLER(fill_console_output);
|
DECL_HANDLER(fill_console_output);
|
||||||
DECL_HANDLER(read_console_output);
|
DECL_HANDLER(read_console_output);
|
||||||
DECL_HANDLER(move_console_output);
|
DECL_HANDLER(move_console_output);
|
||||||
|
DECL_HANDLER(send_console_signal);
|
||||||
DECL_HANDLER(create_change_notification);
|
DECL_HANDLER(create_change_notification);
|
||||||
DECL_HANDLER(create_mapping);
|
DECL_HANDLER(create_mapping);
|
||||||
DECL_HANDLER(open_mapping);
|
DECL_HANDLER(open_mapping);
|
||||||
|
@ -333,6 +334,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
|
||||||
(req_handler)req_fill_console_output,
|
(req_handler)req_fill_console_output,
|
||||||
(req_handler)req_read_console_output,
|
(req_handler)req_read_console_output,
|
||||||
(req_handler)req_move_console_output,
|
(req_handler)req_move_console_output,
|
||||||
|
(req_handler)req_send_console_signal,
|
||||||
(req_handler)req_create_change_notification,
|
(req_handler)req_create_change_notification,
|
||||||
(req_handler)req_create_mapping,
|
(req_handler)req_create_mapping,
|
||||||
(req_handler)req_open_mapping,
|
(req_handler)req_open_mapping,
|
||||||
|
|
|
@ -1191,6 +1191,12 @@ static void dump_move_console_output_request( const struct move_console_output_r
|
||||||
fprintf( stderr, " h=%d", req->h );
|
fprintf( stderr, " h=%d", req->h );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dump_send_console_signal_request( const struct send_console_signal_request *req )
|
||||||
|
{
|
||||||
|
fprintf( stderr, " signal=%d,", req->signal );
|
||||||
|
fprintf( stderr, " group_id=%p", req->group_id );
|
||||||
|
}
|
||||||
|
|
||||||
static void dump_create_change_notification_request( const struct create_change_notification_request *req )
|
static void dump_create_change_notification_request( const struct create_change_notification_request *req )
|
||||||
{
|
{
|
||||||
fprintf( stderr, " subtree=%d,", req->subtree );
|
fprintf( stderr, " subtree=%d,", req->subtree );
|
||||||
|
@ -2239,6 +2245,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
||||||
(dump_func)dump_fill_console_output_request,
|
(dump_func)dump_fill_console_output_request,
|
||||||
(dump_func)dump_read_console_output_request,
|
(dump_func)dump_read_console_output_request,
|
||||||
(dump_func)dump_move_console_output_request,
|
(dump_func)dump_move_console_output_request,
|
||||||
|
(dump_func)dump_send_console_signal_request,
|
||||||
(dump_func)dump_create_change_notification_request,
|
(dump_func)dump_create_change_notification_request,
|
||||||
(dump_func)dump_create_mapping_request,
|
(dump_func)dump_create_mapping_request,
|
||||||
(dump_func)dump_open_mapping_request,
|
(dump_func)dump_open_mapping_request,
|
||||||
|
@ -2397,6 +2404,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
||||||
(dump_func)dump_fill_console_output_reply,
|
(dump_func)dump_fill_console_output_reply,
|
||||||
(dump_func)dump_read_console_output_reply,
|
(dump_func)dump_read_console_output_reply,
|
||||||
(dump_func)0,
|
(dump_func)0,
|
||||||
|
(dump_func)0,
|
||||||
(dump_func)dump_create_change_notification_reply,
|
(dump_func)dump_create_change_notification_reply,
|
||||||
(dump_func)dump_create_mapping_reply,
|
(dump_func)dump_create_mapping_reply,
|
||||||
(dump_func)dump_open_mapping_reply,
|
(dump_func)dump_open_mapping_reply,
|
||||||
|
@ -2555,6 +2563,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
||||||
"fill_console_output",
|
"fill_console_output",
|
||||||
"read_console_output",
|
"read_console_output",
|
||||||
"move_console_output",
|
"move_console_output",
|
||||||
|
"send_console_signal",
|
||||||
"create_change_notification",
|
"create_change_notification",
|
||||||
"create_mapping",
|
"create_mapping",
|
||||||
"open_mapping",
|
"open_mapping",
|
||||||
|
|
114
win32/console.c
114
win32/console.c
|
@ -5,7 +5,7 @@
|
||||||
* 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 Eric Pouech
|
* Copyright 2001,2002 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
|
||||||
|
@ -109,7 +109,7 @@ static BOOL start_console_renderer(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* then try the regular PATH */
|
/* then try the regular PATH */
|
||||||
sprintf(buffer, "wineconsole --use-event=%d\n", hEvent);
|
sprintf(buffer, "wineconsole --use-event=%d", hEvent);
|
||||||
if (CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
|
if (CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
|
||||||
goto succeed;
|
goto succeed;
|
||||||
|
|
||||||
|
@ -210,7 +210,6 @@ static BOOL read_console_input(HANDLE handle, LPINPUT_RECORD buffer, DWORD count
|
||||||
{
|
{
|
||||||
BOOL ret;
|
BOOL ret;
|
||||||
unsigned read = 0;
|
unsigned read = 0;
|
||||||
DWORD mode;
|
|
||||||
|
|
||||||
SERVER_START_REQ( read_console_input )
|
SERVER_START_REQ( read_console_input )
|
||||||
{
|
{
|
||||||
|
@ -220,22 +219,6 @@ static BOOL read_console_input(HANDLE handle, LPINPUT_RECORD buffer, DWORD count
|
||||||
if ((ret = !wine_server_call_err( req ))) read = reply->read;
|
if ((ret = !wine_server_call_err( req ))) read = reply->read;
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
if (count && flush && GetConsoleMode(handle, &mode) && (mode & ENABLE_PROCESSED_INPUT))
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < read; i++)
|
|
||||||
{
|
|
||||||
if (buffer[i].EventType == KEY_EVENT && buffer[i].Event.KeyEvent.bKeyDown &&
|
|
||||||
buffer[i].Event.KeyEvent.uChar.UnicodeChar == 'C' - 64 &&
|
|
||||||
!(buffer[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
|
|
||||||
{
|
|
||||||
GenerateConsoleCtrlEvent(CTRL_C_EVENT, GetCurrentProcessId());
|
|
||||||
/* FIXME: this is hackish, but it easily disables IR handling afterwards */
|
|
||||||
buffer[i].Event.KeyEvent.uChar.UnicodeChar = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pRead) *pRead = read;
|
if (pRead) *pRead = read;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -460,6 +443,11 @@ BOOL WINAPI SetConsoleInputExeNameA(LPCSTR name)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* CONSOLE_DefaultHandler
|
||||||
|
*
|
||||||
|
* Final control event handler
|
||||||
|
*/
|
||||||
static BOOL WINAPI CONSOLE_DefaultHandler(DWORD dwCtrlType)
|
static BOOL WINAPI CONSOLE_DefaultHandler(DWORD dwCtrlType)
|
||||||
{
|
{
|
||||||
FIXME("Terminating process %lx on event %lx\n", GetCurrentProcessId(), dwCtrlType);
|
FIXME("Terminating process %lx on event %lx\n", GetCurrentProcessId(), dwCtrlType);
|
||||||
|
@ -546,9 +534,6 @@ static WINE_EXCEPTION_FILTER(CONSOLE_CtrlEventHandler)
|
||||||
* dwCtrlEvent [I] Type of event
|
* dwCtrlEvent [I] Type of event
|
||||||
* dwProcessGroupID [I] Process group ID to send event to
|
* dwProcessGroupID [I] Process group ID to send event to
|
||||||
*
|
*
|
||||||
* NOTES
|
|
||||||
* Doesn't yet work...!
|
|
||||||
*
|
|
||||||
* RETURNS
|
* RETURNS
|
||||||
* Success: True
|
* Success: True
|
||||||
* Failure: False (and *should* [but doesn't] set LastError)
|
* Failure: False (and *should* [but doesn't] set LastError)
|
||||||
|
@ -556,46 +541,25 @@ static WINE_EXCEPTION_FILTER(CONSOLE_CtrlEventHandler)
|
||||||
BOOL WINAPI GenerateConsoleCtrlEvent(DWORD dwCtrlEvent,
|
BOOL WINAPI GenerateConsoleCtrlEvent(DWORD dwCtrlEvent,
|
||||||
DWORD dwProcessGroupID)
|
DWORD dwProcessGroupID)
|
||||||
{
|
{
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
TRACE("(%ld, %ld)\n", dwCtrlEvent, dwProcessGroupID);
|
||||||
|
|
||||||
if (dwCtrlEvent != CTRL_C_EVENT && dwCtrlEvent != CTRL_BREAK_EVENT)
|
if (dwCtrlEvent != CTRL_C_EVENT && dwCtrlEvent != CTRL_BREAK_EVENT)
|
||||||
{
|
{
|
||||||
ERR("invalid event %ld for PGID %ld\n", dwCtrlEvent, dwProcessGroupID);
|
ERR("Invalid event %ld for PGID %ld\n", dwCtrlEvent, dwProcessGroupID);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dwProcessGroupID == GetCurrentProcessId() || dwProcessGroupID == 0)
|
SERVER_START_REQ( send_console_signal )
|
||||||
{
|
{
|
||||||
int i;
|
req->signal = dwCtrlEvent;
|
||||||
|
req->group_id = (void*)dwProcessGroupID;
|
||||||
FIXME("Attempt to send event %ld to self groupID, doing locally only\n", dwCtrlEvent);
|
ret = !wine_server_call_err( req );
|
||||||
|
|
||||||
/* this is only meaningfull when done locally, otherwise it will have to be done on
|
|
||||||
* the 'receive' side of the event generation
|
|
||||||
*/
|
|
||||||
if (dwCtrlEvent == CTRL_C_EVENT && console_ignore_ctrl_c)
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
{
|
|
||||||
RaiseException( (dwCtrlEvent == CTRL_C_EVENT) ? DBG_CONTROL_C : DBG_CONTROL_BREAK,
|
|
||||||
0, 0, NULL);
|
|
||||||
}
|
|
||||||
__EXCEPT(CONSOLE_CtrlEventHandler)
|
|
||||||
{
|
|
||||||
/* the debugger didn't continue... so, pass to ctrl handlers */
|
|
||||||
for (i = 0; i < sizeof(handlers)/sizeof(handlers[0]); i++)
|
|
||||||
{
|
|
||||||
if (handlers[i] && (handlers[i])(dwCtrlEvent)) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
__ENDTRY;
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
FIXME("event %ld to external PGID %ld - not implemented yet\n", dwCtrlEvent, dwProcessGroupID);
|
SERVER_END_REQ;
|
||||||
return FALSE;
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1346,6 +1310,7 @@ BOOL WINAPI ScrollConsoleScreenBufferW(HANDLE hConsoleOutput, LPSMALL_RECT lpScr
|
||||||
* Console manipulation functions
|
* Console manipulation functions
|
||||||
*
|
*
|
||||||
* ====================================================================*/
|
* ====================================================================*/
|
||||||
|
|
||||||
/* some missing functions...
|
/* some missing functions...
|
||||||
* FIXME: those are likely to be defined as undocumented function in kernel32 (or part of them)
|
* FIXME: those are likely to be defined as undocumented function in kernel32 (or part of them)
|
||||||
* should get the right API and implement them
|
* should get the right API and implement them
|
||||||
|
@ -1405,7 +1370,7 @@ BOOL CONSOLE_AppendHistory(const WCHAR* ptr)
|
||||||
*/
|
*/
|
||||||
unsigned CONSOLE_GetNumHistoryEntries(void)
|
unsigned CONSOLE_GetNumHistoryEntries(void)
|
||||||
{
|
{
|
||||||
unsigned ret = 0;
|
unsigned ret = -1;
|
||||||
SERVER_START_REQ(get_console_input_info)
|
SERVER_START_REQ(get_console_input_info)
|
||||||
{
|
{
|
||||||
req->handle = 0;
|
req->handle = 0;
|
||||||
|
@ -1415,3 +1380,40 @@ unsigned CONSOLE_GetNumHistoryEntries(void)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* CONSOLE_HandleCtrlC
|
||||||
|
*
|
||||||
|
* Check whether the shall manipulate CtrlC events
|
||||||
|
*/
|
||||||
|
int CONSOLE_HandleCtrlC(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* FIXME: better test whether a console is attached to this process ??? */
|
||||||
|
extern unsigned CONSOLE_GetNumHistoryEntries(void);
|
||||||
|
if (CONSOLE_GetNumHistoryEntries() == (unsigned)-1) return 0;
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
{
|
||||||
|
RaiseException( DBG_CONTROL_C, 0, 0, NULL );
|
||||||
|
}
|
||||||
|
__EXCEPT(CONSOLE_CtrlEventHandler)
|
||||||
|
{
|
||||||
|
/* the debugger didn't continue... so, pass to ctrl handlers */
|
||||||
|
/* FIXME: since this routine is called while in a signal handler,
|
||||||
|
* there are some serious synchronisation issues with
|
||||||
|
* SetConsoleCtrlHandler (trouble ahead)
|
||||||
|
*/
|
||||||
|
for (i = 0; i < sizeof(handlers)/sizeof(handlers[0]); i++)
|
||||||
|
{
|
||||||
|
if (handlers[i] && (handlers[i])(CTRL_C_EVENT)) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__ENDTRY;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue