Keno Fischer : kernel32: Fix RegisterWaitForSingleObject for console handles.

Alexandre Julliard julliard at winehq.org
Fri Aug 19 08:19:05 CDT 2016


Module: wine
Branch: master
Commit: ccc1d346a6cd4f2d12b6ce1c2f6bdcd92f8a0bf3
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=ccc1d346a6cd4f2d12b6ce1c2f6bdcd92f8a0bf3

Author: Keno Fischer <keno at juliacomputing.com>
Date:   Tue Aug 16 14:35:27 2016 -0400

kernel32: Fix RegisterWaitForSingleObject for console handles.

Signed-off-by: Keno Fischer <keno at juliacomputing.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/kernel32/sync.c          | 37 +++++++++++++++--------------
 dlls/kernel32/tests/console.c | 54 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 74 insertions(+), 17 deletions(-)

diff --git a/dlls/kernel32/sync.c b/dlls/kernel32/sync.c
index c10fd01..b8222db 100644
--- a/dlls/kernel32/sync.c
+++ b/dlls/kernel32/sync.c
@@ -148,6 +148,23 @@ DWORD WINAPI WaitForMultipleObjects( DWORD count, const HANDLE *handles,
     return WaitForMultipleObjectsEx( count, handles, wait_all, timeout, FALSE );
 }
 
+static HANDLE normalize_handle_if_console(HANDLE handle)
+{
+    if ((handle == (HANDLE)STD_INPUT_HANDLE) ||
+        (handle == (HANDLE)STD_OUTPUT_HANDLE) ||
+        (handle == (HANDLE)STD_ERROR_HANDLE))
+        handle = GetStdHandle( HandleToULong(handle) );
+
+    /* yes, even screen buffer console handles are waitable, and are
+     * handled as a handle to the console itself !!
+     */
+    if (is_console_handle(handle))
+    {
+        if (VerifyConsoleIoHandle(handle))
+            handle = GetConsoleInputWaitHandle();
+    }
+    return handle;
+}
 
 /***********************************************************************
  *           WaitForMultipleObjectsEx   (KERNEL32.@)
@@ -167,23 +184,7 @@ DWORD WINAPI WaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
         return WAIT_FAILED;
     }
     for (i = 0; i < count; i++)
-    {
-        if ((handles[i] == (HANDLE)STD_INPUT_HANDLE) ||
-            (handles[i] == (HANDLE)STD_OUTPUT_HANDLE) ||
-            (handles[i] == (HANDLE)STD_ERROR_HANDLE))
-            hloc[i] = GetStdHandle( HandleToULong(handles[i]) );
-        else
-            hloc[i] = handles[i];
-
-        /* yes, even screen buffer console handles are waitable, and are
-         * handled as a handle to the console itself !!
-         */
-        if (is_console_handle(hloc[i]))
-        {
-            if (VerifyConsoleIoHandle(hloc[i]))
-                hloc[i] = GetConsoleInputWaitHandle();
-        }
-    }
+        hloc[i] = normalize_handle_if_console(handles[i]);
 
     status = NtWaitForMultipleObjects( count, hloc, !wait_all, alertable,
                                        get_nt_timeout( &time, timeout ) );
