From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/kernel32/tests/console.c | 247 +++++++++++++++++++++++++++++++++- 1 file changed, 243 insertions(+), 4 deletions(-)
diff --git a/dlls/kernel32/tests/console.c b/dlls/kernel32/tests/console.c index 03491b279af..7e139a9304e 100644 --- a/dlls/kernel32/tests/console.c +++ b/dlls/kernel32/tests/console.c @@ -4124,12 +4124,132 @@ static void test_GetConsoleScreenBufferInfoEx(HANDLE std_output) ok(GetLastError() == 0xdeadbeef, "got %lu, expected 0xdeadbeef\n", GetLastError()); }
-static void test_FreeConsole(void) +/* Flush events and check that there was a double-click event queued. + * Windows may also queue focus change or mouse move events. */ +static void check_mouse_event(HANDLE handle) { - HANDLE handle, unbound_output = NULL, unbound_input = NULL; + BOOL ret, got_mouse_event = FALSE; + INPUT_RECORD ir; + DWORD count; + + while (PeekConsoleInputW(handle, &ir, 1, &count) && count) + { + ret = ReadConsoleInputW(handle, &ir, 1, &count); + ok(ret == TRUE, "got error %lu\n", GetLastError()); + ok(count == 1, "got count %lu\n", count); + if (ir.EventType == MOUSE_EVENT && ir.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK) + got_mouse_event = TRUE; + } + ok(got_mouse_event, "didn't find mouse event\n"); +} + +static void test_unbound_handles_child(DWORD parent_pid, UINT_PTR parent_input_int, UINT_PTR parent_output_int) +{ + HANDLE parent_process, parent_input, parent_output, unbound_input, input, parent_event, child_event; + OBJECT_ATTRIBUTES attr = {sizeof(attr)}; + IO_STATUS_BLOCK iosb; + UNICODE_STRING name; + NTSTATUS status; + INPUT_RECORD ir; + DWORD count; + BOOL ret; + + parent_event = OpenEventA(EVENT_ALL_ACCESS, FALSE, "winetest_unbound_handles_parent"); + child_event = OpenEventA(EVENT_ALL_ACCESS, FALSE, "winetest_unbound_handles_child"); + + parent_process = OpenProcess(PROCESS_DUP_HANDLE, FALSE, parent_pid); + ok(!!parent_process, "got error %lu\n", GetLastError()); + + ret = DuplicateHandle(parent_process, (HANDLE)parent_input_int, + GetCurrentProcess(), &parent_input, 0, FALSE, DUPLICATE_SAME_ACCESS); + ok(ret, "got error %lu\n", GetLastError()); + ret = DuplicateHandle(parent_process, (HANDLE)parent_output_int, + GetCurrentProcess(), &parent_output, 0, FALSE, DUPLICATE_SAME_ACCESS); + ok(ret, "got error %lu\n", GetLastError()); + + ret = WaitForSingleObject(parent_input, 0); + todo_wine ok(!ret, "got %d\n", ret); + ret = WaitForSingleObject(parent_output, 0); + todo_wine ok(!ret, "got %d\n", ret); + + ret = PeekConsoleInputW(parent_input, &ir, 1, &count); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError()); + + /* We cannot create an unbound handle, because we have no console. */ + + attr.ObjectName = &name; + attr.Attributes = OBJ_INHERIT; + RtlInitUnicodeString( &name, L"\Device\ConDrv\Input" ); + status = NtCreateFile( &unbound_input, FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE | FILE_READ_ATTRIBUTES | + FILE_WRITE_ATTRIBUTES, &attr, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_CREATE, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); + todo_wine ok(status == STATUS_INVALID_HANDLE, "got %#lx\n", status); + if (!status) NtClose( unbound_input ); + + /* Allocate a console. */ + + ret = AllocConsole(); + ok(ret == TRUE, "got error %lu\n", GetLastError()); + + unbound_input = create_unbound_handle(FALSE, TRUE); + + input = CreateFileA("CONIN$", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(input != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError()); + + memset(&ir, 0, sizeof(ir)); + ir.EventType = MOUSE_EVENT; + ir.Event.MouseEvent.dwEventFlags = DOUBLE_CLICK; + ret = WriteConsoleInputW(input, &ir, 1, &count); + ok(ret, "got error %lu\n", GetLastError()); + + ret = WaitForSingleObject(unbound_input, 0); + ok(!ret, "got %d\n", ret); + + /* We can read from our input using the parent's handle, but its signaled + * state will not reflect our input. */ + + check_mouse_event(parent_input); + + ret = WaitForSingleObject(unbound_input, 0); + ok(ret == WAIT_TIMEOUT, "got %d\n", ret); + ret = WaitForSingleObject(parent_input, 0); + todo_wine ok(!ret, "got %d\n", ret); + + CloseHandle(input); + ret = FreeConsole(); + ok(ret == TRUE, "got error %lu\n", GetLastError()); + + ret = WaitForSingleObject(unbound_input, 0); + todo_wine ok(ret == WAIT_TIMEOUT, "got %d\n", ret); + CloseHandle(unbound_input); + + ret = WaitForSingleObject(parent_input, 0); + todo_wine ok(!ret, "got %d\n", ret); + ret = WaitForSingleObject(parent_output, 0); + todo_wine ok(!ret, "got %d\n", ret); + + /* Parent will consume its input, designalling those handles. */ + SetEvent(child_event); + ret = WaitForSingleObject(parent_event, 1000); + ok(!ret, "got %d\n", ret); + + ret = WaitForSingleObject(parent_input, 0); + todo_wine ok(ret == WAIT_TIMEOUT, "got %d\n", ret); + ret = WaitForSingleObject(parent_output, 0); + todo_wine ok(ret == WAIT_TIMEOUT, "got %d\n", ret); +} + +static void test_FreeConsole(HANDLE input, HANDLE orig_output) +{ + static const INPUT_RECORD ir = {.EventType = MOUSE_EVENT, .Event.MouseEvent.dwEventFlags = DOUBLE_CLICK}; + HANDLE handle, output, parent_event, child_event, unbound_output = NULL, unbound_input = NULL, unbound_input2; + STARTUPINFOA si = {sizeof(si)}; + char buf[MAX_PATH], **argv; + PROCESS_INFORMATION info; DWORD size, mode, type; WCHAR title[16]; - char buf[32]; HWND hwnd; UINT cp; BOOL ret; @@ -4144,6 +4264,53 @@ static void test_FreeConsole(void) unbound_output = create_unbound_handle(TRUE, TRUE); }
+ output = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); + ok(output != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError()); + + ret = WriteConsoleInputW(input, &ir, 1, &size); + ok(ret, "got error %lu\n", GetLastError()); + + ret = WaitForSingleObject(output, 0); + ok(!ret, "got %d\n", ret); + ret = WaitForSingleObject(unbound_output, 0); + ok(!ret, "got %d\n", ret); + ret = WaitForSingleObject(unbound_input, 0); + ok(!ret, "got %d\n", ret); + + parent_event = CreateEventA(NULL, FALSE, FALSE, "winetest_unbound_handles_parent"); + child_event = CreateEventA(NULL, FALSE, FALSE, "winetest_unbound_handles_child"); + + winetest_get_mainargs(&argv); + sprintf(buf, ""%s" console unbound_handles %#lx %#Ix %#Ix", + argv[0], GetCurrentProcessId(), (UINT_PTR)unbound_input, (UINT_PTR)unbound_output); + ret = CreateProcessA(NULL, buf, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &info); + ok(ret, "got error %lu\n", GetLastError()); + + /* Wait for child to test our handles while there's input available. */ + ret = WaitForSingleObject(child_event, 1000); + todo_wine ok(!ret, "got %d\n", ret); + + /* Read the input. */ + check_mouse_event(unbound_input); + + ret = WaitForSingleObject(output, 0); + ok(ret == WAIT_TIMEOUT, "got %d\n", ret); + ret = WaitForSingleObject(unbound_output, 0); + ok(ret == WAIT_TIMEOUT, "got %d\n", ret); + ret = WaitForSingleObject(unbound_input, 0); + ok(ret == WAIT_TIMEOUT, "got %d\n", ret); + + /* Test that our handles are now designaled in the child. */ + SetEvent(parent_event); + + CloseHandle(info.hThread); + wait_child_process(info.hProcess); + CloseHandle(info.hProcess); + + ret = WriteConsoleInputW(input, &ir, 1, &size); + ok(ret, "got error %lu\n", GetLastError()); + ret = FreeConsole(); ok(ret, "FreeConsole failed: %lu\n", GetLastError());
@@ -4170,6 +4337,71 @@ static void test_FreeConsole(void) (GetLastError() == ERROR_INVALID_HANDLE || broken(GetLastError() == ERROR_FILE_NOT_FOUND /* winxp */)), "CreateFileA failed: %lu\n", GetLastError());
+ CloseHandle(input); + CloseHandle(orig_output); + + /* In Windows 10 the handles are consistently unsignaled here. + * Windows 11 is weirdly inconsistent; the state seems to be very sensitive + * to timing, in unclear ways. */ + ret = WaitForSingleObject(output, 0); + todo_wine ok(!ret || ret == WAIT_TIMEOUT, "got %d\n", ret); + ret = WaitForSingleObject(unbound_output, 0); + todo_wine ok(!ret || ret == WAIT_TIMEOUT, "got %d\n", ret); + ret = WaitForSingleObject(unbound_input, 0); + todo_wine ok(!ret || ret == WAIT_TIMEOUT, "got %d\n", ret); + + /* Create a new console. + * + * The previous unbound handles remain associated with the old console. + * As with the cross-process case, they can be read from, which reads from + * the current process's active console, but the signaled state does not + * reflect the current console. + * + * For some inexplicable reason, allocating the new console also causes the + * original orphaned handles to become signaled. */ + ret = AllocConsole(); + ok(ret, "got error %lu\n", GetLastError()); + + ret = WaitForSingleObject(output, 0); + todo_wine ok(!ret, "got %d\n", ret); + ret = WaitForSingleObject(unbound_output, 0); + todo_wine ok(!ret, "got %d\n", ret); + ret = WaitForSingleObject(unbound_input, 0); + todo_wine ok(!ret, "got %d\n", ret); + + input = CreateFileA("CONIN$", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(input != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError()); + ret = WriteConsoleInputW(input, &ir, 1, &size); + ok(ret, "got error %lu\n", GetLastError()); + + unbound_input2 = create_unbound_handle(FALSE, TRUE); + + ret = WaitForSingleObject(unbound_input2, 0); + ok(!ret, "got %d\n", ret); + + check_mouse_event(unbound_input); + + ret = WaitForSingleObject(output, 0); + todo_wine ok(!ret, "got %d\n", ret); + ret = WaitForSingleObject(unbound_output, 0); + todo_wine ok(!ret, "got %d\n", ret); + ret = WaitForSingleObject(unbound_input, 0); + todo_wine ok(!ret, "got %d\n", ret); + + ret = WaitForSingleObject(unbound_input2, 0); + ok(ret == WAIT_TIMEOUT, "got %d\n", ret); + + ret = FreeConsole(); + ok(ret, "got error %lu\n", GetLastError()); + CloseHandle(input); + + ret = WaitForSingleObject(output, 0); + todo_wine ok(!ret, "got %d\n", ret); + ret = WaitForSingleObject(unbound_output, 0); + todo_wine ok(!ret, "got %d\n", ret); + ret = WaitForSingleObject(unbound_input, 0); + todo_wine ok(!ret, "got %d\n", ret); + handle = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); @@ -4252,6 +4484,7 @@ static void test_FreeConsole(void)
CloseHandle(unbound_input); CloseHandle(unbound_output); + CloseHandle(output); }
static void test_SetConsoleScreenBufferInfoEx(HANDLE std_output) @@ -5473,6 +5706,12 @@ START_TEST(console) return; }
+ if (argc == 6 && !strcmp(argv[2], "unbound_handles")) + { + test_unbound_handles_child(strtoul(argv[3], NULL, 16), strtoull(argv[4], NULL, 16), strtoull(argv[5], NULL, 16)); + return; + } + test_current = argc >= 3 && !strcmp(argv[2], "--current"); using_pseudo_console = argc >= 3 && !strcmp(argv[2], "--pseudo-console");
@@ -5665,7 +5904,7 @@ START_TEST(console) test_pseudo_console(); test_AttachConsole(hConOut); test_AllocConsole(); - test_FreeConsole(); + test_FreeConsole(hConIn, hConOut); test_condrv_server_as_root_directory(); test_CreateProcessCUI(); test_CtrlHandlerSubsystem();
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/kernel32/tests/console.c | 9 +++++++-- server/console.c | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/dlls/kernel32/tests/console.c b/dlls/kernel32/tests/console.c index 7e139a9304e..886c1aa876a 100644 --- a/dlls/kernel32/tests/console.c +++ b/dlls/kernel32/tests/console.c @@ -4185,8 +4185,13 @@ static void test_unbound_handles_child(DWORD parent_pid, UINT_PTR parent_input_i FILE_WRITE_ATTRIBUTES, &attr, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_CREATE, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); - todo_wine ok(status == STATUS_INVALID_HANDLE, "got %#lx\n", status); - if (!status) NtClose( unbound_input ); + ok(status == STATUS_INVALID_HANDLE, "got %#lx\n", status); + RtlInitUnicodeString( &name, L"\Device\ConDrv\Output" ); + status = NtCreateFile( &unbound_input, FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE | FILE_READ_ATTRIBUTES | + FILE_WRITE_ATTRIBUTES, &attr, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_CREATE, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); + ok(status == STATUS_INVALID_HANDLE, "got %#lx\n", status);
/* Allocate a console. */
diff --git a/server/console.c b/server/console.c index c3e7bf57e92..16093fed4bc 100644 --- a/server/console.c +++ b/server/console.c @@ -1314,6 +1314,13 @@ static struct object *console_device_lookup_name( struct object *obj, struct uni if (name->len == sizeof(inputW) && !memcmp( name->str, inputW, name->len )) { struct console_input *console_input; + + if (!current->process->console) + { + set_error( STATUS_INVALID_HANDLE ); + return NULL; + } + name->len = 0; if (!(console_input = alloc_object( &console_input_ops ))) return NULL; console_input->fd = alloc_pseudo_fd( &console_input_fd_ops, &console_input->obj, @@ -1329,6 +1336,13 @@ static struct object *console_device_lookup_name( struct object *obj, struct uni if (name->len == sizeof(outputW) && !memcmp( name->str, outputW, name->len )) { struct console_output *console_output; + + if (!current->process->console) + { + set_error( STATUS_INVALID_HANDLE ); + return NULL; + } + name->len = 0; if (!(console_output = alloc_object( &console_output_ops ))) return NULL; console_output->fd = alloc_pseudo_fd( &console_output_fd_ops, &console_output->obj,
From: Elizabeth Figura zfigura@codeweavers.com
--- server/console.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/server/console.c b/server/console.c index 16093fed4bc..c081006590d 100644 --- a/server/console.c +++ b/server/console.c @@ -61,6 +61,7 @@ struct console struct fd *fd; /* for bare console, attached input fd */ struct async_queue ioctl_q; /* ioctl queue */ struct async_queue read_q; /* read queue */ + struct list screen_buffers;/* attached screen buffers */ };
static void console_dump( struct object *obj, int verbose ); @@ -462,8 +463,6 @@ static const struct fd_ops console_connection_fd_ops = default_fd_reselect_async /* reselect_async */ };
-static struct list screen_buffer_list = LIST_INIT(screen_buffer_list); - static int queue_host_ioctl( struct console_server *server, unsigned int code, unsigned int output, struct async *async, struct async_queue *queue );
@@ -539,6 +538,7 @@ static struct object *create_console(void) console->server = NULL; console->fd = NULL; console->last_id = 0; + list_init( &console->screen_buffers ); init_async_queue( &console->ioctl_q ); init_async_queue( &console->read_q );
@@ -639,7 +639,7 @@ static struct object *create_screen_buffer( struct console *console ) screen_buffer->id = ++console->last_id; screen_buffer->input = console; init_async_queue( &screen_buffer->ioctl_q ); - list_add_head( &screen_buffer_list, &screen_buffer->entry ); + list_add_head( &console->screen_buffers, &screen_buffer->entry );
screen_buffer->fd = alloc_pseudo_fd( &screen_buffer_fd_ops, &screen_buffer->obj, FILE_SYNCHRONOUS_IO_NONALERT ); @@ -755,10 +755,8 @@ static void console_destroy( struct object *obj ) if (console->active) release_object( console->active ); console->active = NULL;
- LIST_FOR_EACH_ENTRY( curr, &screen_buffer_list, struct screen_buffer, entry ) - { - if (curr->input == console) curr->input = NULL; - } + LIST_FOR_EACH_ENTRY( curr, &console->screen_buffers, struct screen_buffer, entry ) + curr->input = NULL;
free_async_queue( &console->ioctl_q ); free_async_queue( &console->read_q ); @@ -831,10 +829,13 @@ static void screen_buffer_destroy( struct object *obj )
assert( obj->ops == &screen_buffer_ops );
- list_remove( &screen_buffer->entry ); - if (screen_buffer->input && screen_buffer->input->server) - queue_host_ioctl( screen_buffer->input->server, IOCTL_CONDRV_CLOSE_OUTPUT, - screen_buffer->id, NULL, NULL ); + if (screen_buffer->input) + { + list_remove( &screen_buffer->entry ); + if (screen_buffer->input->server) + queue_host_ioctl( screen_buffer->input->server, IOCTL_CONDRV_CLOSE_OUTPUT, + screen_buffer->id, NULL, NULL ); + } if (screen_buffer->fd) release_object( screen_buffer->fd ); free_async_queue( &screen_buffer->ioctl_q ); }
From: Elizabeth Figura zfigura@codeweavers.com
Wait on the handle directly instead of delegating to the console's wait queue. --- dlls/kernel32/tests/console.c | 2 +- server/console.c | 32 ++++++++++++++++---------------- 2 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/dlls/kernel32/tests/console.c b/dlls/kernel32/tests/console.c index 886c1aa876a..28faf01d2ba 100644 --- a/dlls/kernel32/tests/console.c +++ b/dlls/kernel32/tests/console.c @@ -4349,7 +4349,7 @@ static void test_FreeConsole(HANDLE input, HANDLE orig_output) * Windows 11 is weirdly inconsistent; the state seems to be very sensitive * to timing, in unclear ways. */ ret = WaitForSingleObject(output, 0); - todo_wine ok(!ret || ret == WAIT_TIMEOUT, "got %d\n", ret); + ok(!ret || ret == WAIT_TIMEOUT, "got %d\n", ret); ret = WaitForSingleObject(unbound_output, 0); todo_wine ok(!ret || ret == WAIT_TIMEOUT, "got %d\n", ret); ret = WaitForSingleObject(unbound_input, 0); diff --git a/server/console.c b/server/console.c index c081006590d..656abd7706d 100644 --- a/server/console.c +++ b/server/console.c @@ -215,7 +215,7 @@ struct screen_buffer
static void screen_buffer_dump( struct object *obj, int verbose ); static void screen_buffer_destroy( struct object *obj ); -static int screen_buffer_add_queue( struct object *obj, struct wait_queue_entry *entry ); +static int screen_buffer_signaled( struct object *obj, struct wait_queue_entry *entry ); static struct fd *screen_buffer_get_fd( struct object *obj ); static struct object *screen_buffer_open_file( struct object *obj, unsigned int access, unsigned int sharing, unsigned int options ); @@ -225,10 +225,10 @@ static const struct object_ops screen_buffer_ops = sizeof(struct screen_buffer), /* size */ &file_type, /* type */ screen_buffer_dump, /* dump */ - screen_buffer_add_queue, /* add_queue */ - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* satisfied */ + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + screen_buffer_signaled, /* signaled */ + no_satisfied, /* satisfied */ no_signal, /* signal */ screen_buffer_get_fd, /* get_fd */ default_map_access, /* map_access */ @@ -840,21 +840,18 @@ static void screen_buffer_destroy( struct object *obj ) free_async_queue( &screen_buffer->ioctl_q ); }
-static struct object *screen_buffer_open_file( struct object *obj, unsigned int access, - unsigned int sharing, unsigned int options ) +static int screen_buffer_signaled( struct object *obj, struct wait_queue_entry *entry ) { - return grab_object( obj ); + struct screen_buffer *screen_buffer = (struct screen_buffer *)obj; + assert( obj->ops == &screen_buffer_ops ); + if (!screen_buffer->input) return 0; + return screen_buffer->input->signaled; }
-static int screen_buffer_add_queue( struct object *obj, struct wait_queue_entry *entry ) +static struct object *screen_buffer_open_file( struct object *obj, unsigned int access, + unsigned int sharing, unsigned int options ) { - struct screen_buffer *screen_buffer = (struct screen_buffer*)obj; - if (!screen_buffer->input) - { - set_error( STATUS_ACCESS_DENIED ); - return 0; - } - return console_add_queue( &screen_buffer->input->obj, entry ); + return grab_object( obj ); }
static struct fd *screen_buffer_get_fd( struct object *obj ) @@ -1543,6 +1540,7 @@ struct object *create_console_device( struct object *root, const struct unicode_ DECL_HANDLER(get_next_console_request) { struct console_host_ioctl *ioctl = NULL, *next; + struct screen_buffer *screen_buffer; struct console_server *server; struct iosb *iosb = NULL;
@@ -1563,6 +1561,8 @@ DECL_HANDLER(get_next_console_request) { server->console->signaled = 1; wake_up( &server->console->obj, 0 ); + LIST_FOR_EACH_ENTRY( screen_buffer, &server->console->screen_buffers, struct screen_buffer, entry ) + wake_up( &screen_buffer->obj, 0 ); }
if (req->read)
From: Elizabeth Figura zfigura@codeweavers.com
Do not delegate to the current process's queue, either, but use the queue for this object.
I/O acts on the current process's console, but the handle signaled state is the same across all handles to this object, and reflects the signaled state of the console of the process that created the object. --- dlls/kernel32/tests/console.c | 8 ++++---- server/console.c | 34 +++++++++++++++++++++++----------- 2 files changed, 27 insertions(+), 15 deletions(-)
diff --git a/dlls/kernel32/tests/console.c b/dlls/kernel32/tests/console.c index 28faf01d2ba..a0dd1c32c21 100644 --- a/dlls/kernel32/tests/console.c +++ b/dlls/kernel32/tests/console.c @@ -4168,7 +4168,7 @@ static void test_unbound_handles_child(DWORD parent_pid, UINT_PTR parent_input_i ok(ret, "got error %lu\n", GetLastError());
ret = WaitForSingleObject(parent_input, 0); - todo_wine ok(!ret, "got %d\n", ret); + ok(!ret, "got %d\n", ret); ret = WaitForSingleObject(parent_output, 0); todo_wine ok(!ret, "got %d\n", ret);
@@ -4227,7 +4227,7 @@ static void test_unbound_handles_child(DWORD parent_pid, UINT_PTR parent_input_i ok(ret == TRUE, "got error %lu\n", GetLastError());
ret = WaitForSingleObject(unbound_input, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "got %d\n", ret); + ok(ret == WAIT_TIMEOUT, "got %d\n", ret); CloseHandle(unbound_input);
ret = WaitForSingleObject(parent_input, 0); @@ -4241,7 +4241,7 @@ static void test_unbound_handles_child(DWORD parent_pid, UINT_PTR parent_input_i ok(!ret, "got %d\n", ret);
ret = WaitForSingleObject(parent_input, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "got %d\n", ret); + ok(ret == WAIT_TIMEOUT, "got %d\n", ret); ret = WaitForSingleObject(parent_output, 0); todo_wine ok(ret == WAIT_TIMEOUT, "got %d\n", ret); } @@ -4353,7 +4353,7 @@ static void test_FreeConsole(HANDLE input, HANDLE orig_output) ret = WaitForSingleObject(unbound_output, 0); todo_wine ok(!ret || ret == WAIT_TIMEOUT, "got %d\n", ret); ret = WaitForSingleObject(unbound_input, 0); - todo_wine ok(!ret || ret == WAIT_TIMEOUT, "got %d\n", ret); + ok(!ret || ret == WAIT_TIMEOUT, "got %d\n", ret);
/* Create a new console. * diff --git a/server/console.c b/server/console.c index 656abd7706d..918a91a7b2f 100644 --- a/server/console.c +++ b/server/console.c @@ -62,6 +62,7 @@ struct console struct async_queue ioctl_q; /* ioctl queue */ struct async_queue read_q; /* read queue */ struct list screen_buffers;/* attached screen buffers */ + struct list inputs; /* attached console inputs */ };
static void console_dump( struct object *obj, int verbose ); @@ -297,12 +298,14 @@ struct console_input { struct object obj; /* object header */ struct fd *fd; /* pseudo-fd */ + struct list entry; /* entry in console->inputs */ + struct console *console; /* associated console at creation time */ };
static void console_input_dump( struct object *obj, int verbose ); +static int console_input_signaled( struct object *obj, struct wait_queue_entry *entry ); static struct object *console_input_open_file( struct object *obj, unsigned int access, unsigned int sharing, unsigned int options ); -static int console_input_add_queue( struct object *obj, struct wait_queue_entry *entry ); static struct fd *console_input_get_fd( struct object *obj ); static void console_input_destroy( struct object *obj );
@@ -311,9 +314,9 @@ static const struct object_ops console_input_ops = sizeof(struct console_input), /* size */ &device_type, /* type */ console_input_dump, /* dump */ - console_input_add_queue, /* add_queue */ - NULL, /* remove_queue */ - NULL, /* signaled */ + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + console_input_signaled, /* signaled */ no_satisfied, /* satisfied */ no_signal, /* signal */ console_input_get_fd, /* get_fd */ @@ -539,6 +542,7 @@ static struct object *create_console(void) console->fd = NULL; console->last_id = 0; list_init( &console->screen_buffers ); + list_init( &console->inputs ); init_async_queue( &console->ioctl_q ); init_async_queue( &console->read_q );
@@ -742,6 +746,7 @@ static void console_dump( struct object *obj, int verbose ) static void console_destroy( struct object *obj ) { struct console *console = (struct console *)obj; + struct console_input *input; struct screen_buffer *curr;
assert( obj->ops == &console_ops ); @@ -758,6 +763,9 @@ static void console_destroy( struct object *obj ) LIST_FOR_EACH_ENTRY( curr, &console->screen_buffers, struct screen_buffer, entry ) curr->input = NULL;
+ LIST_FOR_EACH_ENTRY( input, &console->inputs, struct console_input, entry ) + input->console = NULL; + free_async_queue( &console->ioctl_q ); free_async_queue( &console->read_q ); if (console->fd) @@ -1328,6 +1336,8 @@ static struct object *console_device_lookup_name( struct object *obj, struct uni release_object( console_input ); return NULL; } + console_input->console = current->process->console; + list_add_head( ¤t->process->console->inputs, &console_input->entry ); return &console_input->obj; }
@@ -1403,14 +1413,12 @@ static void console_input_dump( struct object *obj, int verbose ) fputs( "console Input device\n", stderr ); }
-static int console_input_add_queue( struct object *obj, struct wait_queue_entry *entry ) +static int console_input_signaled( struct object *obj, struct wait_queue_entry *entry ) { - if (!current->process->console) - { - set_error( STATUS_ACCESS_DENIED ); - return 0; - } - return console_add_queue( ¤t->process->console->obj, entry ); + struct console_input *console_input = (struct console_input *)obj; + assert( obj->ops == &console_input_ops ); + if (!console_input->console) return 0; + return console_input->console->signaled; }
static struct fd *console_input_get_fd( struct object *obj ) @@ -1432,6 +1440,7 @@ static void console_input_destroy( struct object *obj )
assert( obj->ops == &console_input_ops ); if (console_input->fd) release_object( console_input->fd ); + if (console_input->console) list_remove( &console_input->entry ); }
static void console_input_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) @@ -1542,6 +1551,7 @@ DECL_HANDLER(get_next_console_request) struct console_host_ioctl *ioctl = NULL, *next; struct screen_buffer *screen_buffer; struct console_server *server; + struct console_input *input; struct iosb *iosb = NULL;
server = (struct console_server *)get_handle_obj( current->process, req->handle, 0, &console_server_ops ); @@ -1563,6 +1573,8 @@ DECL_HANDLER(get_next_console_request) wake_up( &server->console->obj, 0 ); LIST_FOR_EACH_ENTRY( screen_buffer, &server->console->screen_buffers, struct screen_buffer, entry ) wake_up( &screen_buffer->obj, 0 ); + LIST_FOR_EACH_ENTRY( input, &server->console->inputs, struct console_input, entry ) + wake_up( &input->obj, 0 ); }
if (req->read)
From: Elizabeth Figura zfigura@codeweavers.com
Do not delegate to the current process's queue, either, but use the queue for this object.
I/O acts on the current process's console, but the handle signaled state is the same across all handles to this object, and reflects the signaled state of the console of the process that created the object. --- dlls/kernel32/tests/console.c | 6 +++--- server/console.c | 34 +++++++++++++++++++++++----------- 2 files changed, 26 insertions(+), 14 deletions(-)
diff --git a/dlls/kernel32/tests/console.c b/dlls/kernel32/tests/console.c index a0dd1c32c21..32cf7f971e0 100644 --- a/dlls/kernel32/tests/console.c +++ b/dlls/kernel32/tests/console.c @@ -4170,7 +4170,7 @@ static void test_unbound_handles_child(DWORD parent_pid, UINT_PTR parent_input_i ret = WaitForSingleObject(parent_input, 0); ok(!ret, "got %d\n", ret); ret = WaitForSingleObject(parent_output, 0); - todo_wine ok(!ret, "got %d\n", ret); + ok(!ret, "got %d\n", ret);
ret = PeekConsoleInputW(parent_input, &ir, 1, &count); ok(!ret, "got %d\n", ret); @@ -4243,7 +4243,7 @@ static void test_unbound_handles_child(DWORD parent_pid, UINT_PTR parent_input_i ret = WaitForSingleObject(parent_input, 0); ok(ret == WAIT_TIMEOUT, "got %d\n", ret); ret = WaitForSingleObject(parent_output, 0); - todo_wine ok(ret == WAIT_TIMEOUT, "got %d\n", ret); + ok(ret == WAIT_TIMEOUT, "got %d\n", ret); }
static void test_FreeConsole(HANDLE input, HANDLE orig_output) @@ -4351,7 +4351,7 @@ static void test_FreeConsole(HANDLE input, HANDLE orig_output) ret = WaitForSingleObject(output, 0); ok(!ret || ret == WAIT_TIMEOUT, "got %d\n", ret); ret = WaitForSingleObject(unbound_output, 0); - todo_wine ok(!ret || ret == WAIT_TIMEOUT, "got %d\n", ret); + ok(!ret || ret == WAIT_TIMEOUT, "got %d\n", ret); ret = WaitForSingleObject(unbound_input, 0); ok(!ret || ret == WAIT_TIMEOUT, "got %d\n", ret);
diff --git a/server/console.c b/server/console.c index 918a91a7b2f..de6f4e73e31 100644 --- a/server/console.c +++ b/server/console.c @@ -63,6 +63,7 @@ struct console struct async_queue read_q; /* read queue */ struct list screen_buffers;/* attached screen buffers */ struct list inputs; /* attached console inputs */ + struct list outputs; /* attached console outputs */ };
static void console_dump( struct object *obj, int verbose ); @@ -357,10 +358,12 @@ struct console_output { struct object obj; /* object header */ struct fd *fd; /* pseudo-fd */ + struct list entry; /* entry in console->outputs */ + struct console *console; /* associated console at creation time */ };
static void console_output_dump( struct object *obj, int verbose ); -static int console_output_add_queue( struct object *obj, struct wait_queue_entry *entry ); +static int console_output_signaled( struct object *obj, struct wait_queue_entry *entry ); static struct fd *console_output_get_fd( struct object *obj ); static struct object *console_output_open_file( struct object *obj, unsigned int access, unsigned int sharing, unsigned int options ); @@ -371,9 +374,9 @@ static const struct object_ops console_output_ops = sizeof(struct console_output), /* size */ &device_type, /* type */ console_output_dump, /* dump */ - console_output_add_queue, /* add_queue */ - NULL, /* remove_queue */ - NULL, /* signaled */ + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + console_output_signaled, /* signaled */ no_satisfied, /* satisfied */ no_signal, /* signal */ console_output_get_fd, /* get_fd */ @@ -543,6 +546,7 @@ static struct object *create_console(void) console->last_id = 0; list_init( &console->screen_buffers ); list_init( &console->inputs ); + list_init( &console->outputs ); init_async_queue( &console->ioctl_q ); init_async_queue( &console->read_q );
@@ -746,6 +750,7 @@ static void console_dump( struct object *obj, int verbose ) static void console_destroy( struct object *obj ) { struct console *console = (struct console *)obj; + struct console_output *output; struct console_input *input; struct screen_buffer *curr;
@@ -766,6 +771,9 @@ static void console_destroy( struct object *obj ) LIST_FOR_EACH_ENTRY( input, &console->inputs, struct console_input, entry ) input->console = NULL;
+ LIST_FOR_EACH_ENTRY( output, &console->outputs, struct console_output, entry ) + output->console = NULL; + free_async_queue( &console->ioctl_q ); free_async_queue( &console->read_q ); if (console->fd) @@ -1360,6 +1368,8 @@ static struct object *console_device_lookup_name( struct object *obj, struct uni release_object( console_output ); return NULL; } + console_output->console = current->process->console; + list_add_head( ¤t->process->console->outputs, &console_output->entry ); return &console_output->obj; }
@@ -1484,14 +1494,12 @@ static void console_output_dump( struct object *obj, int verbose ) fputs( "console Output device\n", stderr ); }
-static int console_output_add_queue( struct object *obj, struct wait_queue_entry *entry ) +static int console_output_signaled( struct object *obj, struct wait_queue_entry *entry ) { - if (!current->process->console || !current->process->console->active) - { - set_error( STATUS_ACCESS_DENIED ); - return 0; - } - return console_add_queue( ¤t->process->console->obj, entry ); + struct console_output *console_output = (struct console_output *)obj; + assert( obj->ops == &console_output_ops ); + if (!console_output->console) return 0; + return console_output->console->signaled; }
static struct fd *console_output_get_fd( struct object *obj ) @@ -1513,6 +1521,7 @@ static void console_output_destroy( struct object *obj )
assert( obj->ops == &console_output_ops ); if (console_output->fd) release_object( console_output->fd ); + if (console_output->console) list_remove( &console_output->entry ); }
static void console_output_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) @@ -1551,6 +1560,7 @@ DECL_HANDLER(get_next_console_request) struct console_host_ioctl *ioctl = NULL, *next; struct screen_buffer *screen_buffer; struct console_server *server; + struct console_output *output; struct console_input *input; struct iosb *iosb = NULL;
@@ -1575,6 +1585,8 @@ DECL_HANDLER(get_next_console_request) wake_up( &screen_buffer->obj, 0 ); LIST_FOR_EACH_ENTRY( input, &server->console->inputs, struct console_input, entry ) wake_up( &input->obj, 0 ); + LIST_FOR_EACH_ENTRY( output, &server->console->outputs, struct console_output, entry ) + wake_up( &output->obj, 0 ); }
if (req->read)
From: Elizabeth Figura zfigura@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57951 --- dlls/wined3d/glsl_shader.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index b2e89704933..a875501a147 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -8052,6 +8052,7 @@ static GLuint shader_glsl_generate_fragment_shader(const struct wined3d_context_ shader_addline(buffer, "vpos = floor(gl_FragCoord);\n"); else shader_addline(buffer, "vpos = gl_FragCoord;\n"); + shader_addline(buffer, "vpos.w = 1 / vpos.w;\n"); }
if (reg_maps->shader_version.major < 3 || args->vp_mode != WINED3D_VP_MODE_SHADER)
From: Elizabeth Figura zfigura@codeweavers.com
Fixes red objects in Ultrakill. --- dlls/wined3d/adapter_vk.c | 1 + dlls/wined3d/shader_spirv.c | 29 +++++++++++++++++++---------- dlls/wined3d/wined3d_vk.h | 1 + 3 files changed, 21 insertions(+), 10 deletions(-)
diff --git a/dlls/wined3d/adapter_vk.c b/dlls/wined3d/adapter_vk.c index 8219c0728d4..ca11ec480d2 100644 --- a/dlls/wined3d/adapter_vk.c +++ b/dlls/wined3d/adapter_vk.c @@ -2366,6 +2366,7 @@ static void wined3d_adapter_vk_init_d3d_info(struct wined3d_adapter_vk *adapter_ d3d_info->multisample_draw_location = WINED3D_LOCATION_TEXTURE_RGB;
vk_info->multiple_viewports = device_info.features2.features.multiViewport; + vk_info->uav_read_without_format = device_info.features2.features.shaderStorageImageReadWithoutFormat; vk_info->dynamic_state2 = device_info.dynamic_state2_features.extendedDynamicState2; vk_info->dynamic_patch_vertex_count = device_info.dynamic_state2_features.extendedDynamicState2PatchControlPoints;
diff --git a/dlls/wined3d/shader_spirv.c b/dlls/wined3d/shader_spirv.c index 51cfe58e255..e7deabfa14e 100644 --- a/dlls/wined3d/shader_spirv.c +++ b/dlls/wined3d/shader_spirv.c @@ -24,12 +24,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
static const struct wined3d_shader_backend_ops spirv_shader_backend_vk;
-static const struct vkd3d_shader_compile_option spirv_compile_options[] = -{ - {VKD3D_SHADER_COMPILE_OPTION_API_VERSION, VKD3D_SHADER_API_VERSION_1_7}, - {VKD3D_SHADER_COMPILE_OPTION_WRITE_TESS_GEOM_POINT_SIZE, 0}, -}; - struct shader_spirv_resource_bindings { struct vkd3d_shader_resource_binding *bindings; @@ -53,6 +47,8 @@ struct shader_spirv_priv const struct wined3d_fragment_pipe_ops *fragment_pipe;
struct shader_spirv_resource_bindings bindings; + + struct vkd3d_shader_compile_option compile_options[3]; };
#define MAX_SM1_INTER_STAGE_VARYINGS 12 @@ -281,6 +277,7 @@ static VkShaderModule shader_spirv_compile_shader(struct wined3d_context_vk *con const struct shader_spirv_resource_bindings *bindings, const struct wined3d_stream_output_desc *so_desc) { struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device); + const struct shader_spirv_priv *priv = device_vk->d.shader_priv; const struct wined3d_vk_info *vk_info = &device_vk->vk_info; struct wined3d_shader_spirv_compile_args compile_args; struct wined3d_shader_spirv_shader_interface iface; @@ -302,8 +299,8 @@ static VkShaderModule shader_spirv_compile_shader(struct wined3d_context_vk *con info.source.size = shader_desc->byte_code_size; info.source_type = source_type; info.target_type = VKD3D_SHADER_TARGET_SPIRV_BINARY; - info.options = spirv_compile_options; - info.option_count = ARRAY_SIZE(spirv_compile_options); + info.options = priv->compile_options; + info.option_count = ARRAY_SIZE(priv->compile_options); info.log_level = VKD3D_SHADER_LOG_WARNING; info.source_name = NULL;
@@ -760,6 +757,7 @@ static void shader_spirv_scan_shader(struct wined3d_shader *shader, struct vkd3d_shader_scan_descriptor_info *descriptor_info, struct vkd3d_shader_scan_signature_info *signature_info) { + const struct shader_spirv_priv *priv = shader->device->shader_priv; struct vkd3d_shader_compile_info info; char *messages; int ret; @@ -788,8 +786,8 @@ static void shader_spirv_scan_shader(struct wined3d_shader *shader, } info.source_type = shader->source_type; info.target_type = VKD3D_SHADER_TARGET_SPIRV_BINARY; - info.options = spirv_compile_options; - info.option_count = ARRAY_SIZE(spirv_compile_options); + info.options = priv->compile_options; + info.option_count = ARRAY_SIZE(priv->compile_options); info.log_level = VKD3D_SHADER_LOG_WARNING; info.source_name = NULL;
@@ -1056,6 +1054,7 @@ static void shader_spirv_destroy(struct wined3d_shader *shader) static HRESULT shader_spirv_alloc(struct wined3d_device *device, const struct wined3d_vertex_pipe_ops *vertex_pipe, const struct wined3d_fragment_pipe_ops *fragment_pipe) { + const struct wined3d_vk_info *vk_info = &wined3d_adapter_vk(device->adapter)->vk_info; void *vertex_priv, *fragment_priv; struct shader_spirv_priv *priv;
@@ -1085,6 +1084,16 @@ static HRESULT shader_spirv_alloc(struct wined3d_device *device, device->fragment_priv = fragment_priv; device->shader_priv = priv;
+ priv->compile_options[0].name = VKD3D_SHADER_COMPILE_OPTION_API_VERSION; + priv->compile_options[0].value = VKD3D_SHADER_API_VERSION_1_7; + priv->compile_options[1].name = VKD3D_SHADER_COMPILE_OPTION_WRITE_TESS_GEOM_POINT_SIZE; + priv->compile_options[1].value = 0; + priv->compile_options[2].name = VKD3D_SHADER_COMPILE_OPTION_TYPED_UAV; + if (vk_info->uav_read_without_format) + priv->compile_options[2].value = VKD3D_SHADER_COMPILE_OPTION_TYPED_UAV_READ_FORMAT_UNKNOWN; + else + priv->compile_options[2].value = VKD3D_SHADER_COMPILE_OPTION_TYPED_UAV_READ_FORMAT_R32; + return WINED3D_OK; }
diff --git a/dlls/wined3d/wined3d_vk.h b/dlls/wined3d/wined3d_vk.h index fcc275490c7..f51acf8b0f4 100644 --- a/dlls/wined3d/wined3d_vk.h +++ b/dlls/wined3d/wined3d_vk.h @@ -277,6 +277,7 @@ struct wined3d_vk_info bool dynamic_multisample_state; bool dynamic_blend_state; bool dynamic_rasterizer_state; + bool uav_read_without_format; };
#define VK_CALL(f) (vk_info->vk_ops.f)