kernel32: Add AttachConsole implementation.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=41573 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=43910 Signed-off-by: Jacek Caban <jacek@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
d175419f0b
commit
57212f64f8
|
@ -2909,8 +2909,23 @@ BOOL WINAPI ScrollConsoleScreenBufferW(HANDLE hConsoleOutput, LPSMALL_RECT lpScr
|
|||
*/
|
||||
BOOL WINAPI AttachConsole(DWORD dwProcessId)
|
||||
{
|
||||
FIXME("stub %x\n",dwProcessId);
|
||||
return TRUE;
|
||||
BOOL ret;
|
||||
|
||||
TRACE("(%x)\n", dwProcessId);
|
||||
|
||||
SERVER_START_REQ( attach_console )
|
||||
{
|
||||
req->pid = dwProcessId;
|
||||
ret = !wine_server_call_err( req );
|
||||
if (ret)
|
||||
{
|
||||
SetStdHandle(STD_INPUT_HANDLE, wine_server_ptr_handle(reply->std_in));
|
||||
SetStdHandle(STD_OUTPUT_HANDLE, wine_server_ptr_handle(reply->std_out));
|
||||
SetStdHandle(STD_ERROR_HANDLE, wine_server_ptr_handle(reply->std_err));
|
||||
}
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
|
|
|
@ -208,19 +208,29 @@ static void testEmptyWrite(HANDLE hCon)
|
|||
okCURSOR(hCon, c);
|
||||
}
|
||||
|
||||
static void testWriteSimple(HANDLE hCon)
|
||||
static void simple_write_console(HANDLE console, const char *text)
|
||||
{
|
||||
COORD c;
|
||||
DWORD len;
|
||||
const char* mytest = "abcdefg";
|
||||
const int mylen = strlen(mytest);
|
||||
DWORD len;
|
||||
COORD c = {0, 0};
|
||||
BOOL ret;
|
||||
|
||||
/* single line write */
|
||||
c.X = c.Y = 0;
|
||||
ok(SetConsoleCursorPosition(hCon, c) != 0, "Cursor in upper-left\n");
|
||||
ok(SetConsoleCursorPosition(console, c) != 0, "Cursor in upper-left\n");
|
||||
|
||||
ret = WriteConsoleA(console, text, strlen(text), &len, NULL);
|
||||
ok(ret, "WriteConsoleA failed: %u\n", GetLastError());
|
||||
ok(len == strlen(text), "unexpected len %u\n", len);
|
||||
}
|
||||
|
||||
static void testWriteSimple(HANDLE hCon)
|
||||
{
|
||||
const char* mytest = "abcdefg";
|
||||
int mylen = strlen(mytest);
|
||||
COORD c = {0, 0};
|
||||
|
||||
simple_write_console(hCon, mytest);
|
||||
|
||||
ok(WriteConsoleA(hCon, mytest, mylen, &len, NULL) != 0 && len == mylen, "WriteConsole\n");
|
||||
c.Y = 0;
|
||||
for (c.X = 0; c.X < mylen; c.X++)
|
||||
{
|
||||
okCHAR(hCon, c, mytest[c.X], TEST_ATTRIB);
|
||||
|
@ -3019,6 +3029,98 @@ static void test_GetConsoleScreenBufferInfoEx(HANDLE std_output)
|
|||
ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
|
||||
}
|
||||
|
||||
static void test_AttachConsole_child(DWORD console_pid)
|
||||
{
|
||||
HANDLE pipe_in, pipe_out;
|
||||
COORD c = {0,0};
|
||||
HANDLE console;
|
||||
char buf[32];
|
||||
DWORD len;
|
||||
BOOL res;
|
||||
|
||||
res = CreatePipe(&pipe_in, &pipe_out, NULL, 0);
|
||||
ok(res, "CreatePipe failed: %u\n", GetLastError());
|
||||
|
||||
res = AttachConsole(console_pid);
|
||||
ok(!res && GetLastError() == ERROR_ACCESS_DENIED,
|
||||
"AttachConsole returned: %x(%u)\n", res, GetLastError());
|
||||
|
||||
res = FreeConsole();
|
||||
ok(res, "FreeConsole failed: %u\n", GetLastError());
|
||||
|
||||
SetStdHandle(STD_ERROR_HANDLE, pipe_out);
|
||||
|
||||
res = AttachConsole(console_pid);
|
||||
ok(res, "AttachConsole failed: %u\n", GetLastError());
|
||||
|
||||
ok(pipe_out != GetStdHandle(STD_ERROR_HANDLE), "std handle not set to console\n");
|
||||
|
||||
console = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
|
||||
ok(console != INVALID_HANDLE_VALUE, "Could not open console\n");
|
||||
|
||||
res = ReadConsoleOutputCharacterA(console, buf, 6, c, &len);
|
||||
ok(res, "ReadConsoleOutputCharacterA failed: %u\n", GetLastError());
|
||||
ok(len == 6, "len = %u\n", len);
|
||||
ok(!memcmp(buf, "Parent", 6), "Unexpected console output\n");
|
||||
|
||||
res = FreeConsole();
|
||||
ok(res, "FreeConsole failed: %u\n", GetLastError());
|
||||
|
||||
SetStdHandle(STD_INPUT_HANDLE, pipe_in);
|
||||
SetStdHandle(STD_OUTPUT_HANDLE, pipe_out);
|
||||
|
||||
res = AttachConsole(ATTACH_PARENT_PROCESS);
|
||||
ok(res, "AttachConsole failed: %u\n", GetLastError());
|
||||
|
||||
ok(pipe_in != GetStdHandle(STD_INPUT_HANDLE), "std handle not set to console\n");
|
||||
ok(pipe_out != GetStdHandle(STD_OUTPUT_HANDLE), "std handle not set to console\n");
|
||||
|
||||
console = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
|
||||
ok(console != INVALID_HANDLE_VALUE, "Could not open console\n");
|
||||
|
||||
res = ReadConsoleOutputCharacterA(console, buf, 6, c, &len);
|
||||
ok(res, "ReadConsoleOutputCharacterA failed: %u\n", GetLastError());
|
||||
ok(len == 6, "len = %u\n", len);
|
||||
ok(!memcmp(buf, "Parent", 6), "Unexpected console output\n");
|
||||
|
||||
simple_write_console(console, "Child");
|
||||
CloseHandle(console);
|
||||
|
||||
res = FreeConsole();
|
||||
ok(res, "FreeConsole failed: %u\n", GetLastError());
|
||||
|
||||
res = CloseHandle(pipe_in);
|
||||
ok(res, "pipe_in is no longer valid\n");
|
||||
res = CloseHandle(pipe_out);
|
||||
ok(res, "pipe_out is no longer valid\n");
|
||||
}
|
||||
|
||||
static void test_AttachConsole(HANDLE console)
|
||||
{
|
||||
STARTUPINFOA si = { sizeof(si) };
|
||||
PROCESS_INFORMATION info;
|
||||
char **argv, buf[MAX_PATH];
|
||||
COORD c = {0,0};
|
||||
DWORD len;
|
||||
BOOL res;
|
||||
|
||||
simple_write_console(console, "Parent console");
|
||||
|
||||
winetest_get_mainargs(&argv);
|
||||
sprintf(buf, "\"%s\" console attach_console %x", argv[0], GetCurrentProcessId());
|
||||
res = CreateProcessA(NULL, buf, NULL, NULL, TRUE, 0, NULL, NULL, &si, &info);
|
||||
ok(res, "CreateProcess failed: %u\n", GetLastError());
|
||||
CloseHandle(info.hThread);
|
||||
|
||||
winetest_wait_child_process(info.hProcess);
|
||||
CloseHandle(info.hProcess);
|
||||
|
||||
res = ReadConsoleOutputCharacterA(console, buf, 5, c, &len);
|
||||
ok(res, "ReadConsoleOutputCharacterA failed: %u\n", GetLastError());
|
||||
ok(len == 5, "len = %u\n", len);
|
||||
ok(!memcmp(buf, "Child", 5), "Unexpected console output\n");
|
||||
}
|
||||
|
||||
START_TEST(console)
|
||||
{
|
||||
static const char font_name[] = "Lucida Console";
|
||||
|
@ -3030,9 +3132,21 @@ START_TEST(console)
|
|||
char old_font[LF_FACESIZE];
|
||||
BOOL delete = FALSE;
|
||||
DWORD size;
|
||||
char **argv;
|
||||
int argc;
|
||||
|
||||
init_function_pointers();
|
||||
|
||||
argc = winetest_get_mainargs(&argv);
|
||||
|
||||
if (argc > 3 && !strcmp(argv[2], "attach_console"))
|
||||
{
|
||||
DWORD parent_pid;
|
||||
sscanf(argv[3], "%x", &parent_pid);
|
||||
test_AttachConsole_child(parent_pid);
|
||||
return;
|
||||
}
|
||||
|
||||
/* be sure we have a clean console (and that's our own)
|
||||
* FIXME: this will make the test fail (currently) if we don't run
|
||||
* under X11
|
||||
|
@ -3170,4 +3284,5 @@ START_TEST(console)
|
|||
test_GetConsoleFontInfo(hConOut);
|
||||
test_SetConsoleFont(hConOut);
|
||||
test_GetConsoleScreenBufferInfoEx(hConOut);
|
||||
test_AttachConsole(hConOut);
|
||||
}
|
||||
|
|
|
@ -1839,6 +1839,22 @@ struct open_console_reply
|
|||
|
||||
|
||||
|
||||
struct attach_console_request
|
||||
{
|
||||
struct request_header __header;
|
||||
process_id_t pid;
|
||||
};
|
||||
struct attach_console_reply
|
||||
{
|
||||
struct reply_header __header;
|
||||
obj_handle_t std_in;
|
||||
obj_handle_t std_out;
|
||||
obj_handle_t std_err;
|
||||
char __pad_20[4];
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct get_console_wait_event_request
|
||||
{
|
||||
struct request_header __header;
|
||||
|
@ -5697,6 +5713,7 @@ enum request
|
|||
REQ_free_console,
|
||||
REQ_get_console_renderer_events,
|
||||
REQ_open_console,
|
||||
REQ_attach_console,
|
||||
REQ_get_console_wait_event,
|
||||
REQ_get_console_mode,
|
||||
REQ_set_console_mode,
|
||||
|
@ -5993,6 +6010,7 @@ union generic_request
|
|||
struct free_console_request free_console_request;
|
||||
struct get_console_renderer_events_request get_console_renderer_events_request;
|
||||
struct open_console_request open_console_request;
|
||||
struct attach_console_request attach_console_request;
|
||||
struct get_console_wait_event_request get_console_wait_event_request;
|
||||
struct get_console_mode_request get_console_mode_request;
|
||||
struct set_console_mode_request set_console_mode_request;
|
||||
|
@ -6287,6 +6305,7 @@ union generic_reply
|
|||
struct free_console_reply free_console_reply;
|
||||
struct get_console_renderer_events_reply get_console_renderer_events_reply;
|
||||
struct open_console_reply open_console_reply;
|
||||
struct attach_console_reply attach_console_reply;
|
||||
struct get_console_wait_event_reply get_console_wait_event_reply;
|
||||
struct get_console_mode_reply get_console_mode_reply;
|
||||
struct set_console_mode_reply set_console_mode_reply;
|
||||
|
@ -6514,6 +6533,6 @@ union generic_reply
|
|||
struct terminate_job_reply terminate_job_reply;
|
||||
};
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 555
|
||||
#define SERVER_PROTOCOL_VERSION 556
|
||||
|
||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||
|
|
|
@ -1546,6 +1546,49 @@ DECL_HANDLER(open_console)
|
|||
else if (!get_error()) set_error( STATUS_ACCESS_DENIED );
|
||||
}
|
||||
|
||||
/* attach to a other process's console */
|
||||
DECL_HANDLER(attach_console)
|
||||
{
|
||||
struct process *process;
|
||||
|
||||
if (current->process->console)
|
||||
{
|
||||
set_error( STATUS_ACCESS_DENIED );
|
||||
return;
|
||||
}
|
||||
|
||||
process = get_process_from_id( req->pid == ATTACH_PARENT_PROCESS
|
||||
? current->process->parent_id : req->pid );
|
||||
if (!process) return;
|
||||
|
||||
if (process->console && process->console->active)
|
||||
{
|
||||
reply->std_in = alloc_handle( current->process, process->console, GENERIC_READ, 0 );
|
||||
if (!reply->std_in) goto error;
|
||||
|
||||
reply->std_out = alloc_handle( current->process, process->console->active, GENERIC_WRITE, 0 );
|
||||
if (!reply->std_out) goto error;
|
||||
|
||||
reply->std_err = alloc_handle( current->process, process->console->active, GENERIC_WRITE, 0 );
|
||||
if (!reply->std_err) goto error;
|
||||
|
||||
current->process->console = (struct console_input *)grab_object( process->console );
|
||||
current->process->console->num_proc++;
|
||||
}
|
||||
else
|
||||
{
|
||||
set_error( STATUS_INVALID_HANDLE );
|
||||
}
|
||||
|
||||
release_object( process );
|
||||
return;
|
||||
|
||||
error:
|
||||
if (reply->std_in) close_handle( current->process, reply->std_in );
|
||||
if (reply->std_out) close_handle( current->process, reply->std_out );
|
||||
release_object( process );
|
||||
}
|
||||
|
||||
/* set info about a console input */
|
||||
DECL_HANDLER(set_console_input_info)
|
||||
{
|
||||
|
|
|
@ -1463,6 +1463,16 @@ struct console_renderer_event
|
|||
@END
|
||||
|
||||
|
||||
/* Attach to a other process's console */
|
||||
@REQ(attach_console)
|
||||
process_id_t pid; /* pid of attached console process */
|
||||
@REPLY
|
||||
obj_handle_t std_in; /* attached stdin */
|
||||
obj_handle_t std_out; /* attached stdout */
|
||||
obj_handle_t std_err; /* attached stderr */
|
||||
@END
|
||||
|
||||
|
||||
/* Get the input queue wait event */
|
||||
@REQ(get_console_wait_event)
|
||||
@REPLY
|
||||
|
|
|
@ -176,6 +176,7 @@ DECL_HANDLER(alloc_console);
|
|||
DECL_HANDLER(free_console);
|
||||
DECL_HANDLER(get_console_renderer_events);
|
||||
DECL_HANDLER(open_console);
|
||||
DECL_HANDLER(attach_console);
|
||||
DECL_HANDLER(get_console_wait_event);
|
||||
DECL_HANDLER(get_console_mode);
|
||||
DECL_HANDLER(set_console_mode);
|
||||
|
@ -471,6 +472,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
|
|||
(req_handler)req_free_console,
|
||||
(req_handler)req_get_console_renderer_events,
|
||||
(req_handler)req_open_console,
|
||||
(req_handler)req_attach_console,
|
||||
(req_handler)req_get_console_wait_event,
|
||||
(req_handler)req_get_console_mode,
|
||||
(req_handler)req_set_console_mode,
|
||||
|
@ -1120,6 +1122,12 @@ C_ASSERT( FIELD_OFFSET(struct open_console_request, share) == 24 );
|
|||
C_ASSERT( sizeof(struct open_console_request) == 32 );
|
||||
C_ASSERT( FIELD_OFFSET(struct open_console_reply, handle) == 8 );
|
||||
C_ASSERT( sizeof(struct open_console_reply) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct attach_console_request, pid) == 12 );
|
||||
C_ASSERT( sizeof(struct attach_console_request) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct attach_console_reply, std_in) == 8 );
|
||||
C_ASSERT( FIELD_OFFSET(struct attach_console_reply, std_out) == 12 );
|
||||
C_ASSERT( FIELD_OFFSET(struct attach_console_reply, std_err) == 16 );
|
||||
C_ASSERT( sizeof(struct attach_console_reply) == 24 );
|
||||
C_ASSERT( sizeof(struct get_console_wait_event_request) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_console_wait_event_reply, handle) == 8 );
|
||||
C_ASSERT( sizeof(struct get_console_wait_event_reply) == 16 );
|
||||
|
|
|
@ -1989,6 +1989,18 @@ static void dump_open_console_reply( const struct open_console_reply *req )
|
|||
fprintf( stderr, " handle=%04x", req->handle );
|
||||
}
|
||||
|
||||
static void dump_attach_console_request( const struct attach_console_request *req )
|
||||
{
|
||||
fprintf( stderr, " pid=%04x", req->pid );
|
||||
}
|
||||
|
||||
static void dump_attach_console_reply( const struct attach_console_reply *req )
|
||||
{
|
||||
fprintf( stderr, " std_in=%04x", req->std_in );
|
||||
fprintf( stderr, ", std_out=%04x", req->std_out );
|
||||
fprintf( stderr, ", std_err=%04x", req->std_err );
|
||||
}
|
||||
|
||||
static void dump_get_console_wait_event_request( const struct get_console_wait_event_request *req )
|
||||
{
|
||||
}
|
||||
|
@ -4595,6 +4607,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)dump_free_console_request,
|
||||
(dump_func)dump_get_console_renderer_events_request,
|
||||
(dump_func)dump_open_console_request,
|
||||
(dump_func)dump_attach_console_request,
|
||||
(dump_func)dump_get_console_wait_event_request,
|
||||
(dump_func)dump_get_console_mode_request,
|
||||
(dump_func)dump_set_console_mode_request,
|
||||
|
@ -4887,6 +4900,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
|||
NULL,
|
||||
(dump_func)dump_get_console_renderer_events_reply,
|
||||
(dump_func)dump_open_console_reply,
|
||||
(dump_func)dump_attach_console_reply,
|
||||
(dump_func)dump_get_console_wait_event_reply,
|
||||
(dump_func)dump_get_console_mode_reply,
|
||||
NULL,
|
||||
|
@ -5179,6 +5193,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
|||
"free_console",
|
||||
"get_console_renderer_events",
|
||||
"open_console",
|
||||
"attach_console",
|
||||
"get_console_wait_event",
|
||||
"get_console_mode",
|
||||
"set_console_mode",
|
||||
|
@ -5471,6 +5486,7 @@ static const struct
|
|||
{ "INVALID_LOCK_SEQUENCE", STATUS_INVALID_LOCK_SEQUENCE },
|
||||
{ "INVALID_OWNER", STATUS_INVALID_OWNER },
|
||||
{ "INVALID_PARAMETER", STATUS_INVALID_PARAMETER },
|
||||
{ "INVALID_PIPE_STATE", STATUS_INVALID_PIPE_STATE },
|
||||
{ "INVALID_READ_MODE", STATUS_INVALID_READ_MODE },
|
||||
{ "INVALID_SECURITY_DESCR", STATUS_INVALID_SECURITY_DESCR },
|
||||
{ "IO_TIMEOUT", STATUS_IO_TIMEOUT },
|
||||
|
@ -5508,6 +5524,7 @@ static const struct
|
|||
{ "PENDING", STATUS_PENDING },
|
||||
{ "PIPE_BROKEN", STATUS_PIPE_BROKEN },
|
||||
{ "PIPE_BUSY", STATUS_PIPE_BUSY },
|
||||
{ "PIPE_CLOSING", STATUS_PIPE_CLOSING },
|
||||
{ "PIPE_CONNECTED", STATUS_PIPE_CONNECTED },
|
||||
{ "PIPE_DISCONNECTED", STATUS_PIPE_DISCONNECTED },
|
||||
{ "PIPE_LISTENING", STATUS_PIPE_LISTENING },
|
||||
|
|
Loading…
Reference in New Issue