@@ -209,6 +210,7 @@ BOOL WINAPI RegisterWaitForSingleObject(PHANDLE phNewWaitObject, HANDLE hObject,
     TRACE("%p %p %p %p %d %d\n",
           phNewWaitObject,hObject,Callback,Context,dwMilliseconds,dwFlags);
 
+    hObject = normalize_handle_if_console(hObject);
     status = RtlRegisterWait( phNewWaitObject, hObject, Callback, Context, dwMilliseconds, dwFlags );
     if (status != STATUS_SUCCESS)
     {
@@ -231,6 +233,7 @@ HANDLE WINAPI RegisterWaitForSingleObjectEx( HANDLE hObject,
     TRACE("%p %p %p %d %d\n",
           hObject,Callback,Context,dwMilliseconds,dwFlags);
 
+    hObject = normalize_handle_if_console(hObject);
     status = RtlRegisterWait( &hNewWaitObject, hObject, Callback, Context, dwMilliseconds, dwFlags );
     if (status != STATUS_SUCCESS)
     {
diff --git a/dlls/kernel32/tests/console.c b/dlls/kernel32/tests/console.c
index 24f15d4..c88db6a 100644
--- a/dlls/kernel32/tests/console.c
+++ b/dlls/kernel32/tests/console.c
@@ -908,6 +908,58 @@ static void testScreenBuffer(HANDLE hConOut)
     SetConsoleOutputCP(oldcp);
 }
 
+static void CALLBACK signaled_function(void *p, BOOLEAN timeout)
+{
+    HANDLE event = p;
+    SetEvent(event);
+    ok(!timeout, "wait shouldn't have timed out\n");
+}
+
+static void testWaitForConsoleInput(HANDLE input_handle)
+{
+    HANDLE wait_handle;
+    HANDLE complete_event;
+    INPUT_RECORD record;
+    DWORD events_written;
+    DWORD wait_ret;
+    BOOL ret;
+
+    complete_event = CreateEventW(NULL, FALSE, FALSE, NULL);
+
+    /* Test success case */
+    ret = RegisterWaitForSingleObject(&wait_handle, input_handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
+    ok(ret == TRUE, "Expected RegisterWaitForSingleObject to return TRUE, got %d\n", ret);
+    /* give worker thread a chance to start up */
+    Sleep(100);
+    record.EventType = KEY_EVENT;
+    record.Event.KeyEvent.bKeyDown = 1;
+    record.Event.KeyEvent.wRepeatCount = 1;
+    record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
+    record.Event.KeyEvent.wVirtualScanCode = VK_RETURN;
+    record.Event.KeyEvent.uChar.UnicodeChar = '\r';
+    record.Event.KeyEvent.dwControlKeyState = 0;
+    ret = WriteConsoleInputW(input_handle, &record, 1, &events_written);
+    ok(ret == TRUE, "Expected WriteConsoleInputW to return TRUE, got %d\n", ret);
+    wait_ret = WaitForSingleObject(complete_event, INFINITE);
+    ok(wait_ret == WAIT_OBJECT_0, "Expected the handle to be signaled\n");
+    ret = UnregisterWait(wait_handle);
+    /* If the callback is still running, this fails with ERROR_IO_PENDING, but
+       that's ok and expected. */
+    ok(ret != 0 || GetLastError() == ERROR_IO_PENDING,
+        "UnregisterWait failed with error %d\n", GetLastError());
+
+    /* Test timeout case */
+    FlushConsoleInputBuffer(input_handle);
+    ret = RegisterWaitForSingleObject(&wait_handle, input_handle, signaled_function, complete_event, INFINITE, WT_EXECUTEONLYONCE);
+    wait_ret = WaitForSingleObject(complete_event, 100);
+    ok(wait_ret == WAIT_TIMEOUT, "Expected the wait to time out\n");
+    ret = UnregisterWait(wait_handle);
+    ok(ret, "UnregisterWait failed with error %d\n", GetLastError());
+
+    /* Clean up */
+    ok(CloseHandle(complete_event), "Failed to close event handle, last error %d\n", GetLastError());
+}
+
 static void test_GetSetConsoleInputExeName(void)
 {
     BOOL ret;
@@ -3093,6 +3145,8 @@ START_TEST(console)
     testScroll(hConOut, sbi.dwSize);
     /* will test sb creation / modification / codepage handling */
     testScreenBuffer(hConOut);
+    /* Test waiting for a console handle */
+    testWaitForConsoleInput(hConIn);
 
     /* clear duplicated console font table */
     CloseHandle(hConIn);




More information about the wine-cvs mailing list