[KERNEL32_WINETEST] Sync with Wine Staging 2.9. CORE-13362
authorAmine Khaldi <amine.khaldi@reactos.org>
Sun, 4 Jun 2017 14:29:15 +0000 (14:29 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sun, 4 Jun 2017 14:29:15 +0000 (14:29 +0000)
svn path=/trunk/; revision=74908

15 files changed:
rostests/winetests/kernel32/actctx.c
rostests/winetests/kernel32/codepage.c
rostests/winetests/kernel32/console.c
rostests/winetests/kernel32/debugger.c
rostests/winetests/kernel32/directory.c
rostests/winetests/kernel32/file.c
rostests/winetests/kernel32/format_msg.c
rostests/winetests/kernel32/heap.c
rostests/winetests/kernel32/loader.c
rostests/winetests/kernel32/locale.c
rostests/winetests/kernel32/pipe.c
rostests/winetests/kernel32/process.c
rostests/winetests/kernel32/thread.c
rostests/winetests/kernel32/version.c
rostests/winetests/kernel32/virtual.c

index 8120dde..e8a2cdf 100644 (file)
@@ -244,6 +244,61 @@ static const char manifest5[] =
 "</dependency>"
 "</assembly>";
 
+static const char manifest6[] =
+"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
+"<assemblyIdentity version=\"1.0.0.0\"  name=\"Wine.Test\" type=\"win32\"></assemblyIdentity>"
+"<trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v1\">"
+"    <security>"
+"        <requestedPrivileges>"
+"            <requestedExecutionLevel level=\"ASINVOKER\" uiAccess=\"false\"/>"
+"        </requestedPrivileges>"
+"    </security>"
+"</trustInfo>"
+"</assembly>";
+
+static const char manifest7[] =
+"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
+"<assemblyIdentity version=\"1.0.0.0\"  name=\"Wine.Test\" type=\"win32\"></assemblyIdentity>"
+"<trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v2\">"
+"    <security>"
+"        <requestedPrivileges>"
+"            <requestedExecutionLevel level=\"requireAdministrator\" uiAccess=\"TRUE\"/>"
+"        </requestedPrivileges>"
+"    </security>"
+"</trustInfo>"
+"</assembly>";
+
+static const char manifest8[] =
+"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
+"<assemblyIdentity version=\"1.0.0.0\"  name=\"Wine.Test\" type=\"win32\"></assemblyIdentity>"
+"<trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v2\">"
+"    <security>"
+"        <requestedPrivileges>"
+"            <requestedExecutionLevel level=\"requireAdministrator\" uiAccess=\"true\">"
+"            </requestedExecutionLevel>"
+"        </requestedPrivileges>"
+"    </security>"
+"</trustInfo>"
+"</assembly>";
+
+static const char manifest9[] =
+"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
+"<assemblyIdentity version=\"1.0.0.0\"  name=\"Wine.Test\" type=\"win32\"></assemblyIdentity>"
+"<trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v2\">"
+"    <security>"
+"        <requestedPrivileges>"
+"            <requestedExecutionLevel level=\"requireAdministrator\"/>"
+"        </requestedPrivileges>"
+"    </security>"
+"</trustInfo>"
+"<trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v2\">"
+"    <security>"
+"        <requestedPrivileges>"
+"        </requestedPrivileges>"
+"    </security>"
+"</trustInfo>"
+"</assembly>";
+
 static const char testdep_manifest1[] =
 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
 "<assemblyIdentity type=\"win32\" name=\"testdep\" version=\"6.5.4.3\" processorArchitecture=\"" ARCH "\"/>"
@@ -310,6 +365,38 @@ static const char wrong_manifest8[] =
 "<file></file>"
 "</assembly>";
 
+static const char wrong_manifest9[] =
+"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
+"<assemblyIdentity version=\"1.0.0.0\"  name=\"Wine.Test\" type=\"win32\"></assemblyIdentity>"
+"<trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v2\">"
+"    <security>"
+"        <requestedPrivileges>"
+"            <requestedExecutionLevel level=\"requireAdministrator\"/>"
+"            <requestedExecutionLevel uiAccess=\"true\"/>"
+"        </requestedPrivileges>"
+"    </security>"
+"</trustInfo>"
+"</assembly>";
+
+static const char wrong_manifest10[] =
+"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
+"<assemblyIdentity version=\"1.0.0.0\"  name=\"Wine.Test\" type=\"win32\"></assemblyIdentity>"
+"<trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v2\">"
+"    <security>"
+"        <requestedPrivileges>"
+"            <requestedExecutionLevel level=\"requireAdministrator\"/>"
+"        </requestedPrivileges>"
+"    </security>"
+"</trustInfo>"
+"<trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v2\">"
+"    <security>"
+"        <requestedPrivileges>"
+"            <requestedExecutionLevel uiAccess=\"true\"/>"
+"        </requestedPrivileges>"
+"    </security>"
+"</trustInfo>"
+"</assembly>";
+
 static const char wrong_depmanifest1[] =
 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
 "<assemblyIdentity type=\"win32\" name=\"testdep\" version=\"6.5.4.4\" processorArchitecture=\"" ARCH "\" />"
@@ -732,6 +819,57 @@ static void test_file_info(HANDLE handle, ULONG assid, ULONG fileid, LPCWSTR fil
     HeapFree(GetProcessHeap(), 0, info);
 }
 
+typedef struct {
+    ACTCTX_REQUESTED_RUN_LEVEL run_level;
+    DWORD ui_access;
+} runlevel_info_t;
+
+static const runlevel_info_t runlevel_info0 = {
+    ACTCTX_RUN_LEVEL_UNSPECIFIED, FALSE,
+};
+
+static const runlevel_info_t runlevel_info6 = {
+    ACTCTX_RUN_LEVEL_AS_INVOKER, FALSE,
+};
+
+static const runlevel_info_t runlevel_info7 = {
+    ACTCTX_RUN_LEVEL_REQUIRE_ADMIN, TRUE,
+};
+
+static const runlevel_info_t runlevel_info8 = {
+    ACTCTX_RUN_LEVEL_REQUIRE_ADMIN, TRUE,
+};
+
+static const runlevel_info_t runlevel_info9 = {
+    ACTCTX_RUN_LEVEL_REQUIRE_ADMIN, FALSE,
+};
+
+static void test_runlevel_info(HANDLE handle, const runlevel_info_t *exinfo, int line)
+{
+    ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION runlevel_info;
+    SIZE_T size, retsize;
+    BOOL b;
+
+    size = sizeof(runlevel_info);
+    b = pQueryActCtxW(0, handle, NULL,
+                      RunlevelInformationInActivationContext, &runlevel_info,
+                      sizeof(runlevel_info), &retsize);
+    if (!b && GetLastError() == ERROR_INVALID_PARAMETER)
+    {
+        win_skip("RunlevelInformationInActivationContext not supported.\n");
+        return;
+    }
+
+    ok_(__FILE__, line)(b, "QueryActCtx failed: %u\n", GetLastError());
+    ok_(__FILE__, line)(retsize == size, "size=%ld, expected %ld\n", retsize, size);
+
+    ok_(__FILE__, line)(runlevel_info.ulFlags == 0, "runlevel_info.ulFlags=%x\n", runlevel_info.ulFlags);
+    ok_(__FILE__, line)(runlevel_info.RunLevel == exinfo->run_level,
+       "runlevel_info.RunLevel=%u, expected %u\n", runlevel_info.RunLevel, exinfo->run_level);
+    ok_(__FILE__, line)(runlevel_info.UiAccess == exinfo->ui_access,
+       "runlevel_info.UiAccess=%u, expected %u\n", runlevel_info.UiAccess, exinfo->ui_access);
+}
+
 static HANDLE test_create(const char *file)
 {
     ACTCTXW actctx;
@@ -837,6 +975,10 @@ static void test_create_fail(void)
     test_create_and_fail(wrong_manifest7, NULL, 1 );
     trace("wrong_manifest8\n");
     test_create_and_fail(wrong_manifest8, NULL, 0 );
+    trace("wrong_manifest9\n");
+    test_create_and_fail(wrong_manifest9, NULL, 0 );
+    trace("wrong_manifest10\n");
+    test_create_and_fail(wrong_manifest10, NULL, 0 );
     trace("UTF-16 manifest1 without BOM\n");
     test_create_wide_and_fail(manifest1, FALSE );
     trace("manifest2\n");
@@ -1784,6 +1926,7 @@ static void test_actctx(void)
     if(b) {
         test_basic_info(handle, __LINE__);
         test_detailed_info(handle, &detailed_info0, __LINE__);
+        test_runlevel_info(handle, &runlevel_info0, __LINE__);
         pReleaseActCtx(handle);
     }
 
@@ -1955,6 +2098,70 @@ static void test_actctx(void)
         pReleaseActCtx(handle);
     }
 
+    trace("manifest6\n");
+
+    if(create_manifest_file("test6.manifest", manifest6, -1, NULL, NULL)) {
+        handle = test_create("test6.manifest");
+        ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError());
+        DeleteFileA("test6.manifest");
+        DeleteFileA("testdep.manifest");
+        if(handle != INVALID_HANDLE_VALUE)
+        {
+            test_runlevel_info(handle, &runlevel_info6, __LINE__);
+            pReleaseActCtx(handle);
+        }
+    }
+    else
+        skip("Could not create manifest file 6\n");
+
+    trace("manifest7\n");
+
+    if(create_manifest_file("test7.manifest", manifest7, -1, NULL, NULL)) {
+        handle = test_create("test7.manifest");
+        ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError());
+        DeleteFileA("test7.manifest");
+        DeleteFileA("testdep.manifest");
+        if(handle != INVALID_HANDLE_VALUE)
+        {
+            test_runlevel_info(handle, &runlevel_info7, __LINE__);
+            pReleaseActCtx(handle);
+        }
+    }
+    else
+        skip("Could not create manifest file 7\n");
+
+    trace("manifest8\n");
+
+    if(create_manifest_file("test8.manifest", manifest8, -1, NULL, NULL)) {
+        handle = test_create("test8.manifest");
+        ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError());
+        DeleteFileA("test8.manifest");
+        DeleteFileA("testdep.manifest");
+        if(handle != INVALID_HANDLE_VALUE)
+        {
+            test_runlevel_info(handle, &runlevel_info8, __LINE__);
+            pReleaseActCtx(handle);
+        }
+    }
+    else
+        skip("Could not create manifest file 8\n");
+
+    trace("manifest9\n");
+
+    if(create_manifest_file("test9.manifest", manifest9, -1, NULL, NULL)) {
+        handle = test_create("test9.manifest");
+        ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError());
+        DeleteFileA("test9.manifest");
+        DeleteFileA("testdep.manifest");
+        if(handle != INVALID_HANDLE_VALUE)
+        {
+            test_runlevel_info(handle, &runlevel_info9, __LINE__);
+            pReleaseActCtx(handle);
+        }
+    }
+    else
+        skip("Could not create manifest file 9\n");
+
     trace("manifest4\n");
 
     if(!create_manifest_file("test4.manifest", manifest4, -1, NULL, NULL)) {
index c98766e..ac8b902 100755 (executable)
@@ -209,6 +209,40 @@ static void test_other_invalid_parameters(void)
     BOOL used;
     INT len;
 
+    /* Unrecognized flag => ERROR_INVALID_FLAGS */
+    SetLastError(0xdeadbeef);
+    len = WideCharToMultiByte(CP_ACP, 0x100, w_string, -1, c_string, c_string_len, NULL, NULL);
+    ok(len == 0 && GetLastError() == ERROR_INVALID_FLAGS, "len=%d error=%x\n", len, GetLastError());
+
+    SetLastError(0xdeadbeef);
+    len = WideCharToMultiByte(CP_ACP, 0x800, w_string, -1, c_string, c_string_len, NULL, NULL);
+    ok(len == 0 && GetLastError() == ERROR_INVALID_FLAGS, "len=%d error=%x\n", len, GetLastError());
+
+    SetLastError(0xdeadbeef);
+    len = MultiByteToWideChar(CP_ACP, 0x10, c_string, -1, w_string, w_string_len);
+    ok(len == 0 && GetLastError() == ERROR_INVALID_FLAGS, "len=%d error=%x\n", len, GetLastError());
+
+
+    /* Unrecognized flag and invalid codepage => ERROR_INVALID_PARAMETER */
+    SetLastError(0xdeadbeef);
+    len = WideCharToMultiByte(0xdeadbeef, 0x100, w_string, w_string_len, c_string, c_string_len, NULL, NULL);
+    ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
+
+    SetLastError(0xdeadbeef);
+    len = MultiByteToWideChar(0xdeadbeef, 0x10, c_string, c_string_len, w_string, w_string_len);
+    ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
+
+
+    /* Unrecognized flag and src is NULL => ERROR_INVALID_PARAMETER */
+    SetLastError(0xdeadbeef);
+    len = WideCharToMultiByte(CP_ACP, 0x100, NULL, -1, c_string, c_string_len, NULL, NULL);
+    ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
+
+    SetLastError(0xdeadbeef);
+    len = MultiByteToWideChar(CP_ACP, 0x10, NULL, -1, w_string, w_string_len);
+    ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
+
+
     /* srclen=0 => ERROR_INVALID_PARAMETER */
     SetLastError(0xdeadbeef);
     len = WideCharToMultiByte(CP_ACP, 0, w_string, 0, c_string, c_string_len, NULL, NULL);
@@ -266,6 +300,11 @@ static void test_other_invalid_parameters(void)
     SetLastError(0xdeadbeef);
     len = WideCharToMultiByte(CP_UTF7, 1, w_string, w_string_len, c_string, c_string_len, NULL, &used);
     ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
+
+    /* CP_UTF8, unrecognized flag and used not NULL => ERROR_INVALID_PARAMETER */
+    SetLastError(0xdeadbeef);
+    len = WideCharToMultiByte(CP_UTF8, 0x100, w_string, w_string_len, c_string, c_string_len, NULL, &used);
+    ok(len == 0 && GetLastError() == ERROR_INVALID_PARAMETER, "len=%d error=%x\n", len, GetLastError());
 }
 
 static void test_overlapped_buffers(void)
index c88db6a..a14bc45 100755 (executable)
@@ -957,7 +957,7 @@ static void testWaitForConsoleInput(HANDLE input_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());
+    CloseHandle(complete_event);
 }
 
 static void test_GetSetConsoleInputExeName(void)
@@ -1319,7 +1319,9 @@ static void test_VerifyConsoleIoHandle( HANDLE handle )
     SetLastError(0xdeadbeef);
     ret = pVerifyConsoleIoHandle(handle);
     error = GetLastError();
-    ok(ret, "expected VerifyConsoleIoHandle to succeed\n");
+    ok(ret ||
+       broken(!ret), /* Windows 8 and 10 */
+       "expected VerifyConsoleIoHandle to succeed\n");
     ok(error == 0xdeadbeef, "wrong GetLastError() %d\n", error);
 }
 
@@ -1428,32 +1430,31 @@ static void test_WriteConsoleInputA(HANDLE input_handle)
         const INPUT_RECORD *buffer;
         DWORD count;
         LPDWORD written;
-        DWORD expected_count;
         DWORD gle, gle2;
         int win_crash;
     } invalid_table[] =
     {
-        {NULL, NULL, 0, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {NULL, NULL, 0, &count, 0, ERROR_INVALID_HANDLE},
-        {NULL, NULL, 1, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {NULL, NULL, 1, &count, 0xdeadbeef, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
-        {NULL, &event, 0, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {NULL, &event, 0, &count, 0, ERROR_INVALID_HANDLE},
-        {NULL, &event, 1, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {NULL, &event, 1, &count, 0, ERROR_INVALID_HANDLE},
-        {INVALID_HANDLE_VALUE, NULL, 0, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {INVALID_HANDLE_VALUE, NULL, 0, &count, 0, ERROR_INVALID_HANDLE},
-        {INVALID_HANDLE_VALUE, NULL, 1, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {INVALID_HANDLE_VALUE, NULL, 1, &count, 0xdeadbeef, ERROR_INVALID_HANDLE, ERROR_INVALID_ACCESS},
-        {INVALID_HANDLE_VALUE, &event, 0, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {INVALID_HANDLE_VALUE, &event, 0, &count, 0, ERROR_INVALID_HANDLE},
-        {INVALID_HANDLE_VALUE, &event, 1, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {INVALID_HANDLE_VALUE, &event, 1, &count, 0, ERROR_INVALID_HANDLE},
-        {input_handle, NULL, 0, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {input_handle, NULL, 1, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {input_handle, NULL, 1, &count, 0xdeadbeef, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
-        {input_handle, &event, 0, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {input_handle, &event, 1, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
+        {NULL, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {NULL, NULL, 0, &count,ERROR_INVALID_HANDLE},
+        {NULL, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {NULL, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
+        {NULL, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {NULL, &event, 0, &count, ERROR_INVALID_HANDLE},
+        {NULL, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {NULL, &event, 1, &count, ERROR_INVALID_HANDLE},
+        {INVALID_HANDLE_VALUE, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {INVALID_HANDLE_VALUE, NULL, 0, &count, ERROR_INVALID_HANDLE},
+        {INVALID_HANDLE_VALUE, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {INVALID_HANDLE_VALUE, NULL, 1, &count, ERROR_INVALID_HANDLE, ERROR_INVALID_ACCESS},
+        {INVALID_HANDLE_VALUE, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {INVALID_HANDLE_VALUE, &event, 0, &count, ERROR_INVALID_HANDLE},
+        {INVALID_HANDLE_VALUE, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {INVALID_HANDLE_VALUE, &event, 1, &count, ERROR_INVALID_HANDLE},
+        {input_handle, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {input_handle, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {input_handle, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
+        {input_handle, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {input_handle, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
     };
 
     /* Suppress external sources of input events for the duration of the test. */
@@ -1492,12 +1493,6 @@ static void test_WriteConsoleInputA(HANDLE input_handle)
                                  invalid_table[i].count,
                                  invalid_table[i].written);
         ok(!ret, "[%d] Expected WriteConsoleInputA to return FALSE, got %d\n", i, ret);
-        if (invalid_table[i].written)
-        {
-            ok(count == invalid_table[i].expected_count,
-               "[%d] Expected output count to be %u, got %u\n",
-               i, invalid_table[i].expected_count, count);
-        }
         gle = GetLastError();
         ok(gle == invalid_table[i].gle || (gle != 0 && gle == invalid_table[i].gle2),
            "[%d] Expected last error to be %u or %u, got %u\n",
@@ -1672,32 +1667,31 @@ static void test_WriteConsoleInputW(HANDLE input_handle)
         const INPUT_RECORD *buffer;
         DWORD count;
         LPDWORD written;
-        DWORD expected_count;
         DWORD gle, gle2;
         int win_crash;
     } invalid_table[] =
     {
-        {NULL, NULL, 0, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {NULL, NULL, 0, &count, 0, ERROR_INVALID_HANDLE},
-        {NULL, NULL, 1, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {NULL, NULL, 1, &count, 0xdeadbeef, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
-        {NULL, &event, 0, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {NULL, &event, 0, &count, 0, ERROR_INVALID_HANDLE},
-        {NULL, &event, 1, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {NULL, &event, 1, &count, 0, ERROR_INVALID_HANDLE},
-        {INVALID_HANDLE_VALUE, NULL, 0, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {INVALID_HANDLE_VALUE, NULL, 0, &count, 0, ERROR_INVALID_HANDLE},
-        {INVALID_HANDLE_VALUE, NULL, 1, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {INVALID_HANDLE_VALUE, NULL, 1, &count, 0xdeadbeef, ERROR_INVALID_HANDLE, ERROR_INVALID_ACCESS},
-        {INVALID_HANDLE_VALUE, &event, 0, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {INVALID_HANDLE_VALUE, &event, 0, &count, 0, ERROR_INVALID_HANDLE},
-        {INVALID_HANDLE_VALUE, &event, 1, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {INVALID_HANDLE_VALUE, &event, 1, &count, 0, ERROR_INVALID_HANDLE},
-        {input_handle, NULL, 0, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {input_handle, NULL, 1, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {input_handle, NULL, 1, &count, 0xdeadbeef, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
-        {input_handle, &event, 0, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
-        {input_handle, &event, 1, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 0, 1},
+        {NULL, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {NULL, NULL, 0, &count, ERROR_INVALID_HANDLE},
+        {NULL, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {NULL, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
+        {NULL, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {NULL, &event, 0, &count, ERROR_INVALID_HANDLE},
+        {NULL, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {NULL, &event, 1, &count, ERROR_INVALID_HANDLE},
+        {INVALID_HANDLE_VALUE, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {INVALID_HANDLE_VALUE, NULL, 0, &count, ERROR_INVALID_HANDLE},
+        {INVALID_HANDLE_VALUE, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {INVALID_HANDLE_VALUE, NULL, 1, &count, ERROR_INVALID_HANDLE, ERROR_INVALID_ACCESS},
+        {INVALID_HANDLE_VALUE, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {INVALID_HANDLE_VALUE, &event, 0, &count, ERROR_INVALID_HANDLE},
+        {INVALID_HANDLE_VALUE, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {INVALID_HANDLE_VALUE, &event, 1, &count, ERROR_INVALID_HANDLE},
+        {input_handle, NULL, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {input_handle, NULL, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {input_handle, NULL, 1, &count, ERROR_NOACCESS, ERROR_INVALID_ACCESS},
+        {input_handle, &event, 0, NULL, ERROR_INVALID_ACCESS, 0, 1},
+        {input_handle, &event, 1, NULL, ERROR_INVALID_ACCESS, 0, 1},
     };
 
     /* Suppress external sources of input events for the duration of the test. */
@@ -1736,12 +1730,6 @@ static void test_WriteConsoleInputW(HANDLE input_handle)
                                  invalid_table[i].count,
                                  invalid_table[i].written);
         ok(!ret, "[%d] Expected WriteConsoleInputW to return FALSE, got %d\n", i, ret);
-        if (invalid_table[i].written)
-        {
-            ok(count == invalid_table[i].expected_count,
-               "[%d] Expected output count to be %u, got %u\n",
-               i, invalid_table[i].expected_count, count);
-        }
         gle = GetLastError();
         ok(gle == invalid_table[i].gle || (gle != 0 && gle == invalid_table[i].gle2),
            "[%d] Expected last error to be %u or %u, got %u\n",
@@ -2165,21 +2153,20 @@ static void test_FillConsoleOutputCharacterA(HANDLE output_handle)
         DWORD length;
         COORD coord;
         LPDWORD lpNumCharsWritten;
-        DWORD expected_count;
         DWORD last_error;
         int win7_crash;
     } invalid_table[] =
     {
-        {NULL, 'a', 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
-        {NULL, 'a', 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
-        {NULL, 'a', 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
-        {NULL, 'a', 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
-        {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
-        {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
-        {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
-        {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
-        {output_handle, 'a', 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
-        {output_handle, 'a', 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
+        {NULL, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
+        {NULL, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
+        {NULL, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
+        {NULL, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
+        {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
+        {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
+        {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
+        {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
+        {output_handle, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
+        {output_handle, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
     };
 
     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
@@ -2195,12 +2182,6 @@ static void test_FillConsoleOutputCharacterA(HANDLE output_handle)
                                           invalid_table[i].coord,
                                           invalid_table[i].lpNumCharsWritten);
         ok(!ret, "[%d] Expected FillConsoleOutputCharacterA to return FALSE, got %d\n", i, ret);
-        if (invalid_table[i].lpNumCharsWritten)
-        {
-            ok(count == invalid_table[i].expected_count,
-               "[%d] Expected count to be %u, got %u\n",
-               i, invalid_table[i].expected_count, count);
-        }
         ok(GetLastError() == invalid_table[i].last_error,
            "[%d] Expected last error to be %u, got %u\n",
            i, invalid_table[i].last_error, GetLastError());
@@ -2231,21 +2212,20 @@ static void test_FillConsoleOutputCharacterW(HANDLE output_handle)
         DWORD length;
         COORD coord;
         LPDWORD lpNumCharsWritten;
-        DWORD expected_count;
         DWORD last_error;
         int win7_crash;
     } invalid_table[] =
     {
-        {NULL, 'a', 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
-        {NULL, 'a', 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
-        {NULL, 'a', 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
-        {NULL, 'a', 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
-        {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
-        {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
-        {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
-        {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
-        {output_handle, 'a', 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
-        {output_handle, 'a', 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
+        {NULL, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
+        {NULL, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
+        {NULL, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
+        {NULL, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
+        {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
+        {INVALID_HANDLE_VALUE, 'a', 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
+        {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
+        {INVALID_HANDLE_VALUE, 'a', 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
+        {output_handle, 'a', 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
+        {output_handle, 'a', 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
     };
 
     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
@@ -2261,12 +2241,6 @@ static void test_FillConsoleOutputCharacterW(HANDLE output_handle)
                                           invalid_table[i].coord,
                                           invalid_table[i].lpNumCharsWritten);
         ok(!ret, "[%d] Expected FillConsoleOutputCharacterW to return FALSE, got %d\n", i, ret);
-        if (invalid_table[i].lpNumCharsWritten)
-        {
-            ok(count == invalid_table[i].expected_count,
-               "[%d] Expected count to be %u, got %u\n",
-               i, invalid_table[i].expected_count, count);
-        }
         ok(GetLastError() == invalid_table[i].last_error,
            "[%d] Expected last error to be %u, got %u\n",
            i, invalid_table[i].last_error, GetLastError());
@@ -2297,21 +2271,20 @@ static void test_FillConsoleOutputAttribute(HANDLE output_handle)
         DWORD length;
         COORD coord;
         LPDWORD lpNumAttrsWritten;
-        DWORD expected_count;
         DWORD last_error;
         int win7_crash;
     } invalid_table[] =
     {
-        {NULL, FOREGROUND_BLUE, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
-        {NULL, FOREGROUND_BLUE, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
-        {NULL, FOREGROUND_BLUE, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
-        {NULL, FOREGROUND_BLUE, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
-        {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
-        {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 0, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
-        {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
-        {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 1, {0, 0}, &count, 0, ERROR_INVALID_HANDLE},
-        {output_handle, FOREGROUND_BLUE, 0, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
-        {output_handle, FOREGROUND_BLUE, 1, {0, 0}, NULL, 0xdeadbeef, ERROR_INVALID_ACCESS, 1},
+        {NULL, FOREGROUND_BLUE, 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
+        {NULL, FOREGROUND_BLUE, 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
+        {NULL, FOREGROUND_BLUE, 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
+        {NULL, FOREGROUND_BLUE, 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
+        {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
+        {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 0, {0, 0}, &count, ERROR_INVALID_HANDLE},
+        {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
+        {INVALID_HANDLE_VALUE, FOREGROUND_BLUE, 1, {0, 0}, &count, ERROR_INVALID_HANDLE},
+        {output_handle, FOREGROUND_BLUE, 0, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
+        {output_handle, FOREGROUND_BLUE, 1, {0, 0}, NULL, ERROR_INVALID_ACCESS, 1},
     };
 
     for (i = 0; i < sizeof(invalid_table)/sizeof(invalid_table[0]); i++)
@@ -2327,12 +2300,6 @@ static void test_FillConsoleOutputAttribute(HANDLE output_handle)
                                          invalid_table[i].coord,
                                          invalid_table[i].lpNumAttrsWritten);
         ok(!ret, "[%d] Expected FillConsoleOutputAttribute to return FALSE, got %d\n", i, ret);
-        if (invalid_table[i].lpNumAttrsWritten)
-        {
-            ok(count == invalid_table[i].expected_count,
-               "[%d] Expected count to be %u, got %u\n",
-               i, invalid_table[i].expected_count, count);
-        }
         ok(GetLastError() == invalid_table[i].last_error,
            "[%d] Expected last error to be %u, got %u\n",
            i, invalid_table[i].last_error, GetLastError());
@@ -2616,27 +2583,35 @@ static void test_ReadConsole(void)
     SetLastError(0xdeadbeef);
     ret = GetFileSize(std_input, NULL);
     ok(ret == INVALID_FILE_SIZE, "expected INVALID_FILE_SIZE, got %#x\n", ret);
-    ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
+    ok(GetLastError() == ERROR_INVALID_HANDLE ||
+       GetLastError() == ERROR_INVALID_FUNCTION, /* Win 8, 10 */
+       "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
 
     bytes = 0xdeadbeef;
     SetLastError(0xdeadbeef);
     ret = ReadFile(std_input, buf, -128, &bytes, NULL);
     ok(!ret, "expected 0, got %u\n", ret);
-    ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError());
+    ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
+       GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */
+       "expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError());
     ok(!bytes, "expected 0, got %u\n", bytes);
 
     bytes = 0xdeadbeef;
     SetLastError(0xdeadbeef);
     ret = ReadConsoleA(std_input, buf, -128, &bytes, NULL);
     ok(!ret, "expected 0, got %u\n", ret);
-    ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError());
+    ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
+       GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */
+       "expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError());
     ok(bytes == 0xdeadbeef, "expected 0xdeadbeef, got %#x\n", bytes);
 
     bytes = 0xdeadbeef;
     SetLastError(0xdeadbeef);
     ret = ReadConsoleW(std_input, buf, -128, &bytes, NULL);
     ok(!ret, "expected 0, got %u\n", ret);
-    ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError());
+    ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
+       GetLastError() == ERROR_NOACCESS, /* Win 8, 10 */
+       "expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError());
     ok(bytes == 0xdeadbeef, "expected 0xdeadbeef, got %#x\n", bytes);
 }
 
index 3bab961..58f1f3c 100644 (file)
@@ -321,8 +321,8 @@ static void crash_and_debug(HKEY hkey, const char* argv0, const char* dbgtasks)
         TerminateProcess(info.hProcess, WAIT_TIMEOUT);
         WaitForSingleObject(info.hProcess, 5000);
         CloseHandle(info.hProcess);
-        assert(DeleteFileA(dbglog) != 0);
-        assert(DeleteFileA(childlog) != 0);
+        DeleteFileA(dbglog);
+        DeleteFileA(childlog);
         win_skip("Giving up on child process\n");
         return;
     }
@@ -357,16 +357,16 @@ static void crash_and_debug(HKEY hkey, const char* argv0, const char* dbgtasks)
     skip_crash_and_debug = broken(wait_code == WAIT_TIMEOUT);
     if (skip_crash_and_debug)
     {
-        assert(DeleteFileA(dbglog) != 0);
-        assert(DeleteFileA(childlog) != 0);
+        DeleteFileA(dbglog);
+        DeleteFileA(childlog);
         win_skip("Giving up on debugger\n");
         return;
     }
 #endif
     ok(wait_code == WAIT_OBJECT_0, "Timed out waiting for the debugger\n");
 
-    assert(load_blackbox(childlog, &crash_blackbox, sizeof(crash_blackbox)));
-    assert(load_blackbox(dbglog, &dbg_blackbox, sizeof(dbg_blackbox)));
+    ok(load_blackbox(childlog, &crash_blackbox, sizeof(crash_blackbox)), "failed to open: %s\n", childlog);
+    ok(load_blackbox(dbglog, &dbg_blackbox, sizeof(dbg_blackbox)), "failed to open: %s\n", dbglog);
 
     ok(dbg_blackbox.argc == 6, "wrong debugger argument count: %d\n", dbg_blackbox.argc);
     ok(dbg_blackbox.pid == crash_blackbox.pid, "the child and debugged pids don't match: %d != %d\n", crash_blackbox.pid, dbg_blackbox.pid);
@@ -375,8 +375,8 @@ static void crash_and_debug(HKEY hkey, const char* argv0, const char* dbgtasks)
     ok(dbg_blackbox.nokill_rc, "DebugSetProcessKillOnExit(FALSE) failed err=%d\n", dbg_blackbox.nokill_err);
     ok(dbg_blackbox.detach_rc, "DebugActiveProcessStop(%d) failed err=%d\n", dbg_blackbox.pid, dbg_blackbox.detach_err);
 
-    assert(DeleteFileA(dbglog) != 0);
-    assert(DeleteFileA(childlog) != 0);
+    DeleteFileA(dbglog);
+    DeleteFileA(childlog);
 }
 
 static void crash_and_winedbg(HKEY hkey, const char* argv0)
index a3af052..f57618e 100755 (executable)
 #include "windef.h"
 #include "winbase.h"
 #include "winerror.h"
+#include "wine/winternl.h"
+
+static NTSTATUS (WINAPI *pNtQueryObject)(HANDLE,OBJECT_INFORMATION_CLASS,PVOID,ULONG,PULONG);
+
+static void init(void)
+{
+    HMODULE hntdll = GetModuleHandleA("ntdll.dll");
+    pNtQueryObject = (void *)GetProcAddress(hntdll, "NtQueryObject");
+}
+
+#define TEST_GRANTED_ACCESS(a,b) test_granted_access(a,b,__LINE__)
+static void test_granted_access(HANDLE handle, ACCESS_MASK access, int line)
+{
+    OBJECT_BASIC_INFORMATION obj_info;
+    NTSTATUS status;
+
+    status = pNtQueryObject(handle, ObjectBasicInformation, &obj_info,
+                            sizeof(obj_info), NULL);
+    ok_(__FILE__, line)(!status, "NtQueryObject with err: %08x\n", status);
+    ok_(__FILE__, line)(obj_info.GrantedAccess == access, "Granted access should "
+        "be 0x%08x, instead of 0x%08x\n", access, obj_info.GrantedAccess);
+}
 
 /* If you change something in these tests, please do the same
  * for GetSystemDirectory tests.
@@ -424,6 +446,7 @@ static void test_CreateDirectoryW(void)
 
 static void test_RemoveDirectoryA(void)
 {
+    char curdir[MAX_PATH];
     char tmpdir[MAX_PATH];
     BOOL ret;
 
@@ -432,6 +455,18 @@ static void test_RemoveDirectoryA(void)
     ret = CreateDirectoryA(tmpdir, NULL);
     ok(ret == TRUE, "CreateDirectoryA should always succeed\n");
 
+    GetCurrentDirectoryA(MAX_PATH, curdir);
+    ok(SetCurrentDirectoryA(tmpdir), "SetCurrentDirectoryA failed\n");
+
+    SetLastError(0xdeadbeef);
+    ok(!RemoveDirectoryA(tmpdir), "RemoveDirectoryA succeeded\n");
+    ok(GetLastError() == ERROR_SHARING_VIOLATION,
+       "Expected ERROR_SHARING_VIOLATION, got %u\n", GetLastError());
+
+    TEST_GRANTED_ACCESS(NtCurrentTeb()->Peb->ProcessParameters->CurrentDirectory.Handle,
+                        FILE_TRAVERSE | SYNCHRONIZE);
+
+    SetCurrentDirectoryA(curdir);
     ret = RemoveDirectoryA(tmpdir);
     ok(ret == TRUE, "RemoveDirectoryA should always succeed\n");
 
@@ -452,6 +487,7 @@ static void test_RemoveDirectoryA(void)
 
 static void test_RemoveDirectoryW(void)
 {
+    WCHAR curdir[MAX_PATH];
     WCHAR tmpdir[MAX_PATH];
     BOOL ret;
     static const WCHAR tmp_dir_name[] = {'P','l','e','a','s','e',' ','R','e','m','o','v','e',' ','M','e',0};
@@ -468,6 +504,18 @@ static void test_RemoveDirectoryW(void)
 
     ok(ret == TRUE, "CreateDirectoryW should always succeed\n");
 
+    GetCurrentDirectoryW(MAX_PATH, curdir);
+    ok(SetCurrentDirectoryW(tmpdir), "SetCurrentDirectoryW failed\n");
+
+    SetLastError(0xdeadbeef);
+    ok(!RemoveDirectoryW(tmpdir), "RemoveDirectoryW succeeded\n");
+    ok(GetLastError() == ERROR_SHARING_VIOLATION,
+       "Expected ERROR_SHARING_VIOLATION, got %u\n", GetLastError());
+
+    TEST_GRANTED_ACCESS(NtCurrentTeb()->Peb->ProcessParameters->CurrentDirectory.Handle,
+                        FILE_TRAVERSE | SYNCHRONIZE);
+
+    SetCurrentDirectoryW(curdir);
     ret = RemoveDirectoryW(tmpdir);
     ok(ret == TRUE, "RemoveDirectoryW should always succeed\n");
 
@@ -495,6 +543,8 @@ static void test_SetCurrentDirectoryA(void)
 
 START_TEST(directory)
 {
+    init();
+
     test_GetWindowsDirectoryA();
     test_GetWindowsDirectoryW();
 
index 9b6377d..940e2fc 100755 (executable)
@@ -58,8 +58,10 @@ static NTSTATUS (WINAPI *pNtCreateFile)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES
 static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)(LPCWSTR, PUNICODE_STRING, PWSTR*, CURDIR*);
 static NTSTATUS (WINAPI *pRtlAnsiStringToUnicodeString)(PUNICODE_STRING, PCANSI_STRING, BOOLEAN);
 static BOOL (WINAPI *pSetFileInformationByHandle)(HANDLE, FILE_INFO_BY_HANDLE_CLASS, void*, DWORD);
+static void (WINAPI *pRtlInitAnsiString)(PANSI_STRING,PCSZ);
+static void (WINAPI *pRtlFreeUnicodeString)(PUNICODE_STRING);
 
-static const char filename[] = "testfile.xxx";
+static char filename[MAX_PATH];
 static const char sillytext[] =
 "en larvig liten text dx \033 gx hej 84 hej 4484 ! \001\033 bla bl\na.. bla bla."
 "1234 43 4kljf lf &%%%&&&&&& 34 4 34   3############# 33 3 3 3 # 3## 3"
@@ -88,6 +90,8 @@ static void InitFunctionPointers(void)
     pNtCreateFile = (void *)GetProcAddress(hntdll, "NtCreateFile");
     pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(hntdll, "RtlDosPathNameToNtPathName_U");
     pRtlAnsiStringToUnicodeString = (void *)GetProcAddress(hntdll, "RtlAnsiStringToUnicodeString");
+    pRtlInitAnsiString = (void *)GetProcAddress(hntdll, "RtlInitAnsiString");
+    pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString");
 
     pFindFirstFileExA=(void*)GetProcAddress(hkernel32, "FindFirstFileExA");
     pReplaceFileA=(void*)GetProcAddress(hkernel32, "ReplaceFileA");
@@ -266,7 +270,8 @@ static void get_nt_pathW( const char *name, UNICODE_STRING *nameW )
     ANSI_STRING str;
     NTSTATUS status;
     BOOLEAN ret;
-    RtlInitAnsiString( &str, name );
+
+    pRtlInitAnsiString( &str, name );
 
     status = pRtlAnsiStringToUnicodeString( &strW, &str, TRUE );
     ok( !status, "RtlAnsiStringToUnicodeString failed with %08x\n", status );
@@ -274,7 +279,7 @@ static void get_nt_pathW( const char *name, UNICODE_STRING *nameW )
     ret = pRtlDosPathNameToNtPathName_U( strW.Buffer, nameW, NULL, NULL );
     ok( ret, "RtlDosPathNameToNtPathName_U failed\n" );
 
-    RtlFreeUnicodeString( &strW );
+    pRtlFreeUnicodeString( &strW );
 }
 
 static void test__lcreat( void )
@@ -350,30 +355,30 @@ static void test__lcreat( void )
     attr.SecurityDescriptor = NULL;
     attr.SecurityQualityOfService = NULL;
 
-    status = NtCreateFile( &file, GENERIC_READ | GENERIC_WRITE | DELETE, &attr, &io, NULL, 0,
+    status = pNtCreateFile( &file, GENERIC_READ | GENERIC_WRITE | DELETE, &attr, &io, NULL, 0,
                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                            FILE_OPEN, FILE_DELETE_ON_CLOSE | FILE_NON_DIRECTORY_FILE, NULL, 0 );
     ok( status == STATUS_ACCESS_DENIED, "expected STATUS_ACCESS_DENIED, got %08x\n", status );
     ok( GetFileAttributesA( filename ) != INVALID_FILE_ATTRIBUTES, "file was deleted\n" );
 
-    status = NtCreateFile( &file, DELETE, &attr, &io, NULL, 0,
+    status = pNtCreateFile( &file, DELETE, &attr, &io, NULL, 0,
                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                            FILE_OPEN, FILE_DELETE_ON_CLOSE | FILE_NON_DIRECTORY_FILE, NULL, 0 );
     ok( status == STATUS_CANNOT_DELETE, "expected STATUS_CANNOT_DELETE, got %08x\n", status );
 
-    status = NtCreateFile( &file, DELETE, &attr, &io, NULL, 0,
+    status = pNtCreateFile( &file, DELETE, &attr, &io, NULL, 0,
                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                            FILE_OPEN, FILE_DELETE_ON_CLOSE | FILE_DIRECTORY_FILE, NULL, 0 );
     ok( status == STATUS_NOT_A_DIRECTORY, "expected STATUS_NOT_A_DIRECTORY, got %08x\n", status );
 
-    status = NtCreateFile( &file, DELETE, &attr, &io, NULL, 0,
+    status = pNtCreateFile( &file, DELETE, &attr, &io, NULL, 0,
                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                            FILE_OPEN_IF, FILE_DELETE_ON_CLOSE | FILE_NON_DIRECTORY_FILE, NULL, 0 );
     todo_wine
     ok( status == STATUS_CANNOT_DELETE, "expected STATUS_CANNOT_DELETE, got %08x\n", status );
     if (!status) CloseHandle( file );
 
-    RtlFreeUnicodeString( &filenameW );
+    pRtlFreeUnicodeString( &filenameW );
 
     todo_wine
     ok( GetFileAttributesA( filename ) != INVALID_FILE_ATTRIBUTES, "file was deleted\n" );
@@ -450,11 +455,17 @@ static void test__lcreat( void )
       if (INVALID_HANDLE_VALUE==find)
         ok (0, "file \"%s\" not found\n", filename);
       else {
+        const char *name = strrchr(filename, '\\');
+
+        if (name) name++;
+        else name = filename;
+
         ret = FindClose(find);
         ok ( 0 != ret, "FindClose complains (%d)\n", GetLastError ());
-        ok (!strcmp (filename, search_results.cFileName),
-            "found unexpected name \"%s\"\n", search_results.cFileName);
+        ok (!strcmp (name, search_results.cFileName),
+            "expected \"%s\", got \"%s\"\n", name, search_results.cFileName);
         search_results.dwFileAttributes &= ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
+        search_results.dwFileAttributes &= ~FILE_ATTRIBUTE_COMPRESSED;
         ok (FILE_ATTRIBUTE_ARCHIVE==search_results.dwFileAttributes,
             "attributes of file \"%s\" are 0x%04x\n", search_results.cFileName,
             search_results.dwFileAttributes);
@@ -693,9 +704,6 @@ static void test_CopyFileA(void)
     ret = GetTempFileNameA(temp_path, prefix, 0, source);
     ok(ret != 0, "GetTempFileNameA error %d\n", GetLastError());
 
-    ret = MoveFileA(source, source);
-    todo_wine ok(ret, "MoveFileA: failed, error %d\n", GetLastError());
-
     /* copying a file to itself must fail */
     retok = CopyFileA(source, source, FALSE);
     ok( !retok && (GetLastError() == ERROR_SHARING_VIOLATION || broken(GetLastError() == ERROR_FILE_EXISTS) /* Win 9x */),
@@ -1198,20 +1206,22 @@ static void test_CreateFileA(void)
     char directory[] = "removeme";
     static const char nt_drive[] = "\\\\?\\A:";
     DWORD i, ret, len;
-    struct test_list p[] = {
-    {"", ERROR_PATH_NOT_FOUND, -1, FILE_ATTRIBUTE_NORMAL, TRUE }, /* dir as file w \ */
-    {"", ERROR_SUCCESS, ERROR_PATH_NOT_FOUND, FILE_FLAG_BACKUP_SEMANTICS, FALSE }, /* dir as dir w \ */
-    {"a", ERROR_FILE_NOT_FOUND, -1, FILE_ATTRIBUTE_NORMAL, FALSE }, /* non-exist file */
-    {"a\\", ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, FILE_ATTRIBUTE_NORMAL, FALSE }, /* non-exist dir */
-    {"removeme", ERROR_ACCESS_DENIED, -1, FILE_ATTRIBUTE_NORMAL, FALSE }, /* exist dir w/o \ */
-    {"removeme\\", ERROR_PATH_NOT_FOUND, -1, FILE_ATTRIBUTE_NORMAL, TRUE }, /* exst dir w \ */
-    {"c:", ERROR_ACCESS_DENIED, ERROR_PATH_NOT_FOUND, FILE_ATTRIBUTE_NORMAL, FALSE }, /* device in file namespace */
-    {"c:", ERROR_SUCCESS, ERROR_PATH_NOT_FOUND, FILE_FLAG_BACKUP_SEMANTICS, FALSE }, /* device in file namespace as dir */
-    {"c:\\", ERROR_PATH_NOT_FOUND, ERROR_ACCESS_DENIED, FILE_ATTRIBUTE_NORMAL, TRUE }, /* root dir w \ */
-    {"c:\\", ERROR_SUCCESS, ERROR_ACCESS_DENIED, FILE_FLAG_BACKUP_SEMANTICS, FALSE }, /* root dir w \ as dir */
-    {"\\\\?\\c:", ERROR_SUCCESS, ERROR_BAD_NETPATH, FILE_ATTRIBUTE_NORMAL,FALSE }, /* dev namespace drive */
-    {"\\\\?\\c:\\", ERROR_PATH_NOT_FOUND, ERROR_BAD_NETPATH, FILE_ATTRIBUTE_NORMAL, TRUE }, /* dev namespace drive w \ */
-    {NULL, 0, -1, 0, FALSE}
+    static const struct test_list p[] =
+    {
+        {"", ERROR_PATH_NOT_FOUND, -1, FILE_ATTRIBUTE_NORMAL, TRUE }, /* dir as file w \ */
+        {"", ERROR_SUCCESS, ERROR_PATH_NOT_FOUND, FILE_FLAG_BACKUP_SEMANTICS, FALSE }, /* dir as dir w \ */
+        {"a", ERROR_FILE_NOT_FOUND, -1, FILE_ATTRIBUTE_NORMAL, FALSE }, /* non-exist file */
+        {"a\\", ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, FILE_ATTRIBUTE_NORMAL, FALSE }, /* non-exist dir */
+        {"removeme", ERROR_ACCESS_DENIED, -1, FILE_ATTRIBUTE_NORMAL, FALSE }, /* exist dir w/o \ */
+        {"removeme\\", ERROR_PATH_NOT_FOUND, -1, FILE_ATTRIBUTE_NORMAL, TRUE }, /* exst dir w \ */
+        {"c:", ERROR_ACCESS_DENIED, ERROR_PATH_NOT_FOUND, FILE_ATTRIBUTE_NORMAL, FALSE }, /* device in file namespace */
+        {"c:", ERROR_SUCCESS, ERROR_PATH_NOT_FOUND, FILE_FLAG_BACKUP_SEMANTICS, FALSE }, /* device in file namespace as dir */
+        {"c:\\", ERROR_PATH_NOT_FOUND, ERROR_ACCESS_DENIED, FILE_ATTRIBUTE_NORMAL, TRUE }, /* root dir w \ */
+        {"c:\\", ERROR_SUCCESS, ERROR_ACCESS_DENIED, FILE_FLAG_BACKUP_SEMANTICS, FALSE }, /* root dir w \ as dir */
+        {"c:c:\\windows", ERROR_INVALID_NAME, -1, FILE_ATTRIBUTE_NORMAL, TRUE }, /* invalid path */
+        {"\\\\?\\c:", ERROR_SUCCESS, ERROR_BAD_NETPATH, FILE_ATTRIBUTE_NORMAL,FALSE }, /* dev namespace drive */
+        {"\\\\?\\c:\\", ERROR_PATH_NOT_FOUND, ERROR_BAD_NETPATH, FILE_ATTRIBUTE_NORMAL, TRUE }, /* dev namespace drive w \ */
+        {NULL, 0, -1, 0, FALSE}
     };
     BY_HANDLE_FILE_INFORMATION  Finfo;
     WCHAR curdir[MAX_PATH];
@@ -1875,6 +1885,9 @@ static void test_MoveFileA(void)
     ret = GetTempFileNameA(tempdir, prefix, 0, dest);
     ok(ret != 0, "GetTempFileNameA error %d\n", GetLastError());
 
+    ret = MoveFileA(source, source);
+    ok(ret, "MoveFileA: failed, error %d\n", GetLastError());
+
     ret = MoveFileA(source, dest);
     ok(!ret && GetLastError() == ERROR_ALREADY_EXISTS,
        "MoveFileA: unexpected error %d\n", GetLastError());
@@ -1893,12 +1906,10 @@ static void test_MoveFileA(void)
     ok(hmapfile != NULL, "CreateFileMapping: error %d\n", GetLastError());
 
     ret = MoveFileA(source, dest);
-    todo_wine {
-        ok(!ret, "MoveFileA: expected failure\n");
-        ok(GetLastError() == ERROR_SHARING_VIOLATION ||
-           broken(GetLastError() == ERROR_ACCESS_DENIED), /* Win9x and WinMe */
-           "MoveFileA: expected ERROR_SHARING_VIOLATION, got %d\n", GetLastError());
-    }
+    ok(!ret, "MoveFileA: expected failure\n");
+    ok(GetLastError() == ERROR_SHARING_VIOLATION ||
+       broken(GetLastError() == ERROR_ACCESS_DENIED), /* Win9x and WinMe */
+       "MoveFileA: expected ERROR_SHARING_VIOLATION, got %d\n", GetLastError());
 
     CloseHandle(hmapfile);
     CloseHandle(hfile);
@@ -1913,12 +1924,10 @@ static void test_MoveFileA(void)
     ok(hmapfile != NULL, "CreateFileMapping: error %d\n", GetLastError());
 
     ret = MoveFileA(source, dest);
-    todo_wine {
-        ok(!ret, "MoveFileA: expected failure\n");
-        ok(GetLastError() == ERROR_SHARING_VIOLATION ||
-           broken(GetLastError() == ERROR_ACCESS_DENIED), /* Win9x and WinMe */
-           "MoveFileA: expected ERROR_SHARING_VIOLATION, got %d\n", GetLastError());
-    }
+    ok(!ret, "MoveFileA: expected failure\n");
+    ok(GetLastError() == ERROR_SHARING_VIOLATION ||
+       broken(GetLastError() == ERROR_ACCESS_DENIED), /* Win9x and WinMe */
+       "MoveFileA: expected ERROR_SHARING_VIOLATION, got %d\n", GetLastError());
 
     CloseHandle(hmapfile);
     CloseHandle(hfile);
@@ -2326,21 +2335,24 @@ static BOOL is_sharing_map_compatible( DWORD map_access, DWORD access2, DWORD sh
 
 static void test_file_sharing(void)
 {
-    static const DWORD access_modes[] =
-        { 0, GENERIC_READ, GENERIC_WRITE, GENERIC_READ|GENERIC_WRITE,
-          DELETE, GENERIC_READ|DELETE, GENERIC_WRITE|DELETE, GENERIC_READ|GENERIC_WRITE|DELETE,
-          GENERIC_EXECUTE, GENERIC_EXECUTE | DELETE,
-          FILE_READ_DATA, FILE_WRITE_DATA, FILE_APPEND_DATA, FILE_READ_EA, FILE_WRITE_EA,
-          FILE_READ_DATA | FILE_EXECUTE, FILE_WRITE_DATA | FILE_EXECUTE, FILE_APPEND_DATA | FILE_EXECUTE,
-          FILE_READ_EA | FILE_EXECUTE, FILE_WRITE_EA | FILE_EXECUTE, FILE_EXECUTE,
-          FILE_DELETE_CHILD, FILE_READ_ATTRIBUTES, FILE_WRITE_ATTRIBUTES };
-    static const DWORD sharing_modes[] =
-        { 0, FILE_SHARE_READ,
-          FILE_SHARE_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
-          FILE_SHARE_DELETE, FILE_SHARE_READ|FILE_SHARE_DELETE,
-          FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE };
-    static const DWORD mapping_modes[] =
-        { PAGE_READONLY, PAGE_WRITECOPY, PAGE_READWRITE, SEC_IMAGE | PAGE_WRITECOPY };
+    struct mode { DWORD dw; const char* str; };
+#define M(x) {x, # x}
+    static const struct mode access_modes[] =
+        { M(0), M(GENERIC_READ), M(GENERIC_WRITE), M(GENERIC_READ|GENERIC_WRITE),
+          M(DELETE), M(GENERIC_READ|DELETE), M(GENERIC_WRITE|DELETE), M(GENERIC_READ|GENERIC_WRITE|DELETE),
+          M(GENERIC_EXECUTE), M(GENERIC_EXECUTE | DELETE),
+          M(FILE_READ_DATA), M(FILE_WRITE_DATA), M(FILE_APPEND_DATA), M(FILE_READ_EA), M(FILE_WRITE_EA),
+          M(FILE_READ_DATA | FILE_EXECUTE), M(FILE_WRITE_DATA | FILE_EXECUTE), M(FILE_APPEND_DATA | FILE_EXECUTE),
+          M(FILE_READ_EA | FILE_EXECUTE), M(FILE_WRITE_EA | FILE_EXECUTE), M(FILE_EXECUTE),
+          M(FILE_DELETE_CHILD), M(FILE_READ_ATTRIBUTES), M(FILE_WRITE_ATTRIBUTES) };
+    static const struct mode sharing_modes[] =
+        { M(0), M(FILE_SHARE_READ),
+          M(FILE_SHARE_WRITE), M(FILE_SHARE_READ|FILE_SHARE_WRITE),
+          M(FILE_SHARE_DELETE), M(FILE_SHARE_READ|FILE_SHARE_DELETE),
+          M(FILE_SHARE_WRITE|FILE_SHARE_DELETE), M(FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE) };
+    static const struct mode mapping_modes[] =
+        { M(PAGE_READONLY), M(PAGE_WRITECOPY), M(PAGE_READWRITE), M(SEC_IMAGE | PAGE_WRITECOPY) };
+#undef M
     int a1, s1, a2, s2;
     int ret;
     HANDLE h, h2;
@@ -2357,7 +2369,7 @@ static void test_file_sharing(void)
         for (s1 = 0; s1 < sizeof(sharing_modes)/sizeof(sharing_modes[0]); s1++)
         {
             SetLastError(0xdeadbeef);
-            h = CreateFileA( filename, access_modes[a1], sharing_modes[s1],
+            h = CreateFileA( filename, access_modes[a1].dw, sharing_modes[s1].dw,
                              NULL, OPEN_EXISTING, 0, 0 );
             if (h == INVALID_HANDLE_VALUE)
             {
@@ -2369,24 +2381,24 @@ static void test_file_sharing(void)
                 for (s2 = 0; s2 < sizeof(sharing_modes)/sizeof(sharing_modes[0]); s2++)
                 {
                     SetLastError(0xdeadbeef);
-                    h2 = CreateFileA( filename, access_modes[a2], sharing_modes[s2],
+                    h2 = CreateFileA( filename, access_modes[a2].dw, sharing_modes[s2].dw,
                                       NULL, OPEN_EXISTING, 0, 0 );
                     ret = GetLastError();
-                    if (is_sharing_compatible( access_modes[a1], sharing_modes[s1],
-                                               access_modes[a2], sharing_modes[s2] ))
+                    if (is_sharing_compatible( access_modes[a1].dw, sharing_modes[s1].dw,
+                                               access_modes[a2].dw, sharing_modes[s2].dw ))
                     {
                         ok( h2 != INVALID_HANDLE_VALUE,
-                            "open failed for modes %x/%x/%x/%x\n",
-                            access_modes[a1], sharing_modes[s1],
-                            access_modes[a2], sharing_modes[s2] );
+                            "open failed for modes %s / %s / %s / %s\n",
+                            access_modes[a1].str, sharing_modes[s1].str,
+                            access_modes[a2].str, sharing_modes[s2].str );
                         ok( ret == 0, "wrong error code %d\n", ret );
                     }
                     else
                     {
                         ok( h2 == INVALID_HANDLE_VALUE,
-                            "open succeeded for modes %x/%x/%x/%x\n",
-                            access_modes[a1], sharing_modes[s1],
-                            access_modes[a2], sharing_modes[s2] );
+                            "open succeeded for modes %s / %s / %s / %s\n",
+                            access_modes[a1].str, sharing_modes[s1].str,
+                            access_modes[a2].str, sharing_modes[s2].str );
                          ok( ret == ERROR_SHARING_VIOLATION,
                              "wrong error code %d\n", ret );
                     }
@@ -2409,8 +2421,8 @@ static void test_file_sharing(void)
             ok(0,"couldn't create file \"%s\" (err=%d)\n",filename,GetLastError());
             return;
         }
-        m = CreateFileMappingA( h, NULL, mapping_modes[a1], 0, 0, NULL );
-        ok( m != 0, "failed to create mapping %x err %u\n", mapping_modes[a1], GetLastError() );
+        m = CreateFileMappingA( h, NULL, mapping_modes[a1].dw, 0, 0, NULL );
+        ok( m != 0, "failed to create mapping %s err %u\n", mapping_modes[a1].str, GetLastError() );
         CloseHandle( h );
         if (!m) continue;
 
@@ -2419,24 +2431,24 @@ static void test_file_sharing(void)
             for (s2 = 0; s2 < sizeof(sharing_modes)/sizeof(sharing_modes[0]); s2++)
             {
                 SetLastError(0xdeadbeef);
-                h2 = CreateFileA( filename, access_modes[a2], sharing_modes[s2],
+                h2 = CreateFileA( filename, access_modes[a2].dw, sharing_modes[s2].dw,
                                   NULL, OPEN_EXISTING, 0, 0 );
 
                 ret = GetLastError();
                 if (h2 == INVALID_HANDLE_VALUE)
                 {
-                    ok( !is_sharing_map_compatible(mapping_modes[a1], access_modes[a2], sharing_modes[s2]),
-                        "open failed for modes map %x/%x/%x\n",
-                        mapping_modes[a1], access_modes[a2], sharing_modes[s2] );
+                    ok( !is_sharing_map_compatible(mapping_modes[a1].dw, access_modes[a2].dw, sharing_modes[s2].dw),
+                        "open failed for modes map %s / %s / %s\n",
+                        mapping_modes[a1].str, access_modes[a2].str, sharing_modes[s2].str );
                     ok( ret == ERROR_SHARING_VIOLATION,
                         "wrong error code %d\n", ret );
                 }
                 else
                 {
-                    if (!is_sharing_map_compatible(mapping_modes[a1], access_modes[a2], sharing_modes[s2]))
+                    if (!is_sharing_map_compatible(mapping_modes[a1].dw, access_modes[a2].dw, sharing_modes[s2].dw))
                         ok( broken(1),  /* no checking on nt4 */
-                            "open succeeded for modes map %x/%x/%x\n",
-                            mapping_modes[a1], access_modes[a2], sharing_modes[s2] );
+                            "open succeeded for modes map %s / %s / %s\n",
+                            mapping_modes[a1].str, access_modes[a2].str, sharing_modes[s2].str );
                     ok( ret == 0xdeadbeef /* Win9x */ ||
                         ret == 0, /* XP */
                         "wrong error code %d\n", ret );
@@ -2450,15 +2462,15 @@ static void test_file_sharing(void)
         h2 = CreateFileA( filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
                           NULL, CREATE_ALWAYS, 0, 0 );
         ret = GetLastError();
-        if (mapping_modes[a1] & SEC_IMAGE)
+        if (mapping_modes[a1].dw & SEC_IMAGE)
         {
-            ok( h2 == INVALID_HANDLE_VALUE, "create succeeded for map %x\n", mapping_modes[a1] );
-            ok( ret == ERROR_SHARING_VIOLATION, "wrong error code %d for %x\n", ret, mapping_modes[a1] );
+            ok( h2 == INVALID_HANDLE_VALUE, "create succeeded for map %s\n", mapping_modes[a1].str );
+            ok( ret == ERROR_SHARING_VIOLATION, "wrong error code %d for %s\n", ret, mapping_modes[a1].str );
         }
         else
         {
-            ok( h2 == INVALID_HANDLE_VALUE, "create succeeded for map %x\n", mapping_modes[a1] );
-            ok( ret == ERROR_USER_MAPPED_FILE, "wrong error code %d for %x\n", ret, mapping_modes[a1] );
+            ok( h2 == INVALID_HANDLE_VALUE, "create succeeded for map %s\n", mapping_modes[a1].str );
+            ok( ret == ERROR_USER_MAPPED_FILE, "wrong error code %d for %s\n", ret, mapping_modes[a1].str );
         }
         if (h2 != INVALID_HANDLE_VALUE) CloseHandle( h2 );
 
@@ -2467,14 +2479,14 @@ static void test_file_sharing(void)
         h2 = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
                           NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0 );
         ret = GetLastError();
-        if (mapping_modes[a1] & SEC_IMAGE)
+        if (mapping_modes[a1].dw & SEC_IMAGE)
         {
-            ok( h2 == INVALID_HANDLE_VALUE, "create succeeded for map %x\n", mapping_modes[a1] );
-            ok( ret == ERROR_ACCESS_DENIED, "wrong error code %d for %x\n", ret, mapping_modes[a1] );
+            ok( h2 == INVALID_HANDLE_VALUE, "create succeeded for map %s\n", mapping_modes[a1].str );
+            ok( ret == ERROR_ACCESS_DENIED, "wrong error code %d for %s\n", ret, mapping_modes[a1].str );
         }
         else
         {
-            ok( h2 != INVALID_HANDLE_VALUE, "open failed for map %x err %u\n", mapping_modes[a1], ret );
+            ok( h2 != INVALID_HANDLE_VALUE, "open failed for map %s err %u\n", mapping_modes[a1].str, ret );
         }
         if (h2 != INVALID_HANDLE_VALUE) CloseHandle( h2 );
 
@@ -2506,13 +2518,12 @@ static char get_windows_drive(void)
     return windowsdir[0];
 }
 
-static
-struct
+static const struct
 {
     const char *path;
     BOOL expected;
 }
-const invalid_char_tests[] =
+invalid_char_tests[] =
 {
     { "./test-dir",                     TRUE },
     { "./test-dir/",                    FALSE },
@@ -2901,6 +2912,97 @@ cleanup:
     RemoveDirectoryA("test-dir");
 }
 
+static void test_FindFirstFile_wildcards(void)
+{
+    WIN32_FIND_DATAA find_data;
+    HANDLE handle;
+    int i;
+    static const char* files[] = {
+        "..a", "..a.a", ".a", ".a..a", ".a.a", ".aaa",
+        "a", "a..a", "a.a", "a.a.a", "aa", "aaa", "aaaa"
+    };
+    static const struct {
+        int todo;
+        const char *pattern, *result;
+    } tests[] = {
+        {0, "*.*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"},
+        {0, "*.*.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"},
+        {0, ".*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa'"},
+        {0, "*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"},
+        {0, ".*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa'"},
+        {1, "*.", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"},
+        {0, "*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"},
+        {1, "*..*", ", '.', '..', '..a', '..a.a', '.a..a', 'a..a'"},
+        {1, "*..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"},
+        {1, ".*.", ", '.', '..', '.a', '.aaa'"},
+        {0, "..*", ", '.', '..', '..a', '..a.a'"},
+        {0, "**", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"},
+        {0, "**.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"},
+        {0, "*. ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"},
+        {1, "* .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"},
+        {0, "* . ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"},
+        {0, "*.. ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"},
+        {1, "*. .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"},
+        {1, "* ..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"},
+        {1, " *..", ", '.aaa'"},
+        {0, "..* ", ", '.', '..', '..a', '..a.a'"},
+        {1, "?", ", '.', '..', 'a'"},
+        {1, "?.", ", '.', '..', 'a'"},
+        {1, "?. ", ", '.', '..', 'a'"},
+        {1, "??.", ", '.', '..', 'a', 'aa'"},
+        {1, "??. ", ", '.', '..', 'a', 'aa'"},
+        {1, "???.", ", '.', '..', 'a', 'aa', 'aaa'"},
+        {1, "?.??.", ", '.', '..', '.a', 'a', 'a.a'"}
+    };
+
+    CreateDirectoryA("test-dir", NULL);
+    SetCurrentDirectoryA("test-dir");
+    for (i = 0; i < sizeof(files) / sizeof(files[0]); ++i)
+        _lclose(_lcreat(files[i], 0));
+
+    for (i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i)
+    {
+        char correct[512];
+        char incorrect[512];
+        char missing[512];
+
+        strcpy(missing, tests[i].result);
+        correct[0] = incorrect[0] = 0;
+
+        handle = FindFirstFileA(tests[i].pattern, &find_data);
+        if (handle) do {
+            char* ptr;
+            char quoted[16];
+
+            sprintf( quoted, ", '%.10s'", find_data.cFileName );
+
+            if ((ptr = strstr(missing, quoted)))
+            {
+                int len = strlen(quoted);
+                while ((ptr[0] = ptr[len]) != 0)
+                    ++ptr;
+                strcat(correct, quoted);
+            }
+            else
+                strcat(incorrect, quoted);
+        } while (FindNextFileA(handle, &find_data));
+        FindClose(handle);
+
+        todo_wine_if (tests[i].todo)
+        ok(missing[0] == 0 && incorrect[0] == 0,
+           "FindFirstFile with '%s' found correctly %s, found incorrectly %s, and missed %s\n",
+           tests[i].pattern,
+           correct[0] ? correct+2 : "none",
+           incorrect[0] ? incorrect+2 : "none",
+           missing[0] ? missing+2 : "none");
+    }
+
+    for (i = 0; i < sizeof(files) / sizeof(files[0]); ++i)
+        DeleteFileA(files[i]);
+    SetCurrentDirectoryA("..");
+    RemoveDirectoryA("test-dir");
+}
+
 static int test_Mapfile_createtemp(HANDLE *handle)
 {
     SetFileAttributesA(filename,FILE_ATTRIBUTE_NORMAL);
@@ -3892,6 +3994,18 @@ todo_wine_if (i == 1)
                 ok(!ret, "%d: WriteFile should fail\n", i);
                 ok(GetLastError() == ERROR_ACCESS_DENIED, "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError());
             }
+            SetLastError(0xdeadbeef);
+            ret = SetFileTime(hfile, NULL, NULL, NULL);
+            if (td[i].access & GENERIC_WRITE) /* actually FILE_WRITE_ATTRIBUTES */
+                ok(ret, "%d: SetFileTime error %d\n", i, GetLastError());
+            else
+            {
+                todo_wine
+                {
+                ok(!ret, "%d: SetFileTime should fail\n", i);
+                ok(GetLastError() == ERROR_ACCESS_DENIED, "%d: expected ERROR_ACCESS_DENIED, got %d\n", i, GetLastError());
+                }
+            }
             CloseHandle(hfile);
         }
         else
@@ -4719,7 +4833,7 @@ static void test_SetFileInformationByHandle(void)
 {
     FILE_ATTRIBUTE_TAG_INFO fileattrinfo = { 0 };
     FILE_REMOTE_PROTOCOL_INFO protinfo = { 0 };
-    FILE_STANDARD_INFO stdinfo;
+    FILE_STANDARD_INFO stdinfo = { {{0}},{{0}},0,FALSE,FALSE };
     FILE_COMPRESSION_INFO compressinfo;
     FILE_DISPOSITION_INFO dispinfo;
     char tempFileName[MAX_PATH];
@@ -4804,8 +4918,18 @@ static void test_GetFileAttributesExW(void)
 
 START_TEST(file)
 {
+    char temp_path[MAX_PATH];
+    DWORD ret;
+
     InitFunctionPointers();
 
+    ret = GetTempPathA(MAX_PATH, temp_path);
+    ok(ret != 0, "GetTempPath error %u\n", GetLastError());
+    ret = GetTempFileNameA(temp_path, "tmp", 0, filename);
+    ok(ret != 0, "GetTempFileName error %u\n", GetLastError());
+    ret = DeleteFileA(filename);
+    ok(ret != 0, "DeleteFile error %u\n", GetLastError());
+
     test__hread(  );
     test__hwrite(  );
     test__lclose(  );
@@ -4829,6 +4953,7 @@ START_TEST(file)
     test_MoveFileW();
     test_FindFirstFileA();
     test_FindNextFileA();
+    test_FindFirstFile_wildcards();
     test_FindFirstFileExA(FindExInfoStandard, 0, 0);
     test_FindFirstFileExA(FindExInfoStandard, 0, FIND_FIRST_EX_CASE_SENSITIVE);
     test_FindFirstFileExA(FindExInfoStandard, 0, FIND_FIRST_EX_LARGE_FETCH);
index 4a1ae7d..1f88e24 100755 (executable)
@@ -24,6 +24,8 @@
 #include "winbase.h"
 #include "winnls.h"
 
+#define ULL(a,b)   (((ULONG64)(a) << 32) | (b))
+
 static DWORD __cdecl doit(DWORD flags, LPCVOID src, DWORD msg_id, DWORD lang_id,
                           LPSTR out, DWORD outsize, ... )
 {
@@ -1781,6 +1783,80 @@ static void test_message_invalid_flags_wide(void)
        "Expected the output buffer to be untouched\n");
 }
 
+static void test_message_from_64bit_number(void)
+{
+    static const WCHAR I64d[] = {'%', '1', '!', 'I', '6', '4', 'd', '!', 0};
+    static const WCHAR I64u[] = {'%', '1', '!', 'I', '6', '4', 'u', '!', 0};
+    WCHAR outW[0x100], expW[0x100];
+    char outA[0x100];
+    DWORD r;
+    static const struct
+    {
+        UINT64 number;
+        const char expected[32];
+        int len;
+    } unsigned_tests[] =
+    {
+        { 0, "0", 1 },
+        { 1234567890, "1234567890", 10},
+        { ULL(0xFFFFFFFF,0xFFFFFFFF), "18446744073709551615", 20 },
+        { ULL(0x7FFFFFFF,0xFFFFFFFF), "9223372036854775807", 19 },
+    };
+    static const struct
+    {
+        INT64 number;
+        const char expected[32];
+        int len;
+    } signed_tests[] =
+    {
+        { 0, "0" , 1},
+        { 1234567890, "1234567890", 10 },
+        { -1, "-1", 2},
+        { ULL(0xFFFFFFFF,0xFFFFFFFF), "-1", 2},
+        { ULL(0x7FFFFFFF,0xFFFFFFFF), "9223372036854775807", 19 },
+        { -ULL(0x7FFFFFFF,0xFFFFFFFF), "-9223372036854775807", 20},
+    };
+    int i;
+
+    for (i = 0; i < sizeof(unsigned_tests) / sizeof(unsigned_tests[0]); i++)
+    {
+        r = doitW(FORMAT_MESSAGE_FROM_STRING, I64u,
+                  0, 0, outW, sizeof(outW) / sizeof(WCHAR), unsigned_tests[i].number);
+        MultiByteToWideChar(CP_ACP, 0, unsigned_tests[i].expected, -1, expW, sizeof(expW) / sizeof(WCHAR));
+todo_wine {
+        ok(!lstrcmpW(outW, expW),"[%d] failed, expected %s, got %s\n", i,
+                     unsigned_tests[i].expected, wine_dbgstr_w(outW));
+        ok(r == unsigned_tests[i].len,"[%d] failed: r=%d\n", i, r);
+}
+        r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!I64u!",
+                  0, 0, outA, sizeof(outA), unsigned_tests[i].number);
+todo_wine {
+        ok(!strcmp(outA, unsigned_tests[i].expected),"[%d] failed, expected %s, got %s\n", i,
+                   unsigned_tests[i].expected, outA);
+        ok(r == unsigned_tests[i].len,"[%d] failed: r=%d\n", i, r);
+}
+    }
+
+    for (i = 0; i < sizeof(signed_tests) / sizeof(signed_tests[0]); i++)
+    {
+        r = doitW(FORMAT_MESSAGE_FROM_STRING, I64d,
+                  0, 0, outW, sizeof(outW) / sizeof(WCHAR), signed_tests[i].number);
+        MultiByteToWideChar(CP_ACP, 0, signed_tests[i].expected, -1, expW, sizeof(expW) / sizeof(WCHAR));
+todo_wine {
+        ok(!lstrcmpW(outW, expW),"[%d] failed, expected %s, got %s\n", i,
+                     signed_tests[i].expected, wine_dbgstr_w(outW));
+        ok(r == signed_tests[i].len,"[%d] failed: r=%d\n", i, r);
+}
+        r = doit(FORMAT_MESSAGE_FROM_STRING, "%1!I64d!",
+                  0, 0, outA, sizeof(outA), signed_tests[i].number);
+todo_wine {
+        ok(!strcmp(outA, signed_tests[i].expected),"[%d] failed, expected %s, got %s\n", i,
+                   signed_tests[i].expected, outA);
+        ok(r == signed_tests[i].len,"[%d] failed: r=%d\n", i, r);
+}
+    }
+}
+
 START_TEST(format_msg)
 {
     DWORD ret;
@@ -1808,4 +1884,5 @@ START_TEST(format_msg)
     test_message_null_buffer_wide();
     test_message_allocate_buffer_wide();
     test_message_invalid_flags_wide();
+    test_message_from_64bit_number();
 }
index d8ac787..16d599e 100755 (executable)
@@ -118,6 +118,13 @@ static void test_heap(void)
     HeapFree(GetProcessHeap(), 0, mem);
     mem = HeapAlloc(GetProcessHeap(), 0, ~(SIZE_T)0);
     ok(mem == NULL, "memory allocated for size ~0\n");
+    mem = HeapAlloc(GetProcessHeap(), 0, 17);
+    msecond = HeapReAlloc(GetProcessHeap(), 0, mem, 0);
+    ok(msecond != NULL, "HeapReAlloc(0) should have succeeded\n");
+    size = HeapSize(GetProcessHeap(), 0, msecond);
+    ok(size == 0 || broken(size == 1) /* some vista and win7 */,
+       "HeapSize should have returned 0 instead of %lu\n", size);
+    HeapFree(GetProcessHeap(), 0, msecond);
 
     /* large blocks must be 16-byte aligned */
     mem = HeapAlloc(GetProcessHeap(), 0, 512 * 1024);
@@ -306,6 +313,12 @@ static void test_heap(void)
            "Expected ERROR_INVALID_HANDLE or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
     }
 
+    gbl = GlobalAlloc( GMEM_FIXED, 0 );
+    SetLastError(0xdeadbeef);
+    size = GlobalSize( gbl );
+    ok( size == 1, "wrong size %lu\n", size );
+    GlobalFree( gbl );
+
     /* ####################################### */
     /* Local*() functions */
     gbl = LocalAlloc(LMEM_MOVEABLE, 0);
@@ -438,6 +451,13 @@ static void test_heap(void)
        broken(GetLastError() == 0xdeadbeef) /* win9x */, "got %d\n", GetLastError());
     LocalFree(gbl);
 
+    gbl = LocalAlloc( LMEM_FIXED, 0 );
+    SetLastError(0xdeadbeef);
+    size = LocalSize( gbl );
+    ok( !size || broken(size == 1), /* vistau64 */
+        "wrong size %lu\n", size );
+    LocalFree( gbl );
+
     /* trying to lock empty memory should give an error */
     gbl = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,0);
     ok(gbl != NULL, "returned NULL\n");
index 0fd57cc..9e59834 100644 (file)
@@ -28,6 +28,7 @@
 #include "windef.h"
 #include "winbase.h"
 #include "wine/winternl.h"
+#include "winuser.h"
 #include "wine/test.h"
 #include "delayloadhandler.h"
 
@@ -184,7 +185,7 @@ static DWORD create_test_dll( const IMAGE_DOS_HEADER *dos_header, UINT dos_size,
     {
         SetLastError(0xdeadbeef);
         ret = WriteFile(hfile, &nt_header->OptionalHeader,
-                        min(nt_header->FileHeader.SizeOfOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER)),
+                        sizeof(IMAGE_OPTIONAL_HEADER),
                         &dummy, NULL);
         ok(ret, "WriteFile error %d\n", GetLastError());
         if (nt_header->FileHeader.SizeOfOptionalHeader > sizeof(IMAGE_OPTIONAL_HEADER))
@@ -200,6 +201,8 @@ static DWORD create_test_dll( const IMAGE_DOS_HEADER *dos_header, UINT dos_size,
     assert(nt_header->FileHeader.NumberOfSections <= 1);
     if (nt_header->FileHeader.NumberOfSections)
     {
+        SetFilePointer(hfile, dos_size + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + nt_header->FileHeader.SizeOfOptionalHeader, NULL, FILE_BEGIN);
+
         section.SizeOfRawData = 10;
 
         if (nt_header->OptionalHeader.SectionAlignment >= page_size)
@@ -224,6 +227,17 @@ static DWORD create_test_dll( const IMAGE_DOS_HEADER *dos_header, UINT dos_size,
         ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
         ok(ret, "WriteFile error %d\n", GetLastError());
     }
+
+    /* Minimal PE image that Windows7+ is able to load: 268 bytes */
+    size = GetFileSize(hfile, NULL);
+    if (size < 268)
+    {
+        file_align = 268 - size;
+        SetLastError(0xdeadbeef);
+        ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
+        ok(ret, "WriteFile error %d\n", GetLastError());
+    }
+
     size = GetFileSize(hfile, NULL);
     CloseHandle(hfile);
     return size;
@@ -294,7 +308,8 @@ static void query_image_section( int id, const char *dll_name, const IMAGE_NT_HE
         image.LoaderFlags, nt_header->OptionalHeader.LoaderFlags );
     ok( image.ImageFileSize == file_size || broken(!image.ImageFileSize), /* winxpsp1 */
         "%u: ImageFileSize wrong %08x / %08x\n", id, image.ImageFileSize, file_size );
-    ok( image.CheckSum == nt_header->OptionalHeader.CheckSum, "%u: CheckSum wrong %08x / %08x\n", id,
+    ok( image.CheckSum == nt_header->OptionalHeader.CheckSum || broken(truncated),
+        "%u: CheckSum wrong %08x / %08x\n", id,
         image.CheckSum, nt_header->OptionalHeader.CheckSum );
     /* FIXME: needs more work: */
     /* image.GpValue */
@@ -444,6 +459,7 @@ static void test_Loader(void)
         /* Mandatory are all fields up to SizeOfHeaders, everything else
          * is really optional (at least that's true for XP).
          */
+#if 0 /* 32-bit Windows 8 crashes inside of LoadLibrary */
         { sizeof(dos_header),
           1, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
           sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER) + 0x10,
@@ -451,6 +467,7 @@ static void test_Loader(void)
           { ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT, ERROR_INVALID_ADDRESS,
             ERROR_NOACCESS }
         },
+#endif
         { sizeof(dos_header),
           0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
           0xd0, /* beyond of the end of file */
@@ -519,6 +536,14 @@ static void test_Loader(void)
           0x40, /* minimal image size that Windows7 accepts */
           0,
           { ERROR_SUCCESS }
+        },
+        /* the following data mimics the PE image which 8k demos have */
+        { 0x04,
+          0, 0x08,
+          0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
+          0x200000,
+          0x40,
+          { ERROR_SUCCESS }
         }
     };
     int i;
@@ -709,6 +734,17 @@ static void test_Loader(void)
             ret = FreeLibrary(hlib_as_data_file);
             ok(ret, "FreeLibrary error %d\n", GetLastError());
 
+            SetLastError(0xdeadbeef);
+            ret = DeleteFileA(dll_name);
+            ok(ret, "DeleteFile error %d\n", GetLastError());
+
+            nt_header.OptionalHeader.AddressOfEntryPoint = 0x12345678;
+            file_size = create_test_dll( &dos_header, td[i].size_of_dos_header, &nt_header, dll_name );
+            if (!file_size)
+            {
+                ok(0, "could not create %s\n", dll_name);
+                break;
+            }
             query_image_section( i, dll_name, &nt_header );
         }
         else
@@ -831,6 +867,95 @@ static void test_Loader(void)
     nt_header.FileHeader.Machine = orig_machine;  /* restore it for the next tests */
 }
 
+static void test_FakeDLL(void)
+{
+#ifdef __i386__
+    NTSTATUS (WINAPI *pNtSetEvent)(HANDLE, ULONG *) = NULL;
+    IMAGE_EXPORT_DIRECTORY *dir;
+    HMODULE module = GetModuleHandleA("ntdll.dll");
+    HANDLE file, map, event;
+    WCHAR path[MAX_PATH];
+    DWORD *names, *funcs;
+    WORD *ordinals;
+    ULONG size;
+    void *ptr;
+    int i;
+
+    GetModuleFileNameW(module, path, MAX_PATH);
+
+    file = CreateFileW(path, GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
+    ok(file != INVALID_HANDLE_VALUE, "Failed to open %s (error %u)\n", wine_dbgstr_w(path), GetLastError());
+
+    map = CreateFileMappingW(file, NULL, PAGE_EXECUTE_READ | SEC_IMAGE, 0, 0, NULL);
+    ok(map != NULL, "CreateFileMapping failed with error %u\n", GetLastError());
+    ptr = MapViewOfFile(map, FILE_MAP_READ | FILE_MAP_EXECUTE, 0, 0, 0);
+    ok(ptr != NULL, "MapViewOfFile failed with error %u\n", GetLastError());
+
+    dir = RtlImageDirectoryEntryToData(ptr, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size);
+    ok(dir != NULL, "RtlImageDirectoryEntryToData failed\n");
+
+    names    = RVAToAddr(dir->AddressOfNames, ptr);
+    ordinals = RVAToAddr(dir->AddressOfNameOrdinals, ptr);
+    funcs    = RVAToAddr(dir->AddressOfFunctions, ptr);
+    ok(dir->NumberOfNames > 0, "Could not find any exported functions\n");
+
+    for (i = 0; i < dir->NumberOfNames; i++)
+    {
+        DWORD map_rva, dll_rva, map_offset, dll_offset;
+        char *func_name = RVAToAddr(names[i], ptr);
+        BYTE *dll_func, *map_func;
+
+        /* check only Nt functions for now */
+        if (strncmp(func_name, "Zw", 2) && strncmp(func_name, "Nt", 2))
+            continue;
+
+        dll_func = (BYTE *)GetProcAddress(module, func_name);
+        ok(dll_func != NULL, "%s: GetProcAddress returned NULL\n", func_name);
+        if (dll_func[0] == 0x90 && dll_func[1] == 0x90 &&
+            dll_func[2] == 0x90 && dll_func[3] == 0x90)
+        {
+            todo_wine ok(0, "%s: Export is a stub-function, skipping\n", func_name);
+            continue;
+        }
+
+        /* check position in memory */
+        dll_rva = (DWORD_PTR)dll_func - (DWORD_PTR)module;
+        map_rva = funcs[ordinals[i]];
+        ok(map_rva == dll_rva, "%s: Rva of mapped function (0x%x) does not match dll (0x%x)\n",
+           func_name, dll_rva, map_rva);
+
+        /* check position in file */
+        map_offset = (DWORD_PTR)RtlImageRvaToVa(RtlImageNtHeader(ptr),    ptr,    map_rva, NULL) - (DWORD_PTR)ptr;
+        dll_offset = (DWORD_PTR)RtlImageRvaToVa(RtlImageNtHeader(module), module, dll_rva, NULL) - (DWORD_PTR)module;
+        ok(map_offset == dll_offset, "%s: File offset of mapped function (0x%x) does not match dll (0x%x)\n",
+           func_name, map_offset, dll_offset);
+
+        /* check function content */
+        map_func = RVAToAddr(map_rva, ptr);
+        ok(!memcmp(map_func, dll_func, 0x20), "%s: Function content does not match!\n", func_name);
+
+        if (!strcmp(func_name, "NtSetEvent"))
+            pNtSetEvent = (void *)map_func;
+    }
+
+    ok(pNtSetEvent != NULL, "Could not find NtSetEvent export\n");
+    if (pNtSetEvent)
+    {
+        event = CreateEventA(NULL, TRUE, FALSE, NULL);
+        ok(event != NULL, "CreateEvent failed with error %u\n", GetLastError());
+        pNtSetEvent(event, 0);
+        ok(WaitForSingleObject(event, 0) == WAIT_OBJECT_0, "Event was not signaled\n");
+        pNtSetEvent(event, 0);
+        ok(WaitForSingleObject(event, 0) == WAIT_OBJECT_0, "Event was not signaled\n");
+        CloseHandle(event);
+    }
+
+    UnmapViewOfFile(ptr);
+    CloseHandle(map);
+    CloseHandle(file);
+#endif
+}
+
 /* Verify linking style of import descriptors */
 static void test_ImportDescriptors(void)
 {
@@ -1457,6 +1582,7 @@ static void test_import_resolution(void)
             ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
                 (void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
             ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
+            FreeLibrary( mod2 );
             FreeLibrary( mod );
             break;
         case 2:  /* load without IMAGE_FILE_DLL doesn't resolve imports */
@@ -2991,10 +3117,13 @@ static void test_ResolveDelayLoadedAPI(void)
 
 static void test_InMemoryOrderModuleList(void)
 {
-    LIST_ENTRY *entry1, *mark1 = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
-    LIST_ENTRY *entry2, *mark2 = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
+    PEB_LDR_DATA *ldr = NtCurrentTeb()->Peb->LdrData;
+    LIST_ENTRY *entry1, *mark1 = &ldr->InLoadOrderModuleList;
+    LIST_ENTRY *entry2, *mark2 = &ldr->InMemoryOrderModuleList;
     LDR_MODULE *module1, *module2;
 
+    ok(ldr->Initialized == TRUE, "expected TRUE, got %u\n", ldr->Initialized);
+
     for (entry1 = mark1->Flink, entry2 = mark2->Flink;
          entry1 != mark1 && entry2 != mark2;
          entry1 = entry1->Flink, entry2 = entry2->Flink)
@@ -3007,6 +3136,79 @@ static void test_InMemoryOrderModuleList(void)
     ok(entry2 == mark2, "expected entry2 == mark2, got %p and %p\n", entry2, mark2);
 }
 
+static inline WCHAR toupperW(WCHAR c)
+{
+    WCHAR tmp = c;
+    CharUpperBuffW(&tmp, 1);
+    return tmp;
+}
+
+static ULONG hash_basename(const WCHAR *basename)
+{
+    WORD version = MAKEWORD(NtCurrentTeb()->Peb->OSMinorVersion,
+                            NtCurrentTeb()->Peb->OSMajorVersion);
+    ULONG hash = 0;
+
+    if (version >= 0x0602)
+    {
+        for (; *basename; basename++)
+            hash = hash * 65599 + toupperW(*basename);
+    }
+    else if (version == 0x0601)
+    {
+        for (; *basename; basename++)
+            hash = hash + 65599 * toupperW(*basename);
+    }
+    else
+        hash = toupperW(basename[0]) - 'A';
+
+    return hash & 31;
+}
+
+static void test_HashLinks(void)
+{
+    static WCHAR ntdllW[] = {'n','t','d','l','l','.','d','l','l',0};
+    static WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0};
+
+    LIST_ENTRY *hash_map, *entry, *mark;
+    LDR_MODULE *module;
+    BOOL found;
+
+    entry = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
+    entry = entry->Flink;
+
+    module = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
+    entry = module->HashLinks.Blink;
+
+    hash_map = entry - hash_basename(module->BaseDllName.Buffer);
+
+    mark = &hash_map[hash_basename(ntdllW)];
+    found = FALSE;
+    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
+    {
+        module = CONTAINING_RECORD(entry, LDR_MODULE, HashLinks);
+        if (!lstrcmpiW(module->BaseDllName.Buffer, ntdllW))
+        {
+            found = TRUE;
+            break;
+        }
+    }
+    ok(found, "Could not find ntdll\n");
+
+    mark = &hash_map[hash_basename(kernel32W)];
+    found = FALSE;
+    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
+    {
+        module = CONTAINING_RECORD(entry, LDR_MODULE, HashLinks);
+        if (!lstrcmpiW(module->BaseDllName.Buffer, kernel32W))
+        {
+            found = TRUE;
+            break;
+        }
+    }
+    ok(found, "Could not find kernel32\n");
+}
+
 START_TEST(loader)
 {
     int argc;
@@ -3062,10 +3264,12 @@ START_TEST(loader)
     }
 
     test_Loader();
+    test_FakeDLL();
     test_ResolveDelayLoadedAPI();
     test_ImportDescriptors();
     test_section_access();
     test_import_resolution();
     test_ExitProcess();
     test_InMemoryOrderModuleList();
+    test_HashLinks();
 }
index 70a3d24..5f0a836 100755 (executable)
 
 static const WCHAR upper_case[] = {'\t','J','U','S','T','!',' ','A',',',' ','T','E','S','T',';',' ','S','T','R','I','N','G',' ','1','/','*','+','-','.','\r','\n',0};
 static const WCHAR lower_case[] = {'\t','j','u','s','t','!',' ','a',',',' ','t','e','s','t',';',' ','s','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
+static const WCHAR title_case[] = {'\t','J','u','s','t','!',' ','A',',',' ','T','e','s','t',';',' ','S','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
 static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0};
 static const WCHAR localeW[] = {'e','n','-','U','S',0};
 static const WCHAR fooW[] = {'f','o','o',0};
 static const WCHAR emptyW[] = {0};
+static const WCHAR invalidW[] = {'i','n','v','a','l','i','d',0};
 
 static inline unsigned int strlenW( const WCHAR *str )
 {
@@ -101,6 +103,7 @@ static INT (WINAPI *pGetGeoInfoW)(GEOID, GEOTYPE, LPWSTR, INT, LANGID);
 static BOOL (WINAPI *pEnumSystemGeoID)(GEOCLASS, GEOID, GEO_ENUMPROC);
 static BOOL (WINAPI *pGetSystemPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
 static BOOL (WINAPI *pGetThreadPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
+static BOOL (WINAPI *pGetUserPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*);
 static WCHAR (WINAPI *pRtlUpcaseUnicodeChar)(WCHAR);
 static INT (WINAPI *pGetNumberFormatEx)(LPCWSTR, DWORD, LPCWSTR, const NUMBERFMTW *, LPWSTR, int);
 
@@ -133,6 +136,7 @@ static void InitFunctionPointers(void)
   X(EnumSystemGeoID);
   X(GetSystemPreferredUILanguages);
   X(GetThreadPreferredUILanguages);
+  X(GetUserPreferredUILanguages);
   X(GetNumberFormatEx);
 
   mod = GetModuleHandleA("ntdll");
@@ -254,7 +258,7 @@ static const struct neutralsublang_name2_t neutralsublang_names2[] = {
     { {'e','s',0}, {'e','s','-','E','S',0},
       MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT),
       MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH), SORT_DEFAULT) /* vista */,
-      {'e','s','-','E','S','_','t','r','a','d','n','l',0}, 0x1 },
+      {'e','s','-','E','S','_','t','r','a','d','n','l',0} },
     { {'g','a',0}, {'g','a','-','I','E',0},
       MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT), 0, {0}, 0x3 },
     { {'i','t',0}, {'i','t','-','I','T',0},
@@ -272,7 +276,7 @@ static const struct neutralsublang_name2_t neutralsublang_names2[] = {
     { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0},
       MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
     { {'z','h',0}, {'z','h','-','C','N',0},
-      MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 0, {0}, 0x3 },
+      MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT) },
     { {0} }
 };
 
@@ -2198,9 +2202,37 @@ static void test_CompareStringEx(void)
 
 }
 
+static const DWORD lcmap_invalid_flags[] = {
+    0,
+    LCMAP_HIRAGANA | LCMAP_KATAKANA,
+    LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
+    LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
+    LCMAP_LOWERCASE | SORT_STRINGSORT,
+    LCMAP_UPPERCASE | NORM_IGNORESYMBOLS,
+    LCMAP_LOWERCASE | NORM_IGNORESYMBOLS,
+    LCMAP_UPPERCASE | NORM_IGNORENONSPACE,
+    LCMAP_LOWERCASE | NORM_IGNORENONSPACE,
+    LCMAP_HIRAGANA | NORM_IGNORENONSPACE,
+    LCMAP_HIRAGANA | NORM_IGNORESYMBOLS,
+    LCMAP_HIRAGANA | LCMAP_SIMPLIFIED_CHINESE,
+    LCMAP_HIRAGANA | LCMAP_TRADITIONAL_CHINESE,
+    LCMAP_KATAKANA | NORM_IGNORENONSPACE,
+    LCMAP_KATAKANA | NORM_IGNORESYMBOLS,
+    LCMAP_KATAKANA | LCMAP_SIMPLIFIED_CHINESE,
+    LCMAP_KATAKANA | LCMAP_TRADITIONAL_CHINESE,
+    LCMAP_FULLWIDTH | NORM_IGNORENONSPACE,
+    LCMAP_FULLWIDTH | NORM_IGNORESYMBOLS,
+    LCMAP_FULLWIDTH | LCMAP_SIMPLIFIED_CHINESE,
+    LCMAP_FULLWIDTH | LCMAP_TRADITIONAL_CHINESE,
+    LCMAP_HALFWIDTH | NORM_IGNORENONSPACE,
+    LCMAP_HALFWIDTH | NORM_IGNORESYMBOLS,
+    LCMAP_HALFWIDTH | LCMAP_SIMPLIFIED_CHINESE,
+    LCMAP_HALFWIDTH | LCMAP_TRADITIONAL_CHINESE,
+};
+
 static void test_LCMapStringA(void)
 {
-    int ret, ret2;
+    int ret, ret2, i;
     char buf[256], buf2[256];
     static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n";
     static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n";
@@ -2220,30 +2252,18 @@ static void test_LCMapStringA(void)
     ok(GetLastError() == ERROR_INVALID_FLAGS,
        "unexpected error code %d\n", GetLastError());
 
-    ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA,
-                       upper_case, -1, buf, sizeof(buf));
-    ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n");
-    ok(GetLastError() == ERROR_INVALID_FLAGS,
-       "unexpected error code %d\n", GetLastError());
-
-    ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
-                       upper_case, -1, buf, sizeof(buf));
-    ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n");
-    ok(GetLastError() == ERROR_INVALID_FLAGS,
-       "unexpected error code %d\n", GetLastError());
-
-    ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
-                       upper_case, -1, buf, sizeof(buf));
-    ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n");
-    ok(GetLastError() == ERROR_INVALID_FLAGS,
-       "unexpected error code %d\n", GetLastError());
-
-    /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
-    SetLastError(0xdeadbeef);
-    ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT,
-                       upper_case, -1, buf, sizeof(buf));
-    ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %d\n", GetLastError());
-    ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n");
+    /* test invalid flag combinations */
+    for (i = 0; i < sizeof(lcmap_invalid_flags)/sizeof(lcmap_invalid_flags[0]); i++) {
+        lstrcpyA(buf, "foo");
+        SetLastError(0xdeadbeef);
+        ret = LCMapStringA(LOCALE_USER_DEFAULT, lcmap_invalid_flags[i],
+                           lower_case, -1, buf, sizeof(buf));
+        ok(GetLastError() == ERROR_INVALID_FLAGS,
+           "LCMapStringA (flag %08x) unexpected error code %d\n",
+           lcmap_invalid_flags[i], GetLastError());
+        ok(!ret, "LCMapStringA (flag %08x) should return 0, got %d\n",
+           lcmap_invalid_flags[i], ret);
+    }
 
     /* test LCMAP_LOWERCASE */
     ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE,
@@ -2354,6 +2374,14 @@ static void test_LCMapStringA(void)
        lstrlenA(symbols_stripped) + 1, ret);
     ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
 
+    /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
+    lstrcpyA(buf, "foo");
+    ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE,
+                       lower_case, -1, buf, sizeof(buf));
+    ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
+       lstrlenA(symbols_stripped) + 1, ret);
+    ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
+
     /* test srclen = 0 */
     SetLastError(0xdeadbeef);
     ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
@@ -2366,48 +2394,48 @@ typedef INT (*lcmapstring_wrapper)(DWORD, LPCWSTR, INT, LPWSTR, INT);
 
 static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *func_name)
 {
-    int ret, ret2;
+    static const WCHAR japanese_text[] = {
+        0x3044, 0x309d, 0x3084, 0x3001, 0x30a4, 0x30fc, 0x30cf,
+        0x30c8, 0x30fc, 0x30f4, 0x30a9, 0x306e, 0x2026, 0
+    };
+    static const WCHAR hiragana_text[] = {
+        0x3044, 0x309d, 0x3084, 0x3001, 0x3044, 0x30fc, 0x306f,
+        0x3068, 0x30fc, 0x3094, 0x3049, 0x306e, 0x2026, 0
+    };
+    static const WCHAR katakana_text[] = {
+        0x30a4, 0x30fd, 0x30e4, 0x3001, 0x30a4, 0x30fc, 0x30cf,
+        0x30c8, 0x30fc, 0x30f4, 0x30a9, 0x30ce, 0x2026, 0
+    };
+    static const WCHAR halfwidth_text[] = {
+        0x3044, 0x309d, 0x3084, 0xff64, 0xff72, 0xff70, 0xff8a,
+        0xff84, 0xff70, 0xff73, 0xff9e, 0xff6b, 0x306e, 0x2026, 0
+    };
+    int ret, ret2, i;
     WCHAR buf[256], buf2[256];
     char *p_buf = (char *)buf, *p_buf2 = (char *)buf2;
 
+    /* LCMAP_LOWERCASE | LCMAP_UPPERCASE makes LCMAP_TITLECASE, so it's valid now. */
     ret = func_ptr(LCMAP_LOWERCASE | LCMAP_UPPERCASE,
-                       upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
-    if (broken(ret))
-        ok(lstrcmpW(buf, upper_case) == 0, "Expected upper case string\n");
-    else
-    {
-        ok(!ret, "%s LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n", func_name);
-        ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
-           func_name, GetLastError());
+                       lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
+    todo_wine ok(ret == lstrlenW(title_case) + 1 || broken(!ret),
+       "%s ret %d, error %d, expected value %d\n", func_name,
+       ret, GetLastError(), lstrlenW(title_case) + 1);
+    todo_wine ok(lstrcmpW(buf, title_case) == 0 || broken(!ret),
+       "Expected title case string\n");
+
+    /* test invalid flag combinations */
+    for (i = 0; i < sizeof(lcmap_invalid_flags)/sizeof(lcmap_invalid_flags[0]); i++) {
+        lstrcpyW(buf, fooW);
+        SetLastError(0xdeadbeef);
+        ret = func_ptr(lcmap_invalid_flags[i],
+                           lower_case, -1, buf, sizeof(buf));
+        ok(GetLastError() == ERROR_INVALID_FLAGS,
+           "%s (flag %08x) unexpected error code %d\n",
+           func_name, lcmap_invalid_flags[i], GetLastError());
+        ok(!ret, "%s (flag %08x) should return 0, got %d\n",
+           func_name, lcmap_invalid_flags[i], ret);
     }
 
-    ret = func_ptr(LCMAP_HIRAGANA | LCMAP_KATAKANA,
-                       upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
-    ok(!ret, "%s LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n", func_name);
-    ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
-       func_name, GetLastError());
-
-    ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_FULLWIDTH,
-                       upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
-    ok(!ret, "%s LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n", func_name);
-    ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
-       func_name, GetLastError());
-
-    ret = func_ptr(LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE,
-                       upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
-    ok(!ret, "%s LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n",
-       func_name);
-    ok(GetLastError() == ERROR_INVALID_FLAGS, "%s unexpected error code %d\n",
-       func_name, GetLastError());
-
-    /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
-    SetLastError(0xdeadbeef);
-    ret = func_ptr(LCMAP_LOWERCASE | SORT_STRINGSORT,
-                       upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
-    ok(GetLastError() == ERROR_INVALID_FLAGS, "%s expected ERROR_INVALID_FLAGS, got %d\n",
-       func_name, GetLastError());
-    ok(!ret, "%s SORT_STRINGSORT without LCMAP_SORTKEY must fail\n", func_name);
-
     /* test LCMAP_LOWERCASE */
     ret = func_ptr(LCMAP_LOWERCASE,
                        upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
@@ -2422,6 +2450,59 @@ static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *f
        ret, GetLastError(), lstrlenW(lower_case) + 1);
     ok(!lstrcmpW(buf, upper_case), "%s string compare mismatch\n", func_name);
 
+    /* test LCMAP_HIRAGANA */
+    ret = func_ptr(LCMAP_HIRAGANA,
+                   japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
+    ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
+       ret, GetLastError(), lstrlenW(hiragana_text) + 1);
+    ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name);
+
+    buf[0] = 0x30f5; /* KATAKANA LETTER SMALL KA */
+    ret = func_ptr(LCMAP_HIRAGANA, buf, 1, buf2, 1);
+    ok(ret == 1, "%s ret %d, error %d, expected value 1\n", func_name,
+       ret, GetLastError());
+    /* U+3095: HIRAGANA LETTER SMALL KA was added in Unicode 3.2 */
+    ok(buf2[0] == 0x3095 || broken(buf2[0] == 0x30f5 /* Vista and earlier versions */),
+       "%s expected %04x, got %04x\n", func_name, 0x3095, buf2[0]);
+
+    /* test LCMAP_KATAKANA | LCMAP_LOWERCASE */
+    ret = func_ptr(LCMAP_KATAKANA | LCMAP_LOWERCASE,
+                   japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
+    ok(ret == lstrlenW(katakana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
+       ret, GetLastError(), lstrlenW(katakana_text) + 1);
+    ok(!lstrcmpW(buf, katakana_text), "%s string compare mismatch\n", func_name);
+
+    /* test LCMAP_FULLWIDTH */
+    ret = func_ptr(LCMAP_FULLWIDTH,
+                   halfwidth_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
+    ok(ret == lstrlenW(japanese_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
+       ret, GetLastError(), lstrlenW(japanese_text) + 1);
+    ok(!lstrcmpW(buf, japanese_text), "%s string compare mismatch\n", func_name);
+
+    ret2 = func_ptr(LCMAP_FULLWIDTH, halfwidth_text, -1, NULL, 0);
+    ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret2, ret);
+
+    /* test LCMAP_FULLWIDTH | LCMAP_HIRAGANA
+       (half-width katakana is converted into full-wdith hiragana) */
+    ret = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA,
+                   halfwidth_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
+    ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
+       ret, GetLastError(), lstrlenW(hiragana_text) + 1);
+    ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name);
+
+    ret2 = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA, halfwidth_text, -1, NULL, 0);
+    ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
+
+    /* test LCMAP_HALFWIDTH */
+    ret = func_ptr(LCMAP_HALFWIDTH,
+                   japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
+    ok(ret == lstrlenW(halfwidth_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
+       ret, GetLastError(), lstrlenW(halfwidth_text) + 1);
+    ok(!lstrcmpW(buf, halfwidth_text), "%s string compare mismatch\n", func_name);
+
+    ret2 = func_ptr(LCMAP_HALFWIDTH, japanese_text, -1, NULL, 0);
+    ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
+
     /* test buffer overflow */
     SetLastError(0xdeadbeef);
     ret = func_ptr(LCMAP_UPPERCASE,
@@ -2429,6 +2510,14 @@ static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *f
     ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
        "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
 
+    /* KATAKANA LETTER GA (U+30AC) is converted into two half-width characters.
+       Thus, it requires two WCHARs. */
+    buf[0] = 0x30ac;
+    SetLastError(0xdeadbeef);
+    ret = func_ptr(LCMAP_HALFWIDTH, buf, 1, buf2, 1);
+    ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
+
     /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
     lstrcpyW(buf, lower_case);
     ret = func_ptr(LCMAP_UPPERCASE,
@@ -2502,6 +2591,14 @@ static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *f
     lstrlenW(symbols_stripped) + 1, ret);
     ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
 
+    /* test NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE */
+    lstrcpyW(buf, fooW);
+    ret = func_ptr(NORM_IGNORESYMBOLS | NORM_IGNORENONSPACE,
+                       lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR));
+    ok(ret == lstrlenW(symbols_stripped) + 1, "%s func_ptr should return %d, ret = %d\n", func_name,
+    lstrlenW(symbols_stripped) + 1, ret);
+    ok(!lstrcmpW(buf, symbols_stripped), "%s string comparison mismatch\n", func_name);
+
     /* test srclen = 0 */
     SetLastError(0xdeadbeef);
     ret = func_ptr(0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR));
@@ -2551,7 +2648,7 @@ static void test_LCMapStringEx(void)
     trace("testing LCMapStringEx\n");
 
     SetLastError(0xdeadbeef);
-    ret = pLCMapStringEx(fooW, LCMAP_LOWERCASE,
+    ret = pLCMapStringEx(invalidW, LCMAP_LOWERCASE,
                          upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR), NULL, NULL, 0);
     todo_wine {
     ok(!ret, "LCMapStringEx should fail with bad locale name\n");
@@ -2581,25 +2678,26 @@ static void test_LCMapStringEx(void)
 
 struct neutralsublang_name_t {
     WCHAR name[3];
+    WCHAR sname[16];
     LCID lcid;
     int todo;
 };
 
 static const struct neutralsublang_name_t neutralsublang_names[] = {
-    { {'a','r',0}, MAKELCID(MAKELANGID(LANG_ARABIC,     SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
-    { {'a','z',0}, MAKELCID(MAKELANGID(LANG_AZERI,      SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
-    { {'d','e',0}, MAKELCID(MAKELANGID(LANG_GERMAN,     SUBLANG_GERMAN), SORT_DEFAULT) },
-    { {'e','n',0}, MAKELCID(MAKELANGID(LANG_ENGLISH,    SUBLANG_ENGLISH_US), SORT_DEFAULT) },
-    { {'e','s',0}, MAKELCID(MAKELANGID(LANG_SPANISH,    SUBLANG_SPANISH_MODERN), SORT_DEFAULT), 1 },
-    { {'g','a',0}, MAKELCID(MAKELANGID(LANG_IRISH,      SUBLANG_IRISH_IRELAND), SORT_DEFAULT) },
-    { {'i','t',0}, MAKELCID(MAKELANGID(LANG_ITALIAN,    SUBLANG_ITALIAN), SORT_DEFAULT) },
-    { {'m','s',0}, MAKELCID(MAKELANGID(LANG_MALAY,      SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
-    { {'n','l',0}, MAKELCID(MAKELANGID(LANG_DUTCH,      SUBLANG_DUTCH), SORT_DEFAULT) },
-    { {'p','t',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
-    { {'s','r',0}, MAKELCID(MAKELANGID(LANG_SERBIAN,    SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
-    { {'s','v',0}, MAKELCID(MAKELANGID(LANG_SWEDISH,    SUBLANG_SWEDISH), SORT_DEFAULT) },
-    { {'u','z',0}, MAKELCID(MAKELANGID(LANG_UZBEK,      SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
-    { {'z','h',0}, MAKELCID(MAKELANGID(LANG_CHINESE,    SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT), 1 },
+    { {'a','r',0}, {'a','r','-','S','A',0}, MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_SAUDI_ARABIA), SORT_DEFAULT) },
+    { {'a','z',0}, {'a','z','-','L','a','t','n','-','A','Z',0}, MAKELCID(MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), SORT_DEFAULT) },
+    { {'d','e',0}, {'d','e','-','D','E',0}, MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT) },
+    { {'e','n',0}, {'e','n','-','U','S',0}, MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) },
+    { {'e','s',0}, {'e','s','-','E','S',0}, MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT) },
+    { {'g','a',0}, {'g','a','-','I','E',0}, MAKELCID(MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), SORT_DEFAULT) },
+    { {'i','t',0}, {'i','t','-','I','T',0}, MAKELCID(MAKELANGID(LANG_ITALIAN, SUBLANG_ITALIAN), SORT_DEFAULT) },
+    { {'m','s',0}, {'m','s','-','M','Y',0}, MAKELCID(MAKELANGID(LANG_MALAY, SUBLANG_MALAY_MALAYSIA), SORT_DEFAULT) },
+    { {'n','l',0}, {'n','l','-','N','L',0}, MAKELCID(MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH), SORT_DEFAULT) },
+    { {'p','t',0}, {'p','t','-','B','R',0}, MAKELCID(MAKELANGID(LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN), SORT_DEFAULT) },
+    { {'s','r',0}, {'s','r','-','L','a','t','n','-','R','S',0}, MAKELCID(MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN), SORT_DEFAULT), 1 },
+    { {'s','v',0}, {'s','v','-','S','E',0}, MAKELCID(MAKELANGID(LANG_SWEDISH, SUBLANG_SWEDISH), SORT_DEFAULT) },
+    { {'u','z',0}, {'u','z','-','L','a','t','n','-','U','Z',0}, MAKELCID(MAKELANGID(LANG_UZBEK, SUBLANG_UZBEK_LATIN), SORT_DEFAULT) },
+    { {'z','h',0}, {'z','h','-','C','N',0}, MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT) },
     { {0} }
 };
 
@@ -2609,6 +2707,13 @@ static void test_LocaleNameToLCID(void)
     INT ret;
     WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
     static const WCHAR enW[] = {'e','n',0};
+    static const WCHAR esesW[] = {'e','s','-','e','s',0};
+    static const WCHAR zhHansW[] = {'z','h','-','H','a','n','s',0};
+    static const WCHAR zhhansW[] = {'z','h','-','h','a','n','s',0};
+    static const WCHAR zhHantW[] = {'z','h','-','H','a','n','t',0};
+    static const WCHAR zhhantW[] = {'z','h','-','h','a','n','t',0};
+    static const WCHAR zhcnW[] = {'z','h','-','C','N',0};
+    static const WCHAR zhhkW[] = {'z','h','-','H','K',0};
 
     if (!pLocaleNameToLCID)
     {
@@ -2645,10 +2750,14 @@ static void test_LocaleNameToLCID(void)
 
     /* bad name */
     SetLastError(0xdeadbeef);
-    lcid = pLocaleNameToLCID(fooW, 0);
+    lcid = pLocaleNameToLCID(invalidW, 0);
     ok(!lcid && GetLastError() == ERROR_INVALID_PARAMETER,
        "Expected lcid == 0, got %08x, error %d\n", lcid, GetLastError());
 
+    /* lower-case */
+    lcid = pLocaleNameToLCID(esesW, 0);
+    ok(lcid == MAKELCID(MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT), "Got wrong lcid for es-es: 0x%x\n", lcid);
+
     /* english neutral name */
     lcid = pLocaleNameToLCID(enW, 0);
     ok(lcid == MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) ||
@@ -2667,11 +2776,49 @@ static void test_LocaleNameToLCID(void)
             *buffer = 0;
             ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
             ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(ptr->name), ret);
-            ok(lstrcmpW(ptr->name, buffer), "%s: got wrong locale name %s\n",
+            ok(!lstrcmpW(ptr->sname, buffer), "%s: got wrong locale name %s\n",
                 wine_dbgstr_w(ptr->name), wine_dbgstr_w(buffer));
 
             ptr++;
         }
+
+        /* zh-Hant */
+        lcid = pLocaleNameToLCID(zhHantW, 0);
+        todo_wine ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_HONGKONG), SORT_DEFAULT),
+           "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhHantW), lcid);
+        ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
+        ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhHantW), ret);
+        todo_wine ok(!lstrcmpW(zhhkW, buffer), "%s: got wrong locale name %s\n",
+           wine_dbgstr_w(zhHantW), wine_dbgstr_w(buffer));
+
+        /* zh-hant */
+        lcid = pLocaleNameToLCID(zhhantW, 0);
+        todo_wine ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_HONGKONG), SORT_DEFAULT),
+           "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhhantW),
+           MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_HONGKONG), SORT_DEFAULT));
+        ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
+        ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhhantW), ret);
+        todo_wine ok(!lstrcmpW(zhhkW, buffer), "%s: got wrong locale name %s\n",
+           wine_dbgstr_w(zhhantW), wine_dbgstr_w(buffer));
+
+        /* zh-Hans */
+        lcid = pLocaleNameToLCID(zhHansW, 0);
+        todo_wine ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT),
+           "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhHansW), lcid);
+        ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
+        ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhHansW), ret);
+        todo_wine ok(!lstrcmpW(zhcnW, buffer), "%s: got wrong locale name %s\n",
+           wine_dbgstr_w(zhHansW), wine_dbgstr_w(buffer));
+
+        /* zh-hans */
+        lcid = pLocaleNameToLCID(zhhansW, 0);
+        todo_wine ok(lcid == MAKELCID(MAKELANGID(LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT),
+           "%s: got wrong lcid 0x%04x\n", wine_dbgstr_w(zhhansW),
+           MAKELCID(MAKELANGID(LANG_CHINESE_SIMPLIFIED, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT));
+        ret = pLCIDToLocaleName(lcid, buffer, sizeof(buffer)/sizeof(WCHAR), 0);
+        ok(ret > 0, "%s: got %d\n", wine_dbgstr_w(zhhansW), ret);
+        todo_wine ok(!lstrcmpW(zhcnW, buffer), "%s: got wrong locale name %s\n",
+           wine_dbgstr_w(zhhansW), wine_dbgstr_w(buffer));
     }
 }
 
@@ -4370,7 +4517,8 @@ static void test_IsValidLocaleName(void)
 {
     static const WCHAR enusW[] = {'e','n','-','U','S',0};
     static const WCHAR zzW[] = {'z','z',0};
-    static const WCHAR zzzzW[] = {'z','z','-','Z','Z',0};
+    static const WCHAR zz_zzW[] = {'z','z','-','Z','Z',0};
+    static const WCHAR zzzzW[] = {'z','z','z','z',0};
     BOOL ret;
 
     if (!pIsValidLocaleName)
@@ -4382,7 +4530,9 @@ static void test_IsValidLocaleName(void)
     ret = pIsValidLocaleName(enusW);
     ok(ret, "IsValidLocaleName failed\n");
     ret = pIsValidLocaleName(zzW);
-    ok(!ret, "IsValidLocaleName should have failed\n");
+    ok(!ret || broken(ret), "IsValidLocaleName should have failed\n");
+    ret = pIsValidLocaleName(zz_zzW);
+    ok(!ret || broken(ret), "IsValidLocaleName should have failed\n");
     ret = pIsValidLocaleName(zzzzW);
     ok(!ret, "IsValidLocaleName should have failed\n");
     ret = pIsValidLocaleName(LOCALE_NAME_INVARIANT);
@@ -4629,7 +4779,7 @@ static void test_EnumSystemGeoID(void)
 struct invariant_entry {
   const char *name;
   int id;
-  const char *expect;
+  const char *expect, *expect2;
 };
 
 #define X(x)  #x, x
@@ -4640,7 +4790,7 @@ static const struct invariant_entry invariant_list[] = {
     { X(LOCALE_SNATIVELANGNAME),          "Invariant Language" },
     { X(LOCALE_ICOUNTRY),                 "1" },
     { X(LOCALE_SENGCOUNTRY),              "Invariant Country" },
-    { X(LOCALE_SABBREVCTRYNAME),          "IVC" },
+    { X(LOCALE_SABBREVCTRYNAME),          "IVC", "" },
     { X(LOCALE_SNATIVECTRYNAME),          "Invariant Country" },
     { X(LOCALE_IDEFAULTLANGUAGE),         "0409" },
     { X(LOCALE_IDEFAULTCOUNTRY),          "1" },
@@ -4767,19 +4917,21 @@ static void test_invariant(void)
     else
     {
         len = strlen(ptr->expect)+1; /* include \0 */
-        ok(ret == len, "For id %d, expected ret == %d, got %d, error %d\n",
+        ok(ret == len || (ptr->expect2 && ret == strlen(ptr->expect2)+1),
+           "For id %d, expected ret == %d, got %d, error %d\n",
             ptr->id, len, ret, GetLastError());
-        ok(!strcmp(buffer, ptr->expect), "For id %d, Expected %s, got '%s'\n",
+        ok(!strcmp(buffer, ptr->expect) || (ptr->expect2 && !strcmp(buffer, ptr->expect2)),
+           "For id %d, Expected %s, got '%s'\n",
             ptr->id, ptr->expect, buffer);
     }
 
     ptr++;
   }
 
 if ((PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) != LANG_ENGLISH) ||
-      (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH))
if ((LANGIDFROMLCID(GetSystemDefaultLCID()) != MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)) ||
+     (LANGIDFROMLCID(GetThreadLocale()) != MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)))
   {
-      skip("Non-English locale\n");
+      skip("Non US-English locale\n");
   }
   else
   {
@@ -5026,6 +5178,143 @@ static void test_GetThreadPreferredUILanguages(void)
     HeapFree(GetProcessHeap(), 0, buf);
 }
 
+static void test_GetUserPreferredUILanguages(void)
+{
+    BOOL ret;
+    ULONG count, size, size_id, size_name, size_buffer;
+    WCHAR *buffer;
+
+
+    if (!pGetUserPreferredUILanguages)
+    {
+        win_skip("GetUserPreferredUILanguages is not available.\n");
+        return;
+    }
+
+    count = 0xdeadbeef;
+    size = 0;
+    SetLastError(0xdeadbeef);
+    ret = pGetUserPreferredUILanguages(MUI_FULL_LANGUAGE, &count, NULL, &size);
+    ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
+    ok(ERROR_INVALID_PARAMETER == GetLastError(),
+       "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+    count = 0xdeadbeef;
+    size = 0;
+    SetLastError(0xdeadbeef);
+    ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID | MUI_FULL_LANGUAGE, &count, NULL, &size);
+    ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
+    ok(ERROR_INVALID_PARAMETER == GetLastError(),
+       "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+    count = 0xdeadbeef;
+    size = 0;
+    SetLastError(0xdeadbeef);
+    ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS, &count, NULL, &size);
+    ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
+    ok(ERROR_INVALID_PARAMETER == GetLastError(),
+       "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+    count = 0xdeadbeef;
+    size = 1;
+    SetLastError(0xdeadbeef);
+    ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size);
+    ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
+    ok(ERROR_INVALID_PARAMETER == GetLastError(),
+       "Expected error ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+    count = 0xdeadbeef;
+    size_id = 0;
+    SetLastError(0xdeadbeef);
+    ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, NULL, &size_id);
+    ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
+    ok(count, "Expected count > 0\n");
+    ok(size_id  % 5 == 1, "Expected size (%d) %% 5 == 1\n", size_id);
+
+    count = 0xdeadbeef;
+    size_name = 0;
+    SetLastError(0xdeadbeef);
+    ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &count, NULL, &size_name);
+    ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
+    ok(count, "Expected count > 0\n");
+    ok(size_name % 6 == 1, "Expected size (%d) %% 6 == 1\n", size_name);
+
+    size_buffer = max(size_id, size_name);
+    if(!size_buffer)
+    {
+        skip("No valid buffer size\n");
+        return;
+    }
+
+    buffer = HeapAlloc(GetProcessHeap(), 0, size_buffer * sizeof(WCHAR));
+
+    count = 0xdeadbeef;
+    size = size_buffer;
+    memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
+    SetLastError(0xdeadbeef);
+    ret = pGetUserPreferredUILanguages(0, &count, buffer, &size);
+    ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
+    ok(count, "Expected count > 0\n");
+    ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
+    if (ret && size % 6 == 1)
+        ok(!buffer[size -2] && !buffer[size -1],
+           "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
+           buffer[size -2], buffer[size -1]);
+
+    count = 0xdeadbeef;
+    size = size_buffer;
+    memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
+    SetLastError(0xdeadbeef);
+    ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
+    ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
+    ok(count, "Expected count > 0\n");
+    ok(size % 5 == 1, "Expected size (%d) %% 5 == 1\n", size);
+    if (ret && size % 5 == 1)
+        ok(!buffer[size -2] && !buffer[size -1],
+           "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
+           buffer[size -2], buffer[size -1]);
+
+    count = 0xdeadbeef;
+    size = size_buffer;
+    SetLastError(0xdeadbeef);
+    ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &count, buffer, &size);
+    ok(ret, "Expected GetUserPreferredUILanguages to succeed\n");
+    ok(count, "Expected count > 0\n");
+    ok(size % 6 == 1, "Expected size (%d) %% 6 == 1\n", size);
+    if (ret && size % 5 == 1)
+        ok(!buffer[size -2] && !buffer[size -1],
+           "Expected last two WCHARs being empty, got 0x%x 0x%x\n",
+           buffer[size -2], buffer[size -1]);
+
+    count = 0xdeadbeef;
+    size = 1;
+    SetLastError(0xdeadbeef);
+    ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
+    ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
+    ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
+       "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+
+    count = 0xdeadbeef;
+    size = size_id -1;
+    memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
+    SetLastError(0xdeadbeef);
+    ret = pGetUserPreferredUILanguages(MUI_LANGUAGE_ID, &count, buffer, &size);
+    ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
+    ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
+       "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+
+    count = 0xdeadbeef;
+    size = size_id -2;
+    memset(buffer, 0x5a, size_buffer * sizeof(WCHAR));
+    SetLastError(0xdeadbeef);
+    ret = pGetUserPreferredUILanguages(0, &count, buffer, &size);
+    ok(!ret, "Expected GetUserPreferredUILanguages to fail\n");
+    ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(),
+       "Expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+
+    HeapFree(GetProcessHeap(), 0, buffer);
+}
+
 START_TEST(locale)
 {
   InitFunctionPointers();
@@ -5071,5 +5360,6 @@ START_TEST(locale)
   test_invariant();
   test_GetSystemPreferredUILanguages();
   test_GetThreadPreferredUILanguages();
+  test_GetUserPreferredUILanguages();
   test_sorting();
 }
index 434701b..49c0643 100755 (executable)
@@ -26,6 +26,7 @@
 #include "windef.h"
 #include "winbase.h"
 #include "wine/winternl.h"
+#include "winioctl.h"
 #include "wine/test.h"
 
 #define PIPENAME "\\\\.\\PiPe\\tests_pipe.c"
@@ -37,6 +38,7 @@ static HANDLE alarm_event;
 static BOOL (WINAPI *pDuplicateTokenEx)(HANDLE,DWORD,LPSECURITY_ATTRIBUTES,
                                         SECURITY_IMPERSONATION_LEVEL,TOKEN_TYPE,PHANDLE);
 static DWORD (WINAPI *pQueueUserAPC)(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData);
+static BOOL (WINAPI *pCancelIoEx)(HANDLE handle, LPOVERLAPPED lpOverlapped);
 
 static BOOL user_apc_ran;
 static void CALLBACK user_apc(ULONG_PTR param)
@@ -47,9 +49,7 @@ static void CALLBACK user_apc(ULONG_PTR param)
 
 enum rpcThreadOp
 {
-    RPC_READFILE,
-    RPC_WRITEFILE,
-    RPC_PEEKNAMEDPIPE
+    RPC_READFILE
 };
 
 struct rpcThreadArgs
@@ -57,7 +57,7 @@ struct rpcThreadArgs
     ULONG_PTR returnValue;
     DWORD lastError;
     enum rpcThreadOp op;
-    ULONG_PTR args[6];
+    ULONG_PTR args[5];
 };
 
 static DWORD CALLBACK rpcThreadMain(LPVOID arg)
@@ -76,23 +76,6 @@ static DWORD CALLBACK rpcThreadMain(LPVOID arg)
                                                         (LPOVERLAPPED)rpcargs->args[4] ); /* overlapped */
             break;
 
-        case RPC_WRITEFILE:
-            rpcargs->returnValue = (ULONG_PTR)WriteFile( (HANDLE)rpcargs->args[0],        /* hFile */
-                                                         (LPCVOID)rpcargs->args[1],       /* buffer */
-                                                         (DWORD)rpcargs->args[2],         /* bytesToWrite */
-                                                         (LPDWORD)rpcargs->args[3],       /* bytesWritten */
-                                                         (LPOVERLAPPED)rpcargs->args[4] ); /* overlapped */
-            break;
-
-        case RPC_PEEKNAMEDPIPE:
-            rpcargs->returnValue = (ULONG_PTR)PeekNamedPipe( (HANDLE)rpcargs->args[0],    /* hPipe */
-                                                             (LPVOID)rpcargs->args[1],    /* lpvBuffer */
-                                                             (DWORD)rpcargs->args[2],     /* cbBuffer */
-                                                             (LPDWORD)rpcargs->args[3],   /* lpcbRead */
-                                                             (LPDWORD)rpcargs->args[4],   /* lpcbAvail */
-                                                             (LPDWORD)rpcargs->args[5] ); /* lpcbMessage */
-            break;
-
         default:
             SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
             rpcargs->returnValue = 0;
@@ -130,31 +113,32 @@ static BOOL RpcReadFile(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD
     return (BOOL)rpcargs.returnValue;
 }
 
-/* Runs PeekNamedPipe(...) from a different thread */
-static BOOL RpcPeekNamedPipe(HANDLE hPipe, LPVOID lpvBuffer, DWORD cbBuffer,
-                             LPDWORD lpcbRead, LPDWORD lpcbAvail, LPDWORD lpcbMessage)
+#define test_not_signaled(h) _test_not_signaled(__LINE__,h)
+static void _test_not_signaled(unsigned line, HANDLE handle)
 {
-    struct rpcThreadArgs rpcargs;
-    HANDLE thread;
-    DWORD threadId;
-
-    rpcargs.returnValue = 0;
-    rpcargs.lastError = GetLastError();
-    rpcargs.op = RPC_PEEKNAMEDPIPE;
-    rpcargs.args[0] = (ULONG_PTR)hPipe;
-    rpcargs.args[1] = (ULONG_PTR)lpvBuffer;
-    rpcargs.args[2] = (ULONG_PTR)cbBuffer;
-    rpcargs.args[3] = (ULONG_PTR)lpcbRead;
-    rpcargs.args[4] = (ULONG_PTR)lpcbAvail;
-    rpcargs.args[5] = (ULONG_PTR)lpcbMessage;
+    DWORD res = WaitForSingleObject(handle, 0);
+    ok_(__FILE__,line)(res == WAIT_TIMEOUT, "WaitForSingleObject returned %u (%u)\n", res, GetLastError());
+}
 
-    thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId);
-    ok(thread != NULL, "CreateThread failed. %d\n", GetLastError());
-    ok(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0,"WaitForSingleObject failed with %d.\n", GetLastError());
-    CloseHandle(thread);
+#define test_signaled(h) _test_signaled(__LINE__,h)
+static void _test_signaled(unsigned line, HANDLE handle)
+{
+    DWORD res = WaitForSingleObject(handle, 0);
+    ok_(__FILE__,line)(res == WAIT_OBJECT_0, "WaitForSingleObject returned %u\n", res);
+}
 
-    SetLastError(rpcargs.lastError);
-    return (BOOL)rpcargs.returnValue;
+#define test_pipe_info(a,b,c,d,e) _test_pipe_info(__LINE__,a,b,c,d,e)
+static void _test_pipe_info(unsigned line, HANDLE pipe, DWORD ex_flags, DWORD ex_out_buf_size, DWORD ex_in_buf_size, DWORD ex_max_instances)
+{
+    DWORD flags = 0xdeadbeef, out_buf_size = 0xdeadbeef, in_buf_size = 0xdeadbeef, max_instances = 0xdeadbeef;
+    BOOL res;
+
+    res = GetNamedPipeInfo(pipe, &flags, &out_buf_size, &in_buf_size, &max_instances);
+    ok_(__FILE__,line)(res, "GetNamedPipeInfo failed: %x\n", res);
+    ok_(__FILE__,line)(flags == ex_flags, "flags = %x, expected %x\n", flags, ex_flags);
+    ok_(__FILE__,line)(out_buf_size == ex_out_buf_size, "out_buf_size = %x, expected %u\n", out_buf_size, ex_out_buf_size);
+    ok_(__FILE__,line)(in_buf_size == ex_in_buf_size, "in_buf_size = %x, expected %u\n", in_buf_size, ex_in_buf_size);
+    ok_(__FILE__,line)(max_instances == ex_max_instances, "max_instances = %x, expected %u\n", max_instances, ex_max_instances);
 }
 
 static void test_CreateNamedPipe(int pipemode)
@@ -166,8 +150,8 @@ static void test_CreateNamedPipe(int pipemode)
     char ibuf[32], *pbuf;
     DWORD written;
     DWORD readden;
-    DWORD leftmsg;
     DWORD avail;
+    DWORD left;
     DWORD lpmode;
     BOOL ret;
 
@@ -224,6 +208,7 @@ static void test_CreateNamedPipe(int pipemode)
         /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
         /* lpSecurityAttrib */ NULL);
     ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
+    test_signaled(hnp);
 
     ret = WaitNamedPipeA(PIPENAME, 2000);
     ok(ret, "WaitNamedPipe failed (%d)\n", GetLastError());
@@ -231,7 +216,7 @@ static void test_CreateNamedPipe(int pipemode)
     hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
     ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError());
 
-    ok(!WaitNamedPipeA(PIPENAME, 1000), "WaitNamedPipe succeeded\n");
+    ok(!WaitNamedPipeA(PIPENAME, 100), "WaitNamedPipe succeeded\n");
 
     ok(GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError());
 
@@ -258,8 +243,12 @@ static void test_CreateNamedPipe(int pipemode)
         memset(ibuf, 0, sizeof(ibuf));
         ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
         ok(written == sizeof(obuf), "write file len 1\n");
-        ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL), "Peek\n");
-        ok(readden == sizeof(obuf), "peek 1 got %d bytes\n", readden);
+        ok(PeekNamedPipe(hFile, NULL, 0, NULL, &avail, &left), "Peek\n");
+        ok(avail == sizeof(obuf), "peek 1 got %d bytes\n", avail);
+        if (pipemode == PIPE_TYPE_BYTE)
+            ok(left == 0, "peek 1 got %d bytes left\n", left);
+        else
+            ok(left == sizeof(obuf), "peek 1 got %d bytes left\n", left);
         ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
         ok(readden == sizeof(obuf), "read 1 got %d bytes\n", readden);
         ok(memcmp(obuf, ibuf, written) == 0, "content 1 check\n");
@@ -267,10 +256,18 @@ static void test_CreateNamedPipe(int pipemode)
         memset(ibuf, 0, sizeof(ibuf));
         ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), "WriteFile\n");
         ok(written == sizeof(obuf2), "write file len 2\n");
-        ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL), "Peek\n");
-        ok(readden == sizeof(obuf2), "peek 2 got %d bytes\n", readden);
-        ok(PeekNamedPipe(hnp, (LPVOID)1, 0, NULL, &readden, NULL), "Peek\n");
-        ok(readden == sizeof(obuf2), "peek 2 got %d bytes\n", readden);
+        ok(PeekNamedPipe(hnp, NULL, 0, NULL, &avail, &left), "Peek\n");
+        ok(avail == sizeof(obuf2), "peek 2 got %d bytes\n", avail);
+        if (pipemode == PIPE_TYPE_BYTE)
+            ok(left == 0, "peek 2 got %d bytes left\n", left);
+        else
+            ok(left == sizeof(obuf2), "peek 2 got %d bytes left\n", left);
+        ok(PeekNamedPipe(hnp, (LPVOID)1, 0, NULL, &avail, &left), "Peek\n");
+        ok(avail == sizeof(obuf2), "peek 2 got %d bytes\n", avail);
+        if (pipemode == PIPE_TYPE_BYTE)
+            ok(left == 0, "peek 2 got %d bytes left\n", left);
+        else
+            ok(left == sizeof(obuf2), "peek 2 got %d bytes left\n", left);
         ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
         ok(readden == sizeof(obuf2), "read 2 got %d bytes\n", readden);
         ok(memcmp(obuf2, ibuf, written) == 0, "content 2 check\n");
@@ -279,32 +276,33 @@ static void test_CreateNamedPipe(int pipemode)
         memset(ibuf, 0, sizeof(ibuf));
         ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), "WriteFile\n");
         ok(written == sizeof(obuf2), "write file len\n");
-        ok(ReadFile(hFile, ibuf, 4, &readden, NULL), "ReadFile\n");
-        ok(readden == 4, "read got %d bytes\n", readden);
-        readden = leftmsg = -1;
-        ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe\n");
-        ok(readden == sizeof(obuf2) - 4, "peek got %d bytes total\n", readden);
+        ok(PeekNamedPipe(hFile, ibuf, 4, &readden, &avail, &left), "Peek\n");
+        ok(readden == 4, "peek got %d bytes\n", readden);
+        ok(avail == sizeof(obuf2), "peek got %d bytes available\n", avail);
         if (pipemode == PIPE_TYPE_BYTE)
-            ok(leftmsg == 0, "peek got %d bytes left in message\n", leftmsg);
+            ok(left == -4, "peek got %d bytes left\n", left);
         else
-            ok(leftmsg == sizeof(obuf2) - 4, "peek got %d bytes left in message\n", leftmsg);
+            ok(left == sizeof(obuf2)-4, "peek got %d bytes left\n", left);
+        ok(ReadFile(hFile, ibuf, 4, &readden, NULL), "ReadFile\n");
+        ok(readden == 4, "read got %d bytes\n", readden);
         ok(ReadFile(hFile, ibuf + 4, sizeof(ibuf) - 4, &readden, NULL), "ReadFile\n");
         ok(readden == sizeof(obuf2) - 4, "read got %d bytes\n", readden);
         ok(memcmp(obuf2, ibuf, written) == 0, "content check\n");
-        readden = leftmsg = -1;
-        ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe\n");
-        ok(readden == 0, "peek got %d bytes total\n", readden);
-        ok(leftmsg == 0, "peek got %d bytes left in message\n", leftmsg);
 
         memset(ibuf, 0, sizeof(ibuf));
         ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
         ok(written == sizeof(obuf), "write file len\n");
+        ok(PeekNamedPipe(hnp, ibuf, 4, &readden, &avail, &left), "Peek\n");
+        ok(readden == 4, "peek got %d bytes\n", readden);
+        ok(avail == sizeof(obuf), "peek got %d bytes available\n", avail);
         if (pipemode == PIPE_TYPE_BYTE)
         {
+            ok(left == -4, "peek got %d bytes left\n", left);
             ok(ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile\n");
         }
         else
         {
+            ok(left == sizeof(obuf)-4, "peek got %d bytes left\n", left);
             SetLastError(0xdeadbeef);
             ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile\n");
             ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n");
@@ -339,159 +337,30 @@ static void test_CreateNamedPipe(int pipemode)
         ok(readden == sizeof(obuf2) - 8, "read got %d bytes\n", readden);
         ok(memcmp(obuf2, ibuf, written) == 0, "content check\n");
 
-        /* Tests for sending empty messages */
-        memset(ibuf, 0, sizeof(ibuf));
-        ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
-        ok(written == 0, "write file len\n");
-        if (pipemode != PIPE_TYPE_BYTE)
-        {
-            ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
-            ok(readden == 0, "read got %d bytes\n", readden);
-        }
-
-        memset(ibuf, 0, sizeof(ibuf));
-        ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n");
-        ok(written == 0, "write file len\n");
-        if (pipemode != PIPE_TYPE_BYTE)
-        {
-            ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
-            ok(readden == 0, "read got %d bytes\n", readden);
-        }
-
-        /* similar to above, but with an additional call to PeekNamedPipe inbetween */
-        memset(ibuf, 0, sizeof(ibuf));
-        ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
-        ok(written == 0, "write file len\n");
-        ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL), "Peek\n");
-        ok(readden == 0, "peek got %d bytes\n", readden);
-        if (pipemode != PIPE_TYPE_BYTE)
-        {
-            struct rpcThreadArgs rpcargs;
-            HANDLE thread;
-            DWORD threadId;
-
-            rpcargs.returnValue = 0;
-            rpcargs.lastError = GetLastError();
-            rpcargs.op = RPC_READFILE;
-            rpcargs.args[0] = (ULONG_PTR)hFile;
-            rpcargs.args[1] = (ULONG_PTR)ibuf;
-            rpcargs.args[2] = (ULONG_PTR)sizeof(ibuf);
-            rpcargs.args[3] = (ULONG_PTR)&readden;
-            rpcargs.args[4] = (ULONG_PTR)NULL;
-
-            thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId);
-            ok(thread != NULL, "CreateThread failed. %d\n", GetLastError());
-            ret = WaitForSingleObject(thread, 200);
-            todo_wine
-            ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0);
-            if (ret == WAIT_TIMEOUT)
-            {
-                ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
-                ok(written == 0, "write file len\n");
-                ret = WaitForSingleObject(thread, 200);
-                ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0);
-            }
-            CloseHandle(thread);
-            ok((BOOL)rpcargs.returnValue, "ReadFile\n");
-            ok(readden == 0, "read got %d bytes\n", readden);
-        }
-
-        memset(ibuf, 0, sizeof(ibuf));
-        ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n");
-        ok(written == 0, "write file len\n");
-        ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL), "Peek\n");
-        ok(readden == 0, "peek got %d bytes\n", readden);
-        if (pipemode != PIPE_TYPE_BYTE)
-        {
-            struct rpcThreadArgs rpcargs;
-            HANDLE thread;
-            DWORD threadId;
-
-            rpcargs.returnValue = 0;
-            rpcargs.lastError = GetLastError();
-            rpcargs.op = RPC_READFILE;
-            rpcargs.args[0] = (ULONG_PTR)hnp;
-            rpcargs.args[1] = (ULONG_PTR)ibuf;
-            rpcargs.args[2] = (ULONG_PTR)sizeof(ibuf);
-            rpcargs.args[3] = (ULONG_PTR)&readden;
-            rpcargs.args[4] = (ULONG_PTR)NULL;
-
-            thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId);
-            ok(thread != NULL, "CreateThread failed. %d\n", GetLastError());
-            ret = WaitForSingleObject(thread, 200);
-            todo_wine
-            ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0);
-            if (ret == WAIT_TIMEOUT)
-            {
-                ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n");
-                ok(written == 0, "write file len\n");
-                ret = WaitForSingleObject(thread, 200);
-                ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0);
-            }
-            CloseHandle(thread);
-            ok((BOOL)rpcargs.returnValue, "ReadFile\n");
-            ok(readden == 0, "read got %d bytes\n", readden);
-        }
-
-        /* similar to above, but now with PeekNamedPipe and multiple messages */
-        memset(ibuf, 0, sizeof(ibuf));
-        ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
-        ok(written == 0, "write file len\n");
-        ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
-        ok(written == sizeof(obuf), "write file len\n");
-        ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "Peek\n");
-        ok(readden == sizeof(obuf), "peek got %d bytes\n", readden);
-        ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
-        ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "Peek\n");
-        ok(readden == sizeof(obuf), "peek got %d bytes\n", readden);
-        if (pipemode != PIPE_TYPE_BYTE)
-            todo_wine
-            ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
-        else
-            ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
-        ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
-        ok(readden == sizeof(obuf), "read got %d bytes\n", readden);
-        ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check\n");
-
-        memset(ibuf, 0, sizeof(ibuf));
-        ok(WriteFile(hFile, obuf2, 0, &written, NULL), "WriteFile\n");
-        ok(written == 0, "write file len\n");
-        ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), "WriteFile\n");
-        ok(written == sizeof(obuf2), "write file len\n");
-        ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "Peek\n");
-        ok(readden == sizeof(obuf2), "peek got %d bytes\n", readden);
-        ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
-        ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "Peek\n");
-        ok(readden == sizeof(obuf2), "peek got %d bytes\n", readden);
-        if (pipemode != PIPE_TYPE_BYTE)
-            todo_wine
-            ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
-        else
-            ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
-        ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
-        if (pipemode != PIPE_TYPE_BYTE)
-        {
-            todo_wine
-            ok(readden == 0, "read got %d bytes\n", readden);
-            if (readden == 0)
-                ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
-        }
-        ok(readden == sizeof(obuf2), "read got %d bytes\n", readden);
-        ok(memcmp(obuf2, ibuf, sizeof(obuf2)) == 0, "content check\n");
-
         /* Test reading of multiple writes */
         memset(ibuf, 0, sizeof(ibuf));
         ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile3a\n");
         ok(written == sizeof(obuf), "write file len 3a\n");
         ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), " WriteFile3b\n");
         ok(written == sizeof(obuf2), "write file len 3b\n");
-        ok(PeekNamedPipe(hFile, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek3\n");
+        ok(PeekNamedPipe(hFile, ibuf, 4, &readden, &avail, &left), "Peek3\n");
+        ok(readden == 4, "peek3 got %d bytes\n", readden);
+        if (pipemode == PIPE_TYPE_BYTE)
+            ok(left == -4, "peek3 got %d bytes left\n", left);
+        else
+            ok(left == sizeof(obuf)-4, "peek3 got %d bytes left\n", left);
+        ok(avail == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes available\n", avail);
+        ok(PeekNamedPipe(hFile, ibuf, sizeof(ibuf), &readden, &avail, &left), "Peek3\n");
         if (pipemode == PIPE_TYPE_BYTE) {
-            ok(readden == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes\n", readden);
+            /* currently the Wine behavior depends on the kernel version */
+            /* ok(readden == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes\n", readden); */
+            if (readden != sizeof(obuf) + sizeof(obuf2)) todo_wine ok(0, "peek3 got %d bytes\n", readden);
+            ok(left == (DWORD) -(sizeof(obuf) + sizeof(obuf2)), "peek3 got %d bytes left\n", left);
         }
         else
         {
             ok(readden == sizeof(obuf), "peek3 got %d bytes\n", readden);
+            ok(left == 0, "peek3 got %d bytes left\n", left);
         }
         ok(avail == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes available\n", avail);
         pbuf = ibuf;
@@ -513,13 +382,24 @@ static void test_CreateNamedPipe(int pipemode)
         ok(written == sizeof(obuf), "write file len 4a\n");
         ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), " WriteFile4b\n");
         ok(written == sizeof(obuf2), "write file len 4b\n");
-        ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek4\n");
+        ok(PeekNamedPipe(hnp, ibuf, 4, &readden, &avail, &left), "Peek3\n");
+        ok(readden == 4, "peek3 got %d bytes\n", readden);
+        if (pipemode == PIPE_TYPE_BYTE)
+            ok(left == -4, "peek3 got %d bytes left\n", left);
+        else
+            ok(left == sizeof(obuf)-4, "peek3 got %d bytes left\n", left);
+        ok(avail == sizeof(obuf) + sizeof(obuf2), "peek3 got %d bytes available\n", avail);
+        ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, &left), "Peek4\n");
         if (pipemode == PIPE_TYPE_BYTE) {
-            ok(readden == sizeof(obuf) + sizeof(obuf2), "peek4 got %d bytes\n", readden);
+            /* currently the Wine behavior depends on the kernel version */
+            /* ok(readden == sizeof(obuf) + sizeof(obuf2), "peek4 got %d bytes\n", readden); */
+            if (readden != sizeof(obuf) + sizeof(obuf2)) todo_wine ok(0, "peek4 got %d bytes\n", readden);
+            ok(left == (DWORD) -(sizeof(obuf) + sizeof(obuf2)), "peek4 got %d bytes left\n", left);
         }
         else
         {
             ok(readden == sizeof(obuf), "peek4 got %d bytes\n", readden);
+            ok(left == 0, "peek4 got %d bytes left\n", left);
         }
         ok(avail == sizeof(obuf) + sizeof(obuf2), "peek4 got %d bytes available\n", avail);
         pbuf = ibuf;
@@ -557,9 +437,10 @@ static void test_CreateNamedPipe(int pipemode)
             ok(written == sizeof(obuf), "write file len 3a\n");
             ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), " WriteFile5b\n");
             ok(written == sizeof(obuf2), "write file len 3b\n");
-            ok(PeekNamedPipe(hFile, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek5\n");
+            ok(PeekNamedPipe(hFile, ibuf, sizeof(ibuf), &readden, &avail, &left), "Peek5\n");
             ok(readden == sizeof(obuf), "peek5 got %d bytes\n", readden);
             ok(avail == sizeof(obuf) + sizeof(obuf2), "peek5 got %d bytes available\n", avail);
+            ok(left == 0, "peek5 got %d bytes left\n", left);
             pbuf = ibuf;
             ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 5a check\n");
             ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
@@ -587,6 +468,7 @@ static void test_CreateNamedPipe(int pipemode)
             ok(written == sizeof(obuf2), "write file len 6b\n");
             ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek6\n");
             ok(readden == sizeof(obuf), "peek6 got %d bytes\n", readden);
+
             ok(avail == sizeof(obuf) + sizeof(obuf2), "peek6b got %d bytes available\n", avail);
             pbuf = ibuf;
             ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 6a check\n");
@@ -597,133 +479,6 @@ static void test_CreateNamedPipe(int pipemode)
             if (readden <= sizeof(obuf))
                 ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
 
-            /* Tests for sending empty messages */
-            memset(ibuf, 0, sizeof(ibuf));
-            ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
-            ok(written == 0, "write file len\n");
-            ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
-            ok(readden == 0, "read got %d bytes\n", readden);
-
-            memset(ibuf, 0, sizeof(ibuf));
-            ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n");
-            ok(written == 0, "write file len\n");
-            ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
-            ok(readden == 0, "read got %d bytes\n", readden);
-
-            /* similar to above, but with an additional call to PeekNamedPipe inbetween */
-            memset(ibuf, 0, sizeof(ibuf));
-            ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
-            ok(written == 0, "write file len\n");
-            ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL), "Peek\n");
-            ok(readden == 0, "peek got %d bytes\n", readden);
-            {
-                struct rpcThreadArgs rpcargs;
-                HANDLE thread;
-                DWORD threadId;
-
-                rpcargs.returnValue = 0;
-                rpcargs.lastError = GetLastError();
-                rpcargs.op = RPC_READFILE;
-                rpcargs.args[0] = (ULONG_PTR)hFile;
-                rpcargs.args[1] = (ULONG_PTR)ibuf;
-                rpcargs.args[2] = (ULONG_PTR)sizeof(ibuf);
-                rpcargs.args[3] = (ULONG_PTR)&readden;
-                rpcargs.args[4] = (ULONG_PTR)NULL;
-
-                thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId);
-                ok(thread != NULL, "CreateThread failed. %d\n", GetLastError());
-                ret = WaitForSingleObject(thread, 200);
-                todo_wine
-                ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0);
-                if (ret == WAIT_TIMEOUT)
-                {
-                    ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
-                    ok(written == 0, "write file len\n");
-                    ret = WaitForSingleObject(thread, 200);
-                    ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0);
-                }
-                CloseHandle(thread);
-                ok((BOOL)rpcargs.returnValue, "ReadFile\n");
-                ok(readden == 0, "read got %d bytes\n", readden);
-            }
-
-            memset(ibuf, 0, sizeof(ibuf));
-            ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n");
-            ok(written == 0, "write file len\n");
-            ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL), "Peek\n");
-            ok(readden == 0, "peek got %d bytes\n", readden);
-            {
-                struct rpcThreadArgs rpcargs;
-                HANDLE thread;
-                DWORD threadId;
-
-                rpcargs.returnValue = 0;
-                rpcargs.lastError = GetLastError();
-                rpcargs.op = RPC_READFILE;
-                rpcargs.args[0] = (ULONG_PTR)hnp;
-                rpcargs.args[1] = (ULONG_PTR)ibuf;
-                rpcargs.args[2] = (ULONG_PTR)sizeof(ibuf);
-                rpcargs.args[3] = (ULONG_PTR)&readden;
-                rpcargs.args[4] = (ULONG_PTR)NULL;
-
-                thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId);
-                ok(thread != NULL, "CreateThread failed. %d\n", GetLastError());
-                ret = WaitForSingleObject(thread, 200);
-                todo_wine
-                ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0);
-                if (ret == WAIT_TIMEOUT)
-                {
-                    ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n");
-                    ok(written == 0, "write file len\n");
-                    ret = WaitForSingleObject(thread, 200);
-                    ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0);
-                }
-                CloseHandle(thread);
-                ok((BOOL)rpcargs.returnValue, "ReadFile\n");
-                ok(readden == 0, "read got %d bytes\n", readden);
-            }
-
-            /* similar to above, but now with PeekNamedPipe and multiple messages */
-            memset(ibuf, 0, sizeof(ibuf));
-            ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
-            ok(written == 0, "write file len\n");
-            ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
-            ok(written == sizeof(obuf), "write file len\n");
-            ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "Peek\n");
-            ok(readden == sizeof(obuf), "peek got %d bytes\n", readden);
-            ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
-            ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "Peek\n");
-            ok(readden == sizeof(obuf), "peek got %d bytes\n", readden);
-            todo_wine
-            ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
-            ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
-            todo_wine
-            ok(readden == 0, "read got %d bytes\n", readden);
-            if (readden == 0)
-                ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
-            ok(readden == sizeof(obuf), "read got %d bytes\n", readden);
-            ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check\n");
-
-            memset(ibuf, 0, sizeof(ibuf));
-            ok(WriteFile(hFile, obuf2, 0, &written, NULL), "WriteFile\n");
-            ok(written == 0, "write file len\n");
-            ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), "WriteFile\n");
-            ok(written == sizeof(obuf2), "write file len\n");
-            ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "Peek\n");
-            ok(readden == sizeof(obuf2), "peek got %d bytes\n", readden);
-            ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
-            ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "Peek\n");
-            ok(readden == sizeof(obuf2), "peek got %d bytes\n", readden);
-            todo_wine
-            ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg);
-            ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
-            todo_wine
-            ok(readden == 0, "read got %d bytes\n", readden);
-            if (readden == 0)
-                ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n");
-            ok(readden == sizeof(obuf2), "read got %d bytes\n", readden);
-            ok(memcmp(obuf2, ibuf, sizeof(obuf2)) == 0, "content check\n");
-
             /* Test how ReadFile behaves when the buffer is not big enough for the whole message */
             memset(ibuf, 0, sizeof(ibuf));
             ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), "WriteFile 7\n");
@@ -756,14 +511,6 @@ static void test_CreateNamedPipe(int pipemode)
             ok(written == sizeof(obuf), "write file len 9\n");
             ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), "WriteFile 9\n");
             ok(written == sizeof(obuf2), "write file len 9\n");
-            readden = leftmsg = -1;
-            ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 9\n");
-            ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 9\n", readden);
-            ok(leftmsg == sizeof(obuf), "peek got %d bytes left in message 9\n", leftmsg);
-            readden = leftmsg = -1;
-            ok(RpcPeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 9\n");
-            ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 9\n", readden);
-            ok(leftmsg == sizeof(obuf), "peek got %d bytes left in message 9\n", leftmsg);
             SetLastError(0xdeadbeef);
             ok(!ReadFile(hFile, ibuf, 4, &readden, NULL), "ReadFile 9\n");
             ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n");
@@ -773,14 +520,6 @@ static void test_CreateNamedPipe(int pipemode)
             ok(!ret, "RpcReadFile 9\n");
             ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n");
             ok(readden == 4, "read got %d bytes 9\n", readden);
-            readden = leftmsg = -1;
-            ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 9\n");
-            ok(readden == sizeof(obuf) - 8 + sizeof(obuf2), "peek got %d bytes total 9\n", readden);
-            ok(leftmsg == sizeof(obuf) - 8, "peek got %d bytes left in message 9\n", leftmsg);
-            readden = leftmsg = -1;
-            ok(RpcPeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 9\n");
-            ok(readden == sizeof(obuf) - 8 + sizeof(obuf2), "peek got %d bytes total 9\n", readden);
-            ok(leftmsg == sizeof(obuf) - 8, "peek got %d bytes left in message 9\n", leftmsg);
             ret = RpcReadFile(hFile, ibuf + 8, sizeof(ibuf), &readden, NULL);
             ok(ret, "RpcReadFile 9\n");
             ok(readden == sizeof(obuf) - 8, "read got %d bytes 9\n", readden);
@@ -788,14 +527,6 @@ static void test_CreateNamedPipe(int pipemode)
             if (readden <= sizeof(obuf) - 8) /* blocks forever if second part was already received */
             {
                 memset(ibuf, 0, sizeof(ibuf));
-                readden = leftmsg = -1;
-                ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 9\n");
-                ok(readden == sizeof(obuf2), "peek got %d bytes total 9\n", readden);
-                ok(leftmsg == sizeof(obuf2), "peek got %d bytes left in message 9\n", leftmsg);
-                readden = leftmsg = -1;
-                ok(RpcPeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 9\n");
-                ok(readden == sizeof(obuf2), "peek got %d bytes total 9\n", readden);
-                ok(leftmsg == sizeof(obuf2), "peek got %d bytes left in message 9\n", leftmsg);
                 SetLastError(0xdeadbeef);
                 ret = RpcReadFile(hFile, ibuf, 4, &readden, NULL);
                 ok(!ret, "RpcReadFile 9\n");
@@ -805,27 +536,11 @@ static void test_CreateNamedPipe(int pipemode)
                 ok(!ReadFile(hFile, ibuf + 4, 4, &readden, NULL), "ReadFile 9\n");
                 ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n");
                 ok(readden == 4, "read got %d bytes 9\n", readden);
-                readden = leftmsg = -1;
-                ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 9\n");
-                ok(readden == sizeof(obuf2) - 8, "peek got %d bytes total 9\n", readden);
-                ok(leftmsg == sizeof(obuf2) - 8, "peek got %d bytes left in message 9\n", leftmsg);
-                readden = leftmsg = -1;
-                ok(RpcPeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 9\n");
-                ok(readden == sizeof(obuf2) - 8, "peek got %d bytes total 9\n", readden);
-                ok(leftmsg == sizeof(obuf2) - 8, "peek got %d bytes left in message 9\n", leftmsg);
                 ret = RpcReadFile(hFile, ibuf + 8, sizeof(ibuf), &readden, NULL);
                 ok(ret, "RpcReadFile 9\n");
                 ok(readden == sizeof(obuf2) - 8, "read got %d bytes 9\n", readden);
                 ok(memcmp(obuf2, ibuf, sizeof(obuf2)) == 0, "content check 9\n");
             }
-            readden = leftmsg = -1;
-            ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 9\n");
-            ok(readden == 0, "peek got %d bytes total 9\n", readden);
-            ok(leftmsg == 0, "peek got %d bytes left in message 9\n", leftmsg);
-            readden = leftmsg = -1;
-            ok(RpcPeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 9\n");
-            ok(readden == 0, "peek got %d bytes total 9\n", readden);
-            ok(leftmsg == 0, "peek got %d bytes left in message 9\n", leftmsg);
 
             /* Now the reverse direction */
             memset(ibuf, 0, sizeof(ibuf));
@@ -833,14 +548,6 @@ static void test_CreateNamedPipe(int pipemode)
             ok(written == sizeof(obuf2), "write file len 10\n");
             ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile 10\n");
             ok(written == sizeof(obuf), "write file len 10\n");
-            readden = leftmsg = -1;
-            ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 10\n");
-            ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 10\n", readden);
-            ok(leftmsg == sizeof(obuf2), "peek got %d bytes left in message 10\n", leftmsg);
-            readden = leftmsg = -1;
-            ok(RpcPeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 10\n");
-            ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 10\n", readden);
-            ok(leftmsg == sizeof(obuf2), "peek got %d bytes left in message 10\n", leftmsg);
             SetLastError(0xdeadbeef);
             ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile 10\n");
             ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n");
@@ -850,14 +557,6 @@ static void test_CreateNamedPipe(int pipemode)
             ok(!ret, "RpcReadFile 10\n");
             ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n");
             ok(readden == 4, "read got %d bytes 10\n", readden);
-            readden = leftmsg = -1;
-            ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 10\n");
-            ok(readden == sizeof(obuf2) - 8 + sizeof(obuf), "peek got %d bytes total 10\n", readden);
-            ok(leftmsg == sizeof(obuf2) - 8, "peek got %d bytes left in message 10\n", leftmsg);
-            readden = leftmsg = -1;
-            ok(RpcPeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 10\n");
-            ok(readden == sizeof(obuf2) - 8 + sizeof(obuf), "peek got %d bytes total 10\n", readden);
-            ok(leftmsg == sizeof(obuf2) - 8, "peek got %d bytes left in message 10\n", leftmsg);
             ret = RpcReadFile(hnp, ibuf + 8, sizeof(ibuf), &readden, NULL);
             ok(ret, "RpcReadFile 10\n");
             ok(readden == sizeof(obuf2) - 8, "read got %d bytes 10\n", readden);
@@ -865,14 +564,6 @@ static void test_CreateNamedPipe(int pipemode)
             if (readden <= sizeof(obuf2) - 8) /* blocks forever if second part was already received */
             {
                 memset(ibuf, 0, sizeof(ibuf));
-                readden = leftmsg = -1;
-                ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 10\n");
-                ok(readden == sizeof(obuf), "peek got %d bytes total 10\n", readden);
-                ok(leftmsg == sizeof(obuf), "peek got %d bytes left in message 10\n", leftmsg);
-                readden = leftmsg = -1;
-                ok(RpcPeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 10\n");
-                ok(readden == sizeof(obuf), "peek got %d bytes total 10\n", readden);
-                ok(leftmsg == sizeof(obuf), "peek got %d bytes left in message 10\n", leftmsg);
                 SetLastError(0xdeadbeef);
                 ret = RpcReadFile(hnp, ibuf, 4, &readden, NULL);
                 ok(!ret, "RpcReadFile 10\n");
@@ -882,141 +573,14 @@ static void test_CreateNamedPipe(int pipemode)
                 ok(!ReadFile(hnp, ibuf + 4, 4, &readden, NULL), "ReadFile 10\n");
                 ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n");
                 ok(readden == 4, "read got %d bytes 10\n", readden);
-                readden = leftmsg = -1;
-                ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 10\n");
-                ok(readden == sizeof(obuf) - 8, "peek got %d bytes total 10\n", readden);
-                ok(leftmsg == sizeof(obuf) - 8, "peek got %d bytes left in message 10\n", leftmsg);
-                readden = leftmsg = -1;
-                ok(RpcPeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 10\n");
-                ok(readden == sizeof(obuf) - 8, "peek got %d bytes total 10\n", readden);
-                ok(leftmsg == sizeof(obuf) - 8, "peek got %d bytes left in message 10\n", leftmsg);
                 ret = RpcReadFile(hnp, ibuf + 8, sizeof(ibuf), &readden, NULL);
                 ok(ret, "RpcReadFile 10\n");
                 ok(readden == sizeof(obuf) - 8, "read got %d bytes 10\n", readden);
                 ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check 10\n");
             }
-            readden = leftmsg = -1;
-            ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 10\n");
-            ok(readden == 0, "peek got %d bytes total 10\n", readden);
-            ok(leftmsg == 0, "peek got %d bytes left in message 10\n", leftmsg);
-            readden = leftmsg = -1;
-            ok(RpcPeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 10\n");
-            ok(readden == 0, "peek got %d bytes total 10\n", readden);
-            ok(leftmsg == 0, "peek got %d bytes left in message 10\n", leftmsg);
 
         }
 
-        /* Test behaviour for very huge messages (which don't fit completely in the buffer) */
-        {
-            static char big_obuf[512 * 1024];
-            static char big_ibuf[512 * 1024];
-            struct rpcThreadArgs rpcargs;
-            HANDLE thread;
-            DWORD threadId;
-            memset(big_obuf, 0xAA, sizeof(big_obuf));
-
-            /* Ensure that both pipes are empty before we continue with the next test */
-            while (PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL) && readden > 0)
-                ok(ReadFile(hFile, big_ibuf, sizeof(big_ibuf), &readden, NULL) ||
-                   GetLastError() == ERROR_MORE_DATA, "ReadFile\n");
-
-            while (PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL) && readden > 0)
-                ok(ReadFile(hnp, big_ibuf, sizeof(big_ibuf), &readden, NULL) ||
-                   GetLastError() == ERROR_MORE_DATA, "ReadFile\n");
-
-            readden = leftmsg = -1;
-            ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe\n");
-            ok(readden == 0, "peek got %d bytes total\n", readden);
-            ok(leftmsg == 0, "peek got %d bytes left in message\n", leftmsg);
-
-            /* transmit big message, receive with buffer of equal size */
-            memset(big_ibuf, 0, sizeof(big_ibuf));
-            rpcargs.returnValue = 0;
-            rpcargs.lastError = GetLastError();
-            rpcargs.op = RPC_WRITEFILE;
-            rpcargs.args[0] = (ULONG_PTR)hnp;
-            rpcargs.args[1] = (ULONG_PTR)big_obuf;
-            rpcargs.args[2] = (ULONG_PTR)sizeof(big_obuf);
-            rpcargs.args[3] = (ULONG_PTR)&written;
-            rpcargs.args[4] = (ULONG_PTR)NULL;
-
-            thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId);
-            ok(thread != NULL, "CreateThread failed. %d\n", GetLastError());
-            ret = WaitForSingleObject(thread, 200);
-            ok(ret == WAIT_TIMEOUT, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_TIMEOUT);
-            ok(ReadFile(hFile, big_ibuf, sizeof(big_ibuf), &readden, NULL), "ReadFile\n");
-            todo_wine
-            ok(readden == sizeof(big_obuf), "read got %d bytes\n", readden);
-            todo_wine
-            ok(memcmp(big_ibuf, big_obuf, sizeof(big_obuf)) == 0, "content check\n");
-            do
-            {
-                ret = WaitForSingleObject(thread, 1);
-                while (PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL) && readden > 0)
-                    ok(ReadFile(hFile, big_ibuf, sizeof(big_ibuf), &readden, NULL) ||
-                       GetLastError() == ERROR_MORE_DATA, "ReadFile\n");
-            }
-            while (ret == WAIT_TIMEOUT);
-            ok(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed with %d.\n", GetLastError());
-            ok((BOOL)rpcargs.returnValue, "WriteFile\n");
-            ok(written == sizeof(big_obuf), "write file len\n");
-            CloseHandle(thread);
-
-            readden = leftmsg = -1;
-            ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe\n");
-            ok(readden == 0, "peek got %d bytes total\n", readden);
-            ok(leftmsg == 0, "peek got %d bytes left in message\n", leftmsg);
-
-            /* same as above, but receive as multiple parts */
-            memset(big_ibuf, 0, sizeof(big_ibuf));
-            rpcargs.returnValue = 0;
-            rpcargs.lastError = GetLastError();
-
-            thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId);
-            ok(thread != NULL, "CreateThread failed. %d\n", GetLastError());
-            ret = WaitForSingleObject(thread, 200);
-            ok(ret == WAIT_TIMEOUT, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_TIMEOUT);
-            if (pipemode == PIPE_TYPE_BYTE)
-            {
-                ok(ReadFile(hFile, big_ibuf, 32, &readden, NULL), "ReadFile\n");
-                ok(readden == 32, "read got %d bytes\n", readden);
-                ok(ReadFile(hFile, big_ibuf + 32, 32, &readden, NULL), "ReadFile\n");
-            }
-            else
-            {
-                SetLastError(0xdeadbeef);
-                ok(!ReadFile(hFile, big_ibuf, 32, &readden, NULL), "ReadFile\n");
-                ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n");
-                ok(readden == 32, "read got %d bytes\n", readden);
-                SetLastError(0xdeadbeef);
-                ok(!ReadFile(hFile, big_ibuf + 32, 32, &readden, NULL), "ReadFile\n");
-                ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n");
-            }
-            ok(readden == 32, "read got %d bytes\n", readden);
-            ok(ReadFile(hFile, big_ibuf + 64, sizeof(big_ibuf) - 64, &readden, NULL), "ReadFile\n");
-            todo_wine
-            ok(readden == sizeof(big_obuf) - 64, "read got %d bytes\n", readden);
-            todo_wine
-            ok(memcmp(big_ibuf, big_obuf, sizeof(big_obuf)) == 0, "content check\n");
-            do
-            {
-                ret = WaitForSingleObject(thread, 1);
-                while (PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL) && readden > 0)
-                    ok(ReadFile(hFile, big_ibuf, sizeof(big_ibuf), &readden, NULL) ||
-                       GetLastError() == ERROR_MORE_DATA, "ReadFile\n");
-            }
-            while (ret == WAIT_TIMEOUT);
-            ok(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed with %d.\n", GetLastError());
-            ok((BOOL)rpcargs.returnValue, "WriteFile\n");
-            ok(written == sizeof(big_obuf), "write file len\n");
-            CloseHandle(thread);
-
-            readden = leftmsg = -1;
-            ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe\n");
-            ok(readden == 0, "peek got %d bytes total\n", readden);
-            ok(leftmsg == 0, "peek got %d bytes left in message\n", leftmsg);
-        }
-
         /* Picky conformance tests */
 
         /* Verify that you can't connect to pipe again
@@ -1823,6 +1387,9 @@ static void test_CreatePipe(void)
     pipe_attr.bInheritHandle = TRUE; 
     pipe_attr.lpSecurityDescriptor = NULL;
     ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, 0) != 0, "CreatePipe failed\n");
+    test_pipe_info(piperead, FILE_PIPE_SERVER_END, 4096, 4096, 1);
+    test_pipe_info(pipewrite, 0, 4096, 4096, 1);
+
     ok(WriteFile(pipewrite,PIPENAME,sizeof(PIPENAME), &written, NULL), "Write to anonymous pipe failed\n");
     ok(written == sizeof(PIPENAME), "Write to anonymous pipe wrote %d bytes\n", written);
     ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL), "Read from non empty pipe failed\n");
@@ -1836,8 +1403,8 @@ static void test_CreatePipe(void)
     ok(written == sizeof(PIPENAME), "Write to anonymous pipe wrote %d bytes\n", written);
     /* and close the write end, read should still succeed*/
     ok(CloseHandle(pipewrite), "CloseHandle for the Write Pipe failed\n");
-    ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL), "Read from broken pipe withe with pending data failed\n");
-    ok(read == sizeof(PIPENAME), "Read from  anonymous pipe got %d bytes\n", read);
+    ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL), "Read from broken pipe with pending data failed\n");
+    ok(read == sizeof(PIPENAME), "Read from anonymous pipe got %d bytes\n", read);
     /* But now we need to get informed that the pipe is closed */
     ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL) == 0, "Broken pipe not detected\n");
     ok(CloseHandle(piperead), "CloseHandle for the read pipe failed\n");
@@ -1852,8 +1419,8 @@ static void test_CreatePipe(void)
     /* and close the write end, read should still succeed*/
     ok(CloseHandle(pipewrite), "CloseHandle for the Write Pipe failed\n");
     memset( buffer, 0, size );
-    ok(ReadFile(piperead, buffer, size, &read, NULL), "Read from broken pipe withe with pending data failed\n");
-    ok(read == size, "Read from  anonymous pipe got %d bytes\n", read);
+    ok(ReadFile(piperead, buffer, size, &read, NULL), "Read from broken pipe with pending data failed\n");
+    ok(read == size, "Read from anonymous pipe got %d bytes\n", read);
     for (i = 0; i < size; i++) ok( buffer[i] == (BYTE)i, "invalid data %x at %x\n", buffer[i], i );
     /* But now we need to get informed that the pipe is closed */
     ok(ReadFile(piperead,readbuf,sizeof(readbuf),&read, NULL) == 0, "Broken pipe not detected\n");
@@ -1862,6 +1429,12 @@ static void test_CreatePipe(void)
 
     ok(user_apc_ran == FALSE, "user apc ran, pipe using alertable io mode\n");
     SleepEx(0, TRUE); /* get rid of apc */
+
+    ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, 1) != 0, "CreatePipe failed\n");
+    test_pipe_info(piperead, FILE_PIPE_SERVER_END, 1, 1, 1);
+    test_pipe_info(pipewrite, 0, 1, 1, 1);
+    ok(CloseHandle(pipewrite), "CloseHandle for the Write Pipe failed\n");
+    ok(CloseHandle(piperead), "CloseHandle for the read pipe failed\n");
 }
 
 static void test_CloseHandle(void)
@@ -1919,7 +1492,7 @@ static void test_CloseHandle(void)
     SetLastError(0xdeadbeef);
     ret = WriteFile(hfile, testdata, sizeof(testdata), &numbytes, NULL);
     ok(!ret, "WriteFile unexpectedly succeeded\n");
-    ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %u\n", GetLastError());
+    todo_wine ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %u\n", GetLastError());
 
     CloseHandle(hfile);
 
@@ -1942,9 +1515,14 @@ static void test_CloseHandle(void)
     numbytes = 0xdeadbeef;
     memset(buffer, 0, sizeof(buffer));
     ret = ReadFile(hfile, buffer, sizeof(buffer), &numbytes, NULL);
-    todo_wine ok(ret, "ReadFile failed with %u\n", GetLastError());
+    ok(ret, "ReadFile failed with %u\n", GetLastError());
     ok(numbytes == 0, "expected 0, got %u\n", numbytes);
 
+    SetLastError(0xdeadbeef);
+    ret = ReadFile(hfile, buffer, 0, &numbytes, NULL);
+    ok(!ret, "ReadFile unexpectedly succeeded\n");
+    ok(GetLastError() == ERROR_BROKEN_PIPE, "expected ERROR_BROKEN_PIPE, got %u\n", GetLastError());
+
     ret = GetNamedPipeHandleStateA(hfile, &state, NULL, NULL, NULL, NULL, 0);
     ok(ret, "GetNamedPipeHandleState failed with %u\n", GetLastError());
     state = PIPE_READMODE_MESSAGE | PIPE_WAIT;
@@ -1959,7 +1537,7 @@ static void test_CloseHandle(void)
     SetLastError(0xdeadbeef);
     ret = WriteFile(hfile, testdata, sizeof(testdata), &numbytes, NULL);
     ok(!ret, "WriteFile unexpectedly succeeded\n");
-    ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %u\n", GetLastError());
+    todo_wine ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %u\n", GetLastError());
 
     CloseHandle(hfile);
 
@@ -1989,8 +1567,8 @@ static void test_CloseHandle(void)
     numbytes = 0xdeadbeef;
     memset(buffer, 0, sizeof(buffer));
     ret = ReadFile(hpipe, buffer, 0, &numbytes, NULL);
-    ok(ret || broken(GetLastError() == ERROR_MORE_DATA) /* >= Win 8 */,
-       "ReadFile failed with %u\n", GetLastError());
+    ok(ret || GetLastError() == ERROR_MORE_DATA /* >= Win 8 */,
+                 "ReadFile failed with %u\n", GetLastError());
     ok(numbytes == 0, "expected 0, got %u\n", numbytes);
 
     numbytes = 0xdeadbeef;
@@ -2036,9 +1614,14 @@ static void test_CloseHandle(void)
     numbytes = 0xdeadbeef;
     memset(buffer, 0, sizeof(buffer));
     ret = ReadFile(hpipe, buffer, sizeof(buffer), &numbytes, NULL);
-    todo_wine ok(ret, "ReadFile failed with %u\n", GetLastError());
+    ok(ret, "ReadFile failed with %u\n", GetLastError());
     ok(numbytes == 0, "expected 0, got %u\n", numbytes);
 
+    SetLastError(0xdeadbeef);
+    ret = ReadFile(hpipe, buffer, 0, &numbytes, NULL);
+    ok(!ret, "ReadFile unexpectedly succeeded\n");
+    ok(GetLastError() == ERROR_BROKEN_PIPE, "expected ERROR_BROKEN_PIPE, got %u\n", GetLastError());
+
     ret = GetNamedPipeHandleStateA(hpipe, &state, NULL, NULL, NULL, NULL, 0);
     ok(ret, "GetNamedPipeHandleState failed with %u\n", GetLastError());
     state = PIPE_READMODE_MESSAGE | PIPE_WAIT;
@@ -2540,6 +2123,20 @@ static DWORD CALLBACK overlapped_server(LPVOID arg)
     ok(ret == 1, "ret %d\n", ret);
 
     DisconnectNamedPipe(pipe);
+
+    ret = ConnectNamedPipe(pipe, &ol);
+    err = GetLastError();
+    ok(ret == 0, "ret %d\n", ret);
+    ok(err == ERROR_IO_PENDING, "gle %d\n", err);
+    CancelIo(pipe);
+    ret = WaitForSingleObjectEx(ol.hEvent, INFINITE, 1);
+    ok(ret == WAIT_OBJECT_0, "ret %x\n", ret);
+
+    ret = GetOverlappedResult(pipe, &ol, &num, 1);
+    err = GetLastError();
+    ok(ret == 0, "ret %d\n", ret);
+    ok(err == ERROR_OPERATION_ABORTED, "gle %d\n", err);
+
     CloseHandle(ol.hEvent);
     CloseHandle(pipe);
     return 1;
@@ -2629,121 +2226,6 @@ static void test_overlapped_error(void)
     CloseHandle(event);
 }
 
-static void test_nowait(int pipemode)
-{
-    HANDLE hnp;
-    HANDLE hFile;
-    static const char obuf[] = "Bit Bucket";
-    char ibuf[32];
-    DWORD written;
-    DWORD readden;
-    DWORD lpmode;
-
-    hnp = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX,
-                           pipemode | PIPE_NOWAIT,
-                           /* nMaxInstances */ 1,
-                           /* nOutBufSize */ 1024,
-                           /* nInBufSize */ 1024,
-                           /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
-                           /* lpSecurityAttrib */ NULL);
-    ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
-
-    hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
-    ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError());
-
-    /* don't try to do i/o if one side couldn't be opened, as it hangs */
-    if (hFile != INVALID_HANDLE_VALUE)
-    {
-        /* send message from client to server */
-        ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
-        ok(written == sizeof(obuf), "write file len\n");
-        ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL), "Peek\n");
-        ok(readden == sizeof(obuf), "got %d bytes\n", readden);
-
-        memset(ibuf, 0, sizeof(ibuf));
-        ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
-        ok(readden == sizeof(obuf), "got %d bytes\n", readden);
-        ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check\n");
-
-        readden = 0xdeadbeef;
-        SetLastError(0xdeadbeef);
-        ok(!ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n");
-        ok(readden == 0, "got %d bytes\n", readden);
-        ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
-
-        lpmode = (pipemode & PIPE_READMODE_MESSAGE) | PIPE_NOWAIT;
-        ok(SetNamedPipeHandleState(hFile, &lpmode, NULL, NULL), "Change mode\n");
-
-        /* send message from server to client */
-        ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n");
-        ok(written == sizeof(obuf), "write file len\n");
-        ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL), "Peek\n");
-        ok(readden == sizeof(obuf), "got %d bytes\n", readden);
-
-        memset(ibuf, 0, sizeof(ibuf));
-        ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
-        ok(readden == sizeof(obuf), "got %d bytes\n", readden);
-        ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check\n");
-
-        readden = 0xdeadbeef;
-        SetLastError(0xdeadbeef);
-        ok(!ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n");
-        ok(readden == 0, "got %d bytes\n", readden);
-        ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
-
-        /* now again the bad zero byte message test */
-        ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n");
-        ok(written == 0, "write file len\n");
-
-        if (pipemode != PIPE_TYPE_BYTE)
-        {
-            ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
-            ok(readden == 0, "got %d bytes\n", readden);
-        }
-        else
-        {
-            SetLastError(0xdeadbeef);
-            ok(!ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n");
-            ok(readden == 0, "got %d bytes\n", readden);
-            ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
-        }
-
-        readden = 0xdeadbeef;
-        SetLastError(0xdeadbeef);
-        ok(!ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n");
-        ok(readden == 0, "got %d bytes\n", readden);
-        ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
-
-        /* and the same for the reverse direction */
-        ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n");
-        ok(written == 0, "write file len\n");
-
-        if (pipemode != PIPE_TYPE_BYTE)
-        {
-            ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError());
-            ok(readden == 0, "got %d bytes\n", readden);
-        }
-        else
-        {
-            SetLastError(0xdeadbeef);
-            ok(!ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n");
-            ok(readden == 0, "got %d bytes\n", readden);
-            ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
-        }
-
-        readden = 0xdeadbeef;
-        SetLastError(0xdeadbeef);
-        ok(!ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n");
-        ok(readden == 0, "got %d bytes\n", readden);
-        ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
-
-        ok(CloseHandle(hFile), "CloseHandle\n");
-    }
-
-    ok(CloseHandle(hnp), "CloseHandle\n");
-
-}
-
 static void test_NamedPipeHandleState(void)
 {
     HANDLE server, client;
@@ -2845,15 +2327,71 @@ static void test_NamedPipeHandleState(void)
     CloseHandle(server);
 }
 
+static void test_GetNamedPipeInfo(void)
+{
+    HANDLE server;
+
+    server = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX,
+        /* dwOpenMode */ PIPE_TYPE_BYTE | PIPE_WAIT,
+        /* nMaxInstances */ 1,
+        /* nOutBufSize */ 1024,
+        /* nInBufSize */ 1024,
+        /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+        /* lpSecurityAttrib */ NULL);
+    ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
+
+    test_pipe_info(server, PIPE_SERVER_END | PIPE_TYPE_BYTE, 1024, 1024, 1);
+
+    CloseHandle(server);
+
+    server = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX,
+        /* dwOpenMode */ PIPE_TYPE_MESSAGE | PIPE_NOWAIT,
+        /* nMaxInstances */ 3,
+        /* nOutBufSize */ 1024,
+        /* nInBufSize */ 1024,
+        /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+        /* lpSecurityAttrib */ NULL);
+    ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
+
+    test_pipe_info(server, PIPE_SERVER_END | PIPE_TYPE_MESSAGE, 1024, 1024, 3);
+
+    CloseHandle(server);
+
+    server = CreateNamedPipeA(PIPENAME, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX,
+        /* dwOpenMode */ PIPE_TYPE_MESSAGE | PIPE_WAIT,
+        /* nMaxInstances */ 1,
+        /* nOutBufSize */ 0,
+        /* nInBufSize */ 0,
+        /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+        /* lpSecurityAttrib */ NULL);
+    ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
+
+    test_pipe_info(server, PIPE_SERVER_END | PIPE_TYPE_MESSAGE, 0, 0, 1);
+
+    CloseHandle(server);
+
+    server = CreateNamedPipeA(PIPENAME, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX,
+        /* dwOpenMode */ PIPE_TYPE_MESSAGE | PIPE_WAIT,
+        /* nMaxInstances */ 1,
+        /* nOutBufSize */ 0xf000,
+        /* nInBufSize */ 0xf000,
+        /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+        /* lpSecurityAttrib */ NULL);
+    ok(server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
+
+    test_pipe_info(server, PIPE_SERVER_END | PIPE_TYPE_MESSAGE, 0xf000, 0xf000, 1);
+
+    CloseHandle(server);
+}
+
 static void test_readfileex_pending(void)
 {
     HANDLE server, client, event;
     BOOL ret;
-    DWORD err, wait, num_bytes, lpmode;
+    DWORD err, wait, num_bytes;
     OVERLAPPED overlapped;
     char read_buf[1024];
     char write_buf[1024];
-    const char long_test_string[] = "12test3456ab";
     const char test_string[] = "test";
     int i;
 
@@ -2893,9 +2431,6 @@ static void test_readfileex_pending(void)
     ret = ReadFileEx(server, read_buf, sizeof(read_buf), &overlapped, completion_routine);
     ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError());
     ok(completion_called == 0, "completion routine called before ReadFileEx returned\n");
-    wait = WaitForSingleObject(event, 100);
-    ok(wait == WAIT_TIMEOUT, "WaitForSingleObjectEx returned %x\n", wait);
-    ok(completion_called == 0, "completion routine called before WriteFile started\n");
 
     ret = WriteFile(client, test_string, strlen(test_string), &num_bytes, NULL);
     ok(ret == TRUE, "WriteFile failed\n");
@@ -2975,6 +2510,7 @@ static void test_readfileex_pending(void)
     SetLastError(0xdeadbeef);
     ret = ReadFile(server, read_buf, 0, &num_bytes, &overlapped);
     ok(!ret, "ReadFile should fail\n");
+todo_wine
     ok(GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %d\n", GetLastError());
     ok(num_bytes == 0, "bytes %u\n", num_bytes);
     ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal);
@@ -2990,9 +2526,11 @@ todo_wine
     ok(num_bytes == 1, "bytes %u\n", num_bytes);
 
     wait = WaitForSingleObject(event, 100);
+todo_wine
     ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait);
 
     ok(num_bytes == 1, "bytes %u\n", num_bytes);
+todo_wine
     ok((NTSTATUS)overlapped.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", overlapped.Internal);
     ok(overlapped.InternalHigh == 0, "expected 0, got %lu\n", overlapped.InternalHigh);
 
@@ -3004,449 +2542,513 @@ todo_wine
 
     CloseHandle(client);
     CloseHandle(server);
+    CloseHandle(event);
+}
 
-    /* On Windows versions > 2000 it is not possible to add PIPE_NOWAIT to a byte-mode
-     * PIPE after creating. Create a new pipe for the following tests. */
-    server = CreateNamedPipeA(PIPENAME, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX,
-        /* dwOpenMode */ PIPE_TYPE_BYTE | PIPE_NOWAIT,
-        /* nMaxInstances */ 1,
-        /* nOutBufSize */ 1024,
-        /* nInBufSize */ 1024,
-        /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
-        /* lpSecurityAttrib */ NULL);
-    ok(server != INVALID_HANDLE_VALUE, "cf failed\n");
-
-    client = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, NULL,
-        OPEN_EXISTING, 0, NULL);
-    ok(client != INVALID_HANDLE_VALUE, "cf failed\n");
+#define test_peek_pipe(a,b,c,d) _test_peek_pipe(__LINE__,a,b,c,d)
+static void _test_peek_pipe(unsigned line, HANDLE pipe, DWORD expected_read, DWORD expected_avail, DWORD expected_message_length)
+{
+    DWORD bytes_read = 0xdeadbeed, avail = 0xdeadbeef, left = 0xdeadbeed;
+    char buf[4000];
+    FILE_PIPE_PEEK_BUFFER *peek_buf = (void*)buf;
+    IO_STATUS_BLOCK io;
+    NTSTATUS status;
+    BOOL r;
+
+    r = PeekNamedPipe(pipe, buf, sizeof(buf), &bytes_read, &avail, &left);
+    ok_(__FILE__,line)(r, "PeekNamedPipe failed: %u\n", GetLastError());
+    ok_(__FILE__,line)(bytes_read == expected_read, "bytes_read = %u, expected %u\n", bytes_read, expected_read);
+    ok_(__FILE__,line)(avail == expected_avail, "avail = %u, expected %u\n", avail, expected_avail);
+    ok_(__FILE__,line)(left == expected_message_length - expected_read, "left = %d, expected %d\n",
+                       left, expected_message_length - expected_read);
+
+    status = NtFsControlFile(pipe, 0, NULL, NULL, &io, FSCTL_PIPE_PEEK, NULL, 0, buf, sizeof(buf));
+    ok_(__FILE__,line)(!status || status == STATUS_PENDING, "NtFsControlFile(FSCTL_PIPE_PEEK) failed: %x\n", status);
+    ok_(__FILE__,line)(io.Information == FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[expected_read]),
+                       "io.Information = %lu\n", io.Information);
+    ok_(__FILE__,line)(peek_buf->ReadDataAvailable == expected_avail, "ReadDataAvailable = %u, expected %u\n",
+                       peek_buf->ReadDataAvailable, expected_avail);
+    ok_(__FILE__,line)(peek_buf->MessageLength == expected_message_length, "MessageLength = %u, expected %u\n",
+                       peek_buf->MessageLength, expected_message_length);
+
+    if (expected_read)
+    {
+        r = PeekNamedPipe(pipe, buf, 1, &bytes_read, &avail, &left);
+        ok_(__FILE__,line)(r, "PeekNamedPipe failed: %u\n", GetLastError());
+        ok_(__FILE__,line)(bytes_read == 1, "bytes_read = %u, expected %u\n", bytes_read, expected_read);
+        ok_(__FILE__,line)(avail == expected_avail, "avail = %u, expected %u\n", avail, expected_avail);
+        ok_(__FILE__,line)(left == expected_message_length-1, "left = %d, expected %d\n", left, expected_message_length-1);
+    }
+}
+
+#define overlapped_read_sync(a,b,c,d,e) _overlapped_read_sync(__LINE__,a,b,c,d,e)
+static void _overlapped_read_sync(unsigned line, HANDLE reader, void *buf, DWORD buf_size, DWORD expected_result, BOOL partial_read)
+{
+    DWORD read_bytes = 0xdeadbeef;
+    OVERLAPPED overlapped;
+    BOOL res;
 
     memset(&overlapped, 0, sizeof(overlapped));
-    overlapped.hEvent = event;
+    overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
+    res = ReadFile(reader, buf, buf_size, &read_bytes, &overlapped);
+    if (partial_read)
+        ok_(__FILE__,line)(!res && GetLastError() == ERROR_MORE_DATA, "ReadFile returned: %x (%u)\n", res, GetLastError());
+    else
+        ok_(__FILE__,line)(res, "ReadFile failed: %u\n", GetLastError());
+    if(partial_read)
+        todo_wine ok_(__FILE__,line)(!read_bytes, "read_bytes %u expected 0\n", read_bytes);
+    else
+        ok_(__FILE__,line)(read_bytes == expected_result, "read_bytes %u expected %u\n", read_bytes, expected_result);
 
-    /* Initial check with empty pipe */
-    memset(read_buf, 0, sizeof(read_buf));
-    completion_called = 0;
-    ResetEvent(event);
-    ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine);
-    ok(ret == FALSE, "ReadFileEx succeded\n");
-    ok(completion_called == 0, "completion routine called before ReadFileEx returned\n");
-    ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %d\n", GetLastError());
-    wait = WaitForSingleObjectEx(event, 0, TRUE);
-    ok(wait == WAIT_TIMEOUT, "WaitForSingleObjectEx returned %x\n", wait);
-    ok(completion_called == 0, "completion routine called before writing to file\n");
+    read_bytes = 0xdeadbeef;
+    res = GetOverlappedResult(reader, &overlapped, &read_bytes, FALSE);
+    if (partial_read)
+        ok_(__FILE__,line)(!res && GetLastError() == ERROR_MORE_DATA,
+                           "GetOverlappedResult returned: %x (%u)\n", res, GetLastError());
+    else
+        ok_(__FILE__,line)(res, "GetOverlappedResult failed: %u\n", GetLastError());
+    ok_(__FILE__,line)(read_bytes == expected_result, "read_bytes %u expected %u\n", read_bytes, expected_result);
+    CloseHandle(overlapped.hEvent);
+}
 
-    /* Call ReadFileEx after writing content to the pipe */
-    num_bytes = 0xdeadbeef;
-    ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
-    ok(ret, "WriteFile failed, err=%i\n", GetLastError());
-    ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+#define overlapped_read_async(a,b,c,d) _overlapped_read_async(__LINE__,a,b,c,d)
+static void _overlapped_read_async(unsigned line, HANDLE reader, void *buf, DWORD buf_size, OVERLAPPED *overlapped)
+{
+    DWORD read_bytes = 0xdeadbeef;
+    BOOL res;
 
-    memset(read_buf, 0, sizeof(read_buf));
-    completion_called = 0;
-    ResetEvent(event);
-    ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine);
-    ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError());
-    ok(completion_called == 0, "completion routine called before ReadFileEx returned\n");
-    wait = WaitForSingleObjectEx(event, 0, TRUE);
-    ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait);
-    ok(completion_called == 1, "completion not called after writing pipe\n");
-    ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode);
-    ok(completion_num_bytes == 4, "ReadFileEx returned only %d bytes\n", completion_num_bytes);
-    ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n");
+    memset(overlapped, 0, sizeof(*overlapped));
+    overlapped->hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
+    res = ReadFile(reader, buf, buf_size, &read_bytes, overlapped);
+    ok_(__FILE__,line)(!res && GetLastError() == ERROR_IO_PENDING, "ReadFile returned %x(%u)\n", res, GetLastError());
+    ok_(__FILE__,line)(!read_bytes, "read_bytes %u expected 0\n", read_bytes);
 
-    ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL);
-    ok(ret == TRUE, "ReadFile succeeded\n");
-    ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes);
-    ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+    _test_not_signaled(line, overlapped->hEvent);
+}
 
-    /* Same again, but read as a single part */
-    num_bytes = 0xdeadbeef;
-    ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
-    ok(ret, "WriteFile failed, err=%i\n", GetLastError());
-    ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+#define overlapped_write_sync(a,b,c) _overlapped_write_sync(__LINE__,a,b,c)
+static void _overlapped_write_sync(unsigned line, HANDLE writer, void *buf, DWORD size)
+{
+    DWORD written_bytes = 0xdeadbeef;
+    OVERLAPPED overlapped;
+    BOOL res;
 
-    memset(read_buf, 0, sizeof(read_buf));
-    completion_called = 0;
-    ResetEvent(event);
-    ret = ReadFileEx(server, read_buf, sizeof(read_buf), &overlapped, completion_routine);
-    ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError());
-    ok(completion_called == 0, "completion routine called before ReadFileEx returned\n");
-    wait = WaitForSingleObjectEx(event, 0, TRUE);
-    ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait);
-    ok(completion_called == 1, "completion not called after writing pipe\n");
-    ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode);
-    ok(completion_num_bytes == strlen(long_test_string), "ReadFileEx returned only %d bytes\n", completion_num_bytes);
-    ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n");
-    ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+    memset(&overlapped, 0, sizeof(overlapped));
+    overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
+    res = WriteFile(writer, buf, size, &written_bytes, &overlapped);
+    ok_(__FILE__,line)(res, "WriteFile returned %x(%u)\n", res, GetLastError());
+    ok_(__FILE__,line)(written_bytes == size, "WriteFile returned written_bytes = %u\n", written_bytes);
 
-    /* Check content of overlapped structure */
-    memset(read_buf, 0, sizeof(read_buf));
-    S(U(overlapped)).Offset = 0;
-    S(U(overlapped)).OffsetHigh = 0;
-    overlapped.Internal = -1;
-    overlapped.InternalHigh = -1;
-    overlapped.hEvent = event;
-    num_bytes = 0xdeadbeef;
-    SetLastError(0xdeadbeef);
-    ret = ReadFile(server, read_buf, 4, &num_bytes, &overlapped);
-    ok(ret == FALSE, "ReadFile succeeded\n");
-    ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %d\n", GetLastError());
-    ok(num_bytes == 0, "bytes %u\n", num_bytes);
-    ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal);
-    todo_wine
-    ok(overlapped.InternalHigh == -1, "expected -1, got %lu\n", overlapped.InternalHigh);
-    wait = WaitForSingleObject(event, 100);
-    ok(wait == WAIT_TIMEOUT, "WaitForSingleObjectEx returned %x\n", wait);
-    ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal);
-    todo_wine
-    ok(overlapped.InternalHigh == -1, "expected -1, got %lu\n", overlapped.InternalHigh);
+    written_bytes = 0xdeadbeef;
+    res = GetOverlappedResult(writer, &overlapped, &written_bytes, FALSE);
+    ok_(__FILE__,line)(res, "GetOverlappedResult failed: %u\n", GetLastError());
+    ok_(__FILE__,line)(written_bytes == size, "GetOverlappedResult returned written_bytes %u expected %u\n", written_bytes, size);
 
-    /* Call ReadFile after writing to the pipe */
-    num_bytes = 0xdeadbeef;
-    ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
-    ok(ret, "WriteFile failed, err=%i\n", GetLastError());
-    ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+    CloseHandle(overlapped.hEvent);
+}
 
-    memset(read_buf, 0, sizeof(read_buf));
-    S(U(overlapped)).Offset = 0;
-    S(U(overlapped)).OffsetHigh = 0;
-    overlapped.Internal = -1;
-    overlapped.InternalHigh = -1;
-    overlapped.hEvent = event;
-    num_bytes = 0xdeadbeef;
-    SetLastError(0xdeadbeef);
-    ret = ReadFile(server, read_buf, 4, &num_bytes, &overlapped);
-    ok(ret == TRUE, "ReadFile failed, err=%i\n", GetLastError());
-    ok(num_bytes == 4, "bytes %u\n", num_bytes);
-    ok((NTSTATUS)overlapped.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", overlapped.Internal);
-    ok(overlapped.InternalHigh == 4, "expected 4, got %lu\n", overlapped.InternalHigh);
-    wait = WaitForSingleObject(event, 100);
-    ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait);
-    ok((NTSTATUS)overlapped.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", overlapped.Internal);
-    ok(overlapped.InternalHigh == 4, "expected 4, got %lu\n", overlapped.InternalHigh);
+#define overlapped_write_async(a,b,c,d) _overlapped_write_async(__LINE__,a,b,c,d)
+static void _overlapped_write_async(unsigned line, HANDLE writer, void *buf, DWORD size, OVERLAPPED *overlapped)
+{
+    DWORD written_bytes = 0xdeadbeef;
+    BOOL res;
 
-    ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL);
-    ok(ret == TRUE, "ReadFile failed\n");
-    ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes);
-    ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+    memset(overlapped, 0, sizeof(*overlapped));
+    overlapped->hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
+    res = WriteFile(writer, buf, size, &written_bytes, overlapped);
+    ok_(__FILE__,line)(!res && GetLastError() == ERROR_IO_PENDING, "WriteFile returned %x(%u)\n", res, GetLastError());
+    todo_wine ok_(__FILE__,line)(!written_bytes, "written_bytes = %u\n", written_bytes);
 
-    /* Same again, but read as a single part */
-    num_bytes = 0xdeadbeef;
-    ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
-    ok(ret, "WriteFile failed, err=%i\n", GetLastError());
-    ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+    _test_not_signaled(line, overlapped->hEvent);
+}
 
-    memset(read_buf, 0, sizeof(read_buf));
-    S(U(overlapped)).Offset = 0;
-    S(U(overlapped)).OffsetHigh = 0;
-    overlapped.Internal = -1;
-    overlapped.InternalHigh = -1;
-    overlapped.hEvent = event;
-    num_bytes = 0xdeadbeef;
-    SetLastError(0xdeadbeef);
-    ret = ReadFile(server, read_buf, sizeof(read_buf), &num_bytes, &overlapped);
-    ok(ret == TRUE, "ReadFile failed, err=%i\n", GetLastError());
-    ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
-    ok((NTSTATUS)overlapped.Internal == 0, "expected 0, got %#lx\n", overlapped.Internal);
-    ok(overlapped.InternalHigh == strlen(long_test_string), "expected %u, got %lu\n", (DWORD)strlen(long_test_string), overlapped.InternalHigh);
-    wait = WaitForSingleObject(event, 100);
-    ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait);
-    ok((NTSTATUS)overlapped.Internal == 0, "expected 0, got %#lx\n", overlapped.Internal);
-    ok(overlapped.InternalHigh == strlen(long_test_string), "expected %u, got %lu\n", (DWORD)strlen(long_test_string), overlapped.InternalHigh);
-    ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+#define test_flush_sync(a) _test_flush_sync(__LINE__,a)
+static void _test_flush_sync(unsigned line, HANDLE pipe)
+{
+    BOOL res;
 
-    CloseHandle(client);
-    CloseHandle(server);
+    res = FlushFileBuffers(pipe);
+    ok_(__FILE__,line)(res, "FlushFileBuffers failed: %u\n", GetLastError());
+}
 
-    server = CreateNamedPipeA(PIPENAME, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX,
-        /* dwOpenMode */ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
-        /* nMaxInstances */ 1,
-        /* nOutBufSize */ 1024,
-        /* nInBufSize */ 1024,
-        /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
-        /* lpSecurityAttrib */ NULL);
-    ok(server != INVALID_HANDLE_VALUE, "cf failed\n");
+static DWORD expected_flush_error;
 
-    client = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, NULL,
-        OPEN_EXISTING, 0, NULL);
-    ok(client != INVALID_HANDLE_VALUE, "cf failed\n");
+static DWORD CALLBACK flush_proc(HANDLE pipe)
+{
+    BOOL res;
 
-    memset(&overlapped, 0, sizeof(overlapped));
-    overlapped.hEvent = event;
+    res = FlushFileBuffers(pipe);
+    if (expected_flush_error == ERROR_SUCCESS)
+        ok(res, "FlushFileBuffers failed: %u\n", GetLastError());
+    else
+        todo_wine ok(!res && GetLastError() == expected_flush_error, "FlushFileBuffers failed: %u\n", GetLastError());
+    return 0;
+}
 
-    /* Start a call to ReadFileEx which cannot complete immediately */
-    memset(read_buf, 0, sizeof(read_buf));
-    completion_called = 0;
-    ResetEvent(event);
-    ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine);
-    ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError());
-    ok(completion_called == 0, "completion routine called before ReadFileEx returned\n");
-    wait = WaitForSingleObject(event, 100);
-    ok(wait == WAIT_TIMEOUT, "WaitForSingleObject returned %x\n", wait);
-    ok(completion_called == 0, "completion routine called before WriteFile started\n");
+#define test_flush_async(a,b) _test_flush_async(__LINE__,a,b)
+static HANDLE _test_flush_async(unsigned line, HANDLE pipe, DWORD error)
+{
+    HANDLE thread;
+    DWORD tid;
 
-    ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
-    ok(ret == TRUE, "WriteFile failed\n");
-    ok(num_bytes == strlen(long_test_string), "only %i bytes written\n", num_bytes);
-    ok(completion_called == 0, "completion routine called during WriteFile\n");
-    wait = WaitForSingleObjectEx(event, 0, TRUE);
-    ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait);
+    expected_flush_error = error;
+    thread = CreateThread(NULL, 0, flush_proc, pipe, 0, &tid);
+    ok_(__FILE__,line)(thread != NULL, "CreateThread failed: %u\n", GetLastError());
 
-    ok(completion_called == 1, "completion not called after writing pipe\n");
-    ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode);
-    ok(completion_num_bytes == 4, "ReadFileEx returned only %d bytes\n", completion_num_bytes);
-    ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n");
-    ok(!memcmp(long_test_string, read_buf, 4), "ReadFileEx read wrong bytes\n");
-
-    ret = ReadFile(server, read_buf + 4, 4, &num_bytes, NULL);
-    ok(ret == FALSE, "ReadFile succeeded\n");
-    ok(num_bytes == 4, "ReadFile returned only %d bytes\n", num_bytes);
-    ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n");
-    ret = ReadFile(server, read_buf + 8, sizeof(read_buf) - 8, &num_bytes, NULL);
-    ok(ret == TRUE, "ReadFile failed\n");
-    ok(num_bytes == strlen(long_test_string)-8, "ReadFile returned only %d bytes\n", num_bytes);
-    ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
-
-    /* Call ReadFileEx when there is already some content in the pipe */
-    ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
-    ok(ret == TRUE, "WriteFile failed\n");
-    ok(num_bytes == strlen(long_test_string), "only %i bytes written\n", num_bytes);
+    Sleep(50);
+    _test_not_signaled(line, thread);
+    return thread;
+}
 
-    memset(read_buf, 0, sizeof(read_buf));
-    completion_called = 0;
-    ResetEvent(event);
-    ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine);
-    ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError());
-    ok(completion_called == 0, "completion routine called before ReadFileEx returned\n");
-    wait = WaitForSingleObjectEx(event, 0, TRUE);
-    ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait);
-    ok(completion_called == 1, "completion not called after writing pipe\n");
-    ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode);
-    ok(completion_num_bytes == 4, "ReadFileEx returned only %d bytes\n", completion_num_bytes);
-    ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n");
-    ok(!memcmp(long_test_string, read_buf, 4), "ReadFileEx read wrong bytes\n");
+#define test_flush_done(a) _test_flush_done(__LINE__,a)
+static void _test_flush_done(unsigned line, HANDLE thread)
+{
+    DWORD res = WaitForSingleObject(thread, 1000);
+    ok_(__FILE__,line)(res == WAIT_OBJECT_0, "WaitForSingleObject returned %u (%u)\n", res, GetLastError());
+    CloseHandle(thread);
+}
 
-    ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL);
-    ok(ret == TRUE, "ReadFile failed\n");
-    ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes);
-    ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+#define test_overlapped_result(a,b,c,d) _test_overlapped_result(__LINE__,a,b,c,d)
+static void _test_overlapped_result(unsigned line, HANDLE handle, OVERLAPPED *overlapped, DWORD expected_result, BOOL partial_read)
+{
+    DWORD result = 0xdeadbeef;
+    BOOL res;
 
-    /* Check content of overlapped structure */
-    memset(read_buf, 0, sizeof(read_buf));
-    S(U(overlapped)).Offset = 0;
-    S(U(overlapped)).OffsetHigh = 0;
-    overlapped.Internal = -1;
-    overlapped.InternalHigh = -1;
-    overlapped.hEvent = event;
-    num_bytes = 0xdeadbeef;
-    SetLastError(0xdeadbeef);
-    ret = ReadFile(server, read_buf, 4, &num_bytes, &overlapped);
-    ok(GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %d\n", GetLastError());
-    ok(num_bytes == 0, "bytes %u\n", num_bytes);
-    ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal);
-    todo_wine
-    ok(overlapped.InternalHigh == -1, "expected -1, got %lu\n", overlapped.InternalHigh);
-    wait = WaitForSingleObject(event, 100);
-    ok(wait == WAIT_TIMEOUT, "WaitForSingleObject returned %x\n", wait);
-    ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal);
+    _test_signaled(line, overlapped->hEvent);
 
-    num_bytes = 0xdeadbeef;
-    ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
-    ok(ret, "WriteFile failed\n");
-    ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
-    wait = WaitForSingleObject(event, 100);
-    ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait);
-    ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
-    ok((NTSTATUS)overlapped.Internal == STATUS_BUFFER_OVERFLOW, "expected STATUS_BUFFER_OVERFLOW, got %#lx\n", overlapped.Internal);
-    ok(overlapped.InternalHigh == 4, "expected 4, got %lu\n", overlapped.InternalHigh);
+    res = GetOverlappedResult(handle, overlapped, &result, FALSE);
+    if (partial_read)
+        ok_(__FILE__,line)(!res && GetLastError() == ERROR_MORE_DATA, "GetOverlappedResult returned: %x (%u)\n", res, GetLastError());
+    else
+        ok_(__FILE__,line)(res, "GetOverlappedResult failed: %u\n", GetLastError());
+    ok_(__FILE__,line)(result == expected_result, "read_bytes = %u, expected %u\n", result, expected_result);
+    CloseHandle(overlapped->hEvent);
+}
 
-    ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL);
-    ok(ret == TRUE, "ReadFile failed\n");
-    ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes);
-    ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+#define test_overlapped_failure(a,b,c) _test_overlapped_failure(__LINE__,a,b,c)
+static void _test_overlapped_failure(unsigned line, HANDLE handle, OVERLAPPED *overlapped, DWORD error)
+{
+    DWORD result;
+    BOOL res;
 
-    /* Call ReadFile when there is already some content in the pipe */
-    num_bytes = 0xdeadbeef;
-    ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
-    ok(ret, "WriteFile failed\n");
-    ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+    _test_signaled(line, overlapped->hEvent);
 
-    memset(read_buf, 0, sizeof(read_buf));
-    S(U(overlapped)).Offset = 0;
-    S(U(overlapped)).OffsetHigh = 0;
-    overlapped.Internal = -1;
-    overlapped.InternalHigh = -1;
-    overlapped.hEvent = event;
-    num_bytes = 0xdeadbeef;
-    SetLastError(0xdeadbeef);
-    ret = ReadFile(server, read_buf, 4, &num_bytes, &overlapped);
-    ok(ret == FALSE, "ReadFile succeeded\n");
-    ok(GetLastError() == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", GetLastError());
-    todo_wine
-    ok(num_bytes == 0, "ReadFile returned %d bytes\n", num_bytes);
-    wait = WaitForSingleObjectEx(event, 0, TRUE);
-    ok(wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait);
-    todo_wine
-    ok(num_bytes == 0, "bytes %u\n", num_bytes);
-    ok((NTSTATUS)overlapped.Internal == STATUS_BUFFER_OVERFLOW, "expected STATUS_BUFFER_OVERFLOW, got %#lx\n", overlapped.Internal);
-    ok(overlapped.InternalHigh == 4, "expected 4, got %lu\n", overlapped.InternalHigh);
+    res = GetOverlappedResult(handle, overlapped, &result, FALSE);
+    ok_(__FILE__,line)(!res && GetLastError() == error, "GetOverlappedResult returned: %x (%u), expected error %u\n",
+                       res, GetLastError(), error);
+    ok_(__FILE__,line)(!result, "result = %u\n", result);
+    CloseHandle(overlapped->hEvent);
+}
 
-    ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL);
-    ok(ret == TRUE, "ReadFile failed\n");
-    ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes);
-    ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+#define cancel_overlapped(a,b) _cancel_overlapped(__LINE__,a,b)
+static void _cancel_overlapped(unsigned line, HANDLE handle, OVERLAPPED *overlapped)
+{
+    BOOL res;
 
-    /* Tests for PIPE_NOWAIT in message mode */
-    lpmode = PIPE_READMODE_MESSAGE | PIPE_NOWAIT;
-    ok(SetNamedPipeHandleState(server, &lpmode, NULL, NULL), "Change mode\n");
+    res = pCancelIoEx(handle, overlapped);
+    ok_(__FILE__,line)(res, "CancelIoEx failed: %u\n", GetLastError());
 
-    /* Initial check with empty pipe */
-    memset(read_buf, 0, sizeof(read_buf));
-    completion_called = 0;
-    ResetEvent(event);
-    ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine);
-    ok(ret == FALSE, "ReadFileEx succeded\n");
-    ok(completion_called == 0, "completion routine called before ReadFileEx returned\n");
-    ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %d\n", GetLastError());
-    wait = WaitForSingleObjectEx(event, 0, TRUE);
-    ok(wait == WAIT_TIMEOUT, "WaitForSingleObjectEx returned %x\n", wait);
-    ok(completion_called == 0, "completion routine called before writing to file\n");
+    _test_overlapped_failure(line, handle, overlapped, ERROR_OPERATION_ABORTED);
+}
 
-    /* Call ReadFileEx after writing content to the pipe */
-    num_bytes = 0xdeadbeef;
-    ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
-    ok(ret, "WriteFile failed, err=%i\n", GetLastError());
-    ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+static void test_blocking_rw(HANDLE writer, HANDLE reader, DWORD buf_size, BOOL msg_mode, BOOL msg_read)
+{
+    OVERLAPPED read_overlapped, read_overlapped2, write_overlapped, write_overlapped2;
+    char buf[10000], read_buf[10000];
+    HANDLE flush_thread;
 
-    memset(read_buf, 0, sizeof(read_buf));
-    completion_called = 0;
-    ResetEvent(event);
-    ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine);
-    ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError());
-    ok(completion_called == 0, "completion routine called before ReadFileEx returned\n");
-    wait = WaitForSingleObjectEx(event, 0, TRUE);
-    ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait);
-    ok(completion_called == 1, "completion not called after writing pipe\n");
-    ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode);
-    ok(completion_num_bytes == 4, "ReadFileEx returned only %d bytes\n", completion_num_bytes);
-    ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n");
+    memset(buf, 0xaa, sizeof(buf));
 
-    ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL);
-    ok(ret == TRUE, "ReadFile succeeded\n");
-    ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes);
-    ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+    /* test pending read with overlapped event */
+    overlapped_read_async(reader, read_buf, 1000, &read_overlapped);
+    test_flush_sync(writer);
+    test_peek_pipe(reader, 0, 0, 0);
 
-    /* Same again, but read as a single part */
-    num_bytes = 0xdeadbeef;
-    ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
-    ok(ret, "WriteFile failed, err=%i\n", GetLastError());
-    ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+    /* write more data than needed for read */
+    overlapped_write_sync(writer, buf, 4000);
+    test_overlapped_result(reader, &read_overlapped, 1000, msg_read);
 
-    memset(read_buf, 0, sizeof(read_buf));
-    completion_called = 0;
-    ResetEvent(event);
-    ret = ReadFileEx(server, read_buf, sizeof(read_buf), &overlapped, completion_routine);
-    ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError());
-    ok(completion_called == 0, "completion routine called before ReadFileEx returned\n");
-    wait = WaitForSingleObjectEx(event, 0, TRUE);
-    ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait);
-    ok(completion_called == 1, "completion not called after writing pipe\n");
-    ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode);
-    ok(completion_num_bytes == strlen(long_test_string), "ReadFileEx returned only %d bytes\n", completion_num_bytes);
-    ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n");
-    ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+    /* test pending write with overlapped event */
+    overlapped_write_async(writer, buf, buf_size, &write_overlapped);
 
-    /* Check content of overlapped structure */
-    memset(read_buf, 0, sizeof(read_buf));
-    S(U(overlapped)).Offset = 0;
-    S(U(overlapped)).OffsetHigh = 0;
-    overlapped.Internal = -1;
-    overlapped.InternalHigh = -1;
-    overlapped.hEvent = event;
-    num_bytes = 0xdeadbeef;
-    SetLastError(0xdeadbeef);
-    ret = ReadFile(server, read_buf, 4, &num_bytes, &overlapped);
-    ok(ret == FALSE, "ReadFile succeeded\n");
-    ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %d\n", GetLastError());
-    ok(num_bytes == 0, "bytes %u\n", num_bytes);
-    ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal);
-    todo_wine
-    ok(overlapped.InternalHigh == -1, "expected -1, got %lu\n", overlapped.InternalHigh);
-    wait = WaitForSingleObject(event, 100);
-    ok(wait == WAIT_TIMEOUT, "WaitForSingleObjectEx returned %x\n", wait);
-    ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal);
-    todo_wine
-    ok(overlapped.InternalHigh == -1, "expected -1, got %lu\n", overlapped.InternalHigh);
+    /* write one more byte */
+    overlapped_write_async(writer, buf, 1, &write_overlapped2);
+    flush_thread = test_flush_async(writer, ERROR_SUCCESS);
+    test_not_signaled(write_overlapped.hEvent);
 
-    /* Call ReadFile after writing to the pipe */
-    num_bytes = 0xdeadbeef;
-    ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
-    ok(ret, "WriteFile failed, err=%i\n", GetLastError());
-    ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+    /* empty write will not block */
+    overlapped_write_sync(writer, buf, 0);
+    test_not_signaled(write_overlapped.hEvent);
+    test_not_signaled(write_overlapped2.hEvent);
 
-    memset(read_buf, 0, sizeof(read_buf));
-    S(U(overlapped)).Offset = 0;
-    S(U(overlapped)).OffsetHigh = 0;
-    overlapped.Internal = -1;
-    overlapped.InternalHigh = -1;
-    overlapped.hEvent = event;
-    num_bytes = 0xdeadbeef;
-    SetLastError(0xdeadbeef);
-    ret = ReadFile(server, read_buf, 4, &num_bytes, &overlapped);
-    ok(ret == FALSE, "ReadFile succeeded\n");
-    ok(GetLastError() == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", GetLastError());
-    todo_wine
-    ok(num_bytes == 0, "bytes %u\n", num_bytes);
-    ok((NTSTATUS)overlapped.Internal == STATUS_BUFFER_OVERFLOW, "expected STATUS_BUFFER_OVERFLOW, got %#lx\n", overlapped.Internal);
-    ok(overlapped.InternalHigh == 4, "expected 4, got %lu\n", overlapped.InternalHigh);
-    wait = WaitForSingleObject(event, 100);
-    ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait);
-    ok((NTSTATUS)overlapped.Internal == STATUS_BUFFER_OVERFLOW, "expected STATUS_BUFFER_OVERFLOW, got %#lx\n", overlapped.Internal);
-    ok(overlapped.InternalHigh == 4, "expected 4, got %lu\n", overlapped.InternalHigh);
+    /* read remaining data from the first write */
+    overlapped_read_sync(reader, read_buf, 3000, 3000, FALSE);
+    test_overlapped_result(writer, &write_overlapped, buf_size, FALSE);
+    test_not_signaled(write_overlapped2.hEvent);
+    test_not_signaled(flush_thread);
 
-    ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL);
-    ok(ret == TRUE, "ReadFile failed\n");
-    ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes);
-    ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+    /* read one byte so that the next write fits the buffer */
+    overlapped_read_sync(reader, read_buf, 1, 1, msg_read);
+    test_overlapped_result(writer, &write_overlapped2, 1, FALSE);
 
-    /* Same again, but read as a single part */
-    num_bytes = 0xdeadbeef;
-    ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL);
-    ok(ret, "WriteFile failed, err=%i\n", GetLastError());
-    ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
+    /* read the whole buffer */
+    overlapped_read_sync(reader, read_buf, buf_size, buf_size-msg_read, FALSE);
 
-    memset(read_buf, 0, sizeof(read_buf));
-    S(U(overlapped)).Offset = 0;
-    S(U(overlapped)).OffsetHigh = 0;
-    overlapped.Internal = -1;
-    overlapped.InternalHigh = -1;
-    overlapped.hEvent = event;
-    num_bytes = 0xdeadbeef;
-    SetLastError(0xdeadbeef);
-    ret = ReadFile(server, read_buf, sizeof(read_buf), &num_bytes, &overlapped);
-    ok(ret == TRUE, "ReadFile failed, err=%i\n", GetLastError());
-    ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes);
-    ok((NTSTATUS)overlapped.Internal == 0, "expected 0, got %#lx\n", overlapped.Internal);
-    ok(overlapped.InternalHigh == strlen(long_test_string), "expected %u, got %lu\n", (DWORD)strlen(long_test_string), overlapped.InternalHigh);
-    wait = WaitForSingleObject(event, 100);
-    ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait);
-    ok((NTSTATUS)overlapped.Internal == 0, "expected 0, got %#lx\n", overlapped.Internal);
-    ok(overlapped.InternalHigh == strlen(long_test_string), "expected %u, got %lu\n", (DWORD)strlen(long_test_string), overlapped.InternalHigh);
-    ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n");
+    if(msg_read)
+        overlapped_read_sync(reader, read_buf, 1000, 1, FALSE);
+
+    if(msg_mode) {
+        /* we still have an empty message in queue */
+        overlapped_read_sync(reader, read_buf, 1000, 0, FALSE);
+    }
+    test_flush_done(flush_thread);
+
+    /* pipe is empty, the next read will block */
+    overlapped_read_async(reader, read_buf, 0, &read_overlapped);
+    overlapped_read_async(reader, read_buf, 1000, &read_overlapped2);
+
+    /* write one byte */
+    overlapped_write_sync(writer, buf, 1);
+    test_overlapped_result(reader, &read_overlapped, 0, msg_read);
+    test_overlapped_result(reader, &read_overlapped2, 1, FALSE);
+
+    /* write a message larger than buffer */
+    overlapped_write_async(writer, buf, buf_size+2000, &write_overlapped);
+
+    /* read so that pending write is still larger than the buffer */
+    overlapped_read_sync(reader, read_buf, 1999, 1999, msg_read);
+    test_not_signaled(write_overlapped.hEvent);
+
+    /* read one more byte */
+    overlapped_read_sync(reader, read_buf, 1, 1, msg_read);
+    test_overlapped_result(writer, &write_overlapped, buf_size+2000, FALSE);
+
+    /* read remaining data */
+    overlapped_read_sync(reader, read_buf, buf_size+1, buf_size, FALSE);
+
+    /* simple pass of empty message */
+    overlapped_write_sync(writer, buf, 0);
+    if(msg_mode)
+        overlapped_read_sync(reader, read_buf, 1, 0, FALSE);
+
+    /* pipe is empty, the next read will block */
+    test_flush_sync(writer);
+    overlapped_read_async(reader, read_buf, 0, &read_overlapped);
+    overlapped_read_async(reader, read_buf, 1, &read_overlapped2);
+
+    /* 0 length write wakes one read in msg mode */
+    overlapped_write_sync(writer, buf, 0);
+    if(msg_mode)
+        test_overlapped_result(reader, &read_overlapped, 0, FALSE);
+    else
+        test_not_signaled(read_overlapped.hEvent);
+    test_not_signaled(read_overlapped2.hEvent);
+    overlapped_write_sync(writer, buf, 1);
+    test_overlapped_result(reader, &read_overlapped2, 1, FALSE);
+
+    overlapped_write_sync(writer, buf, 20);
+    test_peek_pipe(reader, 20, 20, msg_mode ? 20 : 0);
+    overlapped_write_sync(writer, buf, 15);
+    test_peek_pipe(reader, msg_mode ? 20 : 35, 35, msg_mode ? 20 : 0);
+    overlapped_read_sync(reader, read_buf, 10, 10, msg_read);
+    test_peek_pipe(reader, msg_mode ? 10 : 25, 25, msg_mode ? 10 : 0);
+    overlapped_read_sync(reader, read_buf, 10, 10, FALSE);
+    test_peek_pipe(reader, 15, 15, msg_mode ? 15 : 0);
+    overlapped_read_sync(reader, read_buf, 15, 15, FALSE);
+
+    if(!pCancelIoEx) {
+        win_skip("CancelIoEx not available\n");
+        return;
+    }
+
+    /* add one more pending read, then cancel the first one */
+    overlapped_read_async(reader, read_buf, 1, &read_overlapped);
+    overlapped_read_async(reader, read_buf, 1, &read_overlapped2);
+    cancel_overlapped(reader, &read_overlapped2);
+    test_not_signaled(read_overlapped.hEvent);
+    overlapped_write_sync(writer, buf, 1);
+    test_overlapped_result(reader, &read_overlapped, 1, FALSE);
+
+    /* make two async writes, cancel the first one and make sure that we read from the second one */
+    overlapped_write_async(writer, buf, buf_size+2000, &write_overlapped);
+    overlapped_write_async(writer, buf, 1, &write_overlapped2);
+    cancel_overlapped(writer, &write_overlapped);
+    overlapped_read_sync(reader, read_buf, 1000, 1, FALSE);
+    test_overlapped_result(writer, &write_overlapped2, 1, FALSE);
+
+    /* same as above, but parially read written data before canceling */
+    overlapped_write_async(writer, buf, buf_size+2000, &write_overlapped);
+    overlapped_write_async(writer, buf, 1, &write_overlapped2);
+    overlapped_read_sync(reader, read_buf, 10, 10, msg_read);
+    test_not_signaled(write_overlapped.hEvent);
+    cancel_overlapped(writer, &write_overlapped);
+    overlapped_read_sync(reader, read_buf, 1000, 1, FALSE);
+    test_overlapped_result(writer, &write_overlapped2, 1, FALSE);
+
+    /* empty queue by canceling write and make sure that flush is signaled */
+    overlapped_write_async(writer, buf, buf_size+2000, &write_overlapped);
+    flush_thread = test_flush_async(writer, ERROR_SUCCESS);
+    test_not_signaled(flush_thread);
+    cancel_overlapped(writer, &write_overlapped);
+    test_flush_done(flush_thread);
+}
+
+static void child_process_write_pipe(HANDLE pipe)
+{
+    OVERLAPPED overlapped;
+    char buf[10000];
+
+    memset(buf, 'x', sizeof(buf));
+    overlapped_write_async(pipe, buf, sizeof(buf), &overlapped);
+
+    /* sleep until parent process terminates this process */
+    Sleep(INFINITE);
+}
+
+static HANDLE create_writepipe_process(HANDLE pipe)
+{
+    STARTUPINFOA si = { sizeof(si) };
+    PROCESS_INFORMATION info;
+    char **argv, buf[MAX_PATH];
+    BOOL res;
+
+    winetest_get_mainargs(&argv);
+    sprintf(buf, "\"%s\" pipe writepipe %lx", argv[0], (UINT_PTR)pipe);
+    res = CreateProcessA(NULL, buf, NULL, NULL, TRUE, 0L, NULL, NULL, &si, &info);
+    ok(res, "CreateProcess failed: %u\n", GetLastError());
+    CloseHandle(info.hThread);
+
+    return info.hProcess;
+}
+
+static void create_overlapped_pipe(DWORD mode, HANDLE *client, HANDLE *server)
+{
+    SECURITY_ATTRIBUTES sec_attr = { sizeof(sec_attr), NULL, TRUE };
+    DWORD read_mode = mode & (PIPE_READMODE_BYTE | PIPE_READMODE_MESSAGE);
+    OVERLAPPED overlapped;
+    BOOL res;
+
+    *server = CreateNamedPipeA(PIPENAME, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX,
+                               PIPE_WAIT | mode, 1, 5000, 6000, NMPWAIT_USE_DEFAULT_WAIT, NULL);
+    ok(&server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %u\n", GetLastError());
+    test_signaled(*server);
+
+    memset(&overlapped, 0, sizeof(overlapped));
+    overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
+    res = ConnectNamedPipe(*server, &overlapped);
+    ok(!res && GetLastError() == ERROR_IO_PENDING, "WriteFile returned %x(%u)\n", res, GetLastError());
+    test_not_signaled(*server);
+    test_not_signaled(overlapped.hEvent);
+
+    *client = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, &sec_attr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+    ok(*server != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
+
+    res = SetNamedPipeHandleState(*client, &read_mode, NULL, NULL);
+    ok(res, "SetNamedPipeHandleState failed: %u\n", GetLastError());
+
+    test_signaled(*client);
+    test_not_signaled(*server);
+    test_overlapped_result(*server, &overlapped, 0, FALSE);
+}
+
+static void test_overlapped_transport(BOOL msg_mode, BOOL msg_read_mode)
+{
+    OVERLAPPED overlapped, overlapped2;
+    HANDLE server, client, flush;
+    DWORD read_bytes;
+    HANDLE process;
+    char buf[60000];
+    BOOL res;
+
+    DWORD create_flags =
+        (msg_mode ? PIPE_TYPE_MESSAGE : PIPE_TYPE_BYTE) |
+        (msg_read_mode ? PIPE_READMODE_MESSAGE : PIPE_READMODE_BYTE);
+
+    create_overlapped_pipe(create_flags, &client, &server);
+
+    trace("testing %s, %s server->client writes...\n",
+          msg_mode ? "message mode" : "byte mode", msg_read_mode ? "message read" : "byte read");
+    test_blocking_rw(server, client, 5000, msg_mode, msg_read_mode);
+    trace("testing %s, %s client->server writes...\n",
+          msg_mode ? "message mode" : "byte mode", msg_read_mode ? "message read" : "byte read");
+    test_blocking_rw(client, server, 6000, msg_mode, msg_read_mode);
 
     CloseHandle(client);
     CloseHandle(server);
-    CloseHandle(event);
+
+    /* close client with pending writes */
+    create_overlapped_pipe(create_flags, &client, &server);
+    overlapped_write_async(server, buf, 7000, &overlapped);
+    flush = test_flush_async(server, ERROR_BROKEN_PIPE);
+    CloseHandle(client);
+    test_overlapped_failure(server, &overlapped, ERROR_BROKEN_PIPE);
+    test_flush_done(flush);
+    CloseHandle(server);
+
+    /* close server with pending writes */
+    create_overlapped_pipe(create_flags, &client, &server);
+    overlapped_write_async(client, buf, 7000, &overlapped);
+    flush = test_flush_async(client, ERROR_BROKEN_PIPE);
+    CloseHandle(server);
+    test_overlapped_failure(client, &overlapped, ERROR_BROKEN_PIPE);
+    test_flush_done(flush);
+    CloseHandle(client);
+
+    /* disconnect with pending writes */
+    create_overlapped_pipe(create_flags, &client, &server);
+    overlapped_write_async(client, buf, 7000, &overlapped);
+    overlapped_write_async(server, buf, 7000, &overlapped2);
+    flush = test_flush_async(client, ERROR_PIPE_NOT_CONNECTED);
+    res = DisconnectNamedPipe(server);
+    ok(res, "DisconnectNamedPipe failed: %u\n", GetLastError());
+    test_overlapped_failure(client, &overlapped, ERROR_PIPE_NOT_CONNECTED);
+    test_overlapped_failure(client, &overlapped2, ERROR_PIPE_NOT_CONNECTED);
+    test_flush_done(flush);
+    CloseHandle(server);
+    CloseHandle(client);
+
+    /* terminate process with pending write */
+    create_overlapped_pipe(create_flags, &client, &server);
+    process = create_writepipe_process(client);
+    /* successfully read part of write that is pending in child process */
+    res = ReadFile(server, buf, 10, &read_bytes, NULL);
+    if(!msg_read_mode)
+        ok(res, "ReadFile failed: %u\n", GetLastError());
+    else
+        ok(!res && GetLastError() == ERROR_MORE_DATA, "ReadFile returned: %x %u\n", res, GetLastError());
+    ok(read_bytes == 10, "read_bytes = %u\n", read_bytes);
+    TerminateProcess(process, 0);
+    winetest_wait_child_process(process);
+    /* after terminating process, there is no pending write and pipe buffer is empty */
+    overlapped_read_async(server, buf, 10, &overlapped);
+    overlapped_write_sync(client, buf, 1);
+    test_overlapped_result(server, &overlapped, 1, FALSE);
+    CloseHandle(process);
+    CloseHandle(server);
+    CloseHandle(client);
 }
 
 START_TEST(pipe)
 {
+    char **argv;
+    int argc;
     HMODULE hmod;
 
     hmod = GetModuleHandleA("advapi32.dll");
     pDuplicateTokenEx = (void *) GetProcAddress(hmod, "DuplicateTokenEx");
     hmod = GetModuleHandleA("kernel32.dll");
     pQueueUserAPC = (void *) GetProcAddress(hmod, "QueueUserAPC");
+    pCancelIoEx = (void *) GetProcAddress(hmod, "CancelIoEx");
+
+    argc = winetest_get_mainargs(&argv);
+
+    if (argc > 3 && !strcmp(argv[2], "writepipe"))
+    {
+        UINT_PTR handle;
+        sscanf(argv[3], "%lx", &handle);
+        child_process_write_pipe((HANDLE)handle);
+        return;
+    }
 
     if (test_DisconnectNamedPipe())
         return;
@@ -3459,8 +3061,11 @@ START_TEST(pipe)
     test_impersonation();
     test_overlapped();
     test_overlapped_error();
-    test_nowait(PIPE_TYPE_BYTE);
-    test_nowait(PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE);
     test_NamedPipeHandleState();
+    test_GetNamedPipeInfo();
     test_readfileex_pending();
+    test_overlapped_transport(TRUE, FALSE);
+    test_overlapped_transport(TRUE, TRUE);
+    if (broken(1)) /* FIXME: Remove once Wine is ready. */
+        test_overlapped_transport(FALSE, FALSE);
 }
index 77d21d8..e4553a3 100755 (executable)
@@ -88,6 +88,10 @@ static BOOL   (WINAPI *pThread32First)(HANDLE, THREADENTRY32*);
 static BOOL   (WINAPI *pThread32Next)(HANDLE, THREADENTRY32*);
 static BOOL   (WINAPI *pGetLogicalProcessorInformationEx)(LOGICAL_PROCESSOR_RELATIONSHIP,SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*,DWORD*);
 static SIZE_T (WINAPI *pGetLargePageMinimum)(void);
+static BOOL   (WINAPI *pInitializeProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD, SIZE_T*);
+static BOOL   (WINAPI *pUpdateProcThreadAttribute)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD_PTR, void *,SIZE_T,void*,SIZE_T*);
+static void   (WINAPI *pDeleteProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*);
+static DWORD  (WINAPI *pGetActiveProcessorCount)(WORD);
 
 /* ############################### */
 static char     base[MAX_PATH];
@@ -252,6 +256,10 @@ static BOOL init(void)
     pThread32Next = (void *)GetProcAddress(hkernel32, "Thread32Next");
     pGetLogicalProcessorInformationEx = (void *)GetProcAddress(hkernel32, "GetLogicalProcessorInformationEx");
     pGetLargePageMinimum = (void *)GetProcAddress(hkernel32, "GetLargePageMinimum");
+    pInitializeProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "InitializeProcThreadAttributeList");
+    pUpdateProcThreadAttribute = (void *)GetProcAddress(hkernel32, "UpdateProcThreadAttribute");
+    pDeleteProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "DeleteProcThreadAttributeList");
+    pGetActiveProcessorCount = (void *)GetProcAddress(hkernel32, "GetActiveProcessorCount");
 
     return TRUE;
 }
@@ -626,7 +634,7 @@ static void test_Startup(void)
     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 
     /* not so simplistic now */
     memset(&startup, 0, sizeof(startup));
@@ -664,7 +672,7 @@ static void test_Startup(void)
     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 
     /* not so simplistic now */
     memset(&startup, 0, sizeof(startup));
@@ -702,7 +710,7 @@ static void test_Startup(void)
     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 
     /* not so simplistic now */
     memset(&startup, 0, sizeof(startup));
@@ -740,7 +748,7 @@ static void test_Startup(void)
     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 
     /* not so simplistic now */
     memset(&startup, 0, sizeof(startup));
@@ -780,7 +788,7 @@ static void test_Startup(void)
     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 
     /* not so simplistic now */
     memset(&startup, 0, sizeof(startup));
@@ -818,7 +826,7 @@ static void test_Startup(void)
     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 
     /* not so simplistic now */
     memset(&startup, 0, sizeof(startup));
@@ -856,7 +864,7 @@ static void test_Startup(void)
     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 
     /* TODO: test for A/W and W/A and W/W */
 }
@@ -888,7 +896,7 @@ static void test_CommandLine(void)
     okChildString("Arguments", "argvA5", NULL);
     okChildString("Arguments", "CommandLineA", buffer);
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 
     memset(&startup, 0, sizeof(startup));
     startup.cb = sizeof(startup);
@@ -911,7 +919,7 @@ static void test_CommandLine(void)
     okChildString("Arguments", "argvA7", NULL);
     okChildString("Arguments", "CommandLineA", buffer);
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 
     /* Test for Bug1330 to show that XP doesn't change '/' to '\\' in argv[0]*/
     get_file_name(resfile);
@@ -927,7 +935,7 @@ static void test_CommandLine(void)
     sprintf(buffer, "./%s", exename);
     okChildString("Arguments", "argvA0", buffer);
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 
     get_file_name(resfile);
     /* Use exename to avoid buffer containing things like 'C:' */
@@ -942,8 +950,8 @@ static void test_CommandLine(void)
     sprintf(buffer, ".\\%s", exename);
     okChildString("Arguments", "argvA0", buffer);
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
-    
+    DeleteFileA(resfile);
+
     get_file_name(resfile);
     GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart);
     assert ( lpFilePart != 0);
@@ -963,7 +971,7 @@ static void test_CommandLine(void)
     else sprintf(buffer, "./%s", exename);
     okChildString("Arguments", "argvA0", buffer);
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 
     /* Using AppName */
     get_file_name(resfile);
@@ -987,7 +995,7 @@ static void test_CommandLine(void)
     okChildString("Arguments", "CommandLineA", buffer2);
     okChildStringWA("Arguments", "CommandLineW", buffer2);
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 
     if (0) /* Test crashes on NT-based Windows. */
     {
@@ -1082,7 +1090,7 @@ static void test_Directory(void)
 
     okChildIString("Misc", "CurrDirA", windir);
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 
     /* search PATH for the exe if directory is NULL */
     ok(CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info), "CreateProcess\n");
@@ -1295,7 +1303,7 @@ static void test_Environment(void)
     env = GetEnvironmentStringsA();
     cmpEnvironment(env);
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 
     memset(&startup, 0, sizeof(startup));
     startup.cb = sizeof(startup);
@@ -1354,7 +1362,7 @@ static void test_Environment(void)
     HeapFree(GetProcessHeap(), 0, child_env);
     FreeEnvironmentStringsA(env);
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 }
 
 static  void    test_SuspendFlag(void)
@@ -1402,7 +1410,7 @@ static  void    test_SuspendFlag(void)
     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 }
 
 static  void    test_DebuggingFlag(void)
@@ -1464,7 +1472,7 @@ static  void    test_DebuggingFlag(void)
     okChildInt("StartupInfoA", "dwFlags", startup.dwFlags);
     okChildInt("StartupInfoA", "wShowWindow", startup.wShowWindow);
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 }
 
 static BOOL is_console(HANDLE h)
@@ -1514,8 +1522,8 @@ static void test_Console(void)
     startup.hStdError = startup.hStdOutput;
 
     ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbi), "Getting sb info\n");
-    ok(GetConsoleMode(startup.hStdInput, &modeIn) && 
-       GetConsoleMode(startup.hStdOutput, &modeOut), "Getting console modes\n");
+    ok(GetConsoleMode(startup.hStdInput, &modeIn), "Getting console in mode\n");
+    ok(GetConsoleMode(startup.hStdOutput, &modeOut), "Getting console out mode\n");
     cpIn = GetConsoleCP();
     cpOut = GetConsoleOutputCP();
 
@@ -1530,8 +1538,8 @@ static void test_Console(void)
 
     /* now get the modification the child has made, and resets parents expected values */
     ok(GetConsoleScreenBufferInfo(startup.hStdOutput, &sbiC), "Getting sb info\n");
-    ok(GetConsoleMode(startup.hStdInput, &modeInC) && 
-       GetConsoleMode(startup.hStdOutput, &modeOutC), "Getting console modes\n");
+    ok(GetConsoleMode(startup.hStdInput, &modeInC), "Getting console in mode\n");
+    ok(GetConsoleMode(startup.hStdOutput, &modeOutC), "Getting console out mode\n");
 
     SetConsoleMode(startup.hStdInput, modeIn);
     SetConsoleMode(startup.hStdOutput, modeOut);
@@ -1611,7 +1619,7 @@ static void test_Console(void)
     ok(sbiC.dwCursorPosition.Y == (sbi.dwCursorPosition.Y ^ 1), "Wrong cursor position\n");
 
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 
     ok(CreatePipe(&hParentIn, &hChildOut, NULL, 0), "Creating parent-input pipe\n");
     ok(DuplicateHandle(GetCurrentProcess(), hChildOut, GetCurrentProcess(), 
@@ -1654,7 +1662,7 @@ static void test_Console(void)
     okChildString("StdHandle", "msg", msg);
 
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 }
 
 static  void    test_ExitCode(void)
@@ -1683,7 +1691,7 @@ static  void    test_ExitCode(void)
     okChildInt("ExitCode", "value", code);
 
     release_memory();
-    assert(DeleteFileA(resfile) != 0);
+    DeleteFileA(resfile);
 }
 
 static void test_OpenProcess(void)
@@ -1953,7 +1961,7 @@ static void test_QueryFullProcessImageNameW(void)
     expect_eq_d(lstrlenW(buf), size);
     expect_eq_ws_i(buf, module_name);
 
-    hSelf = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
+    hSelf = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, GetCurrentProcessId());
     /* Real handle */
     size = sizeof(buf) / sizeof(buf[0]);
     expect_eq_d(TRUE, pQueryFullProcessImageNameW(hSelf, 0, buf, &size));
@@ -2509,7 +2517,6 @@ static void test_QueryInformationJobObject(void)
     ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list,
                                     FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList), &ret_len);
     ok(!ret, "QueryInformationJobObject expected failure\n");
-    todo_wine
     expect_eq_d(ERROR_BAD_LENGTH, GetLastError());
 
     SetLastError(0xdeadbeef);
@@ -2518,18 +2525,20 @@ static void test_QueryInformationJobObject(void)
     pid_list->NumberOfProcessIdsInList  = 42;
     ret = QueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list,
                                     FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[1]), &ret_len);
+    todo_wine
     ok(!ret, "QueryInformationJobObject expected failure\n");
     todo_wine
     expect_eq_d(ERROR_MORE_DATA, GetLastError());
     if (ret)
     {
+        todo_wine
         expect_eq_d(42, pid_list->NumberOfAssignedProcesses);
+        todo_wine
         expect_eq_d(42, pid_list->NumberOfProcessIdsInList);
     }
 
     memset(buf, 0, sizeof(buf));
     ret = pQueryInformationJobObject(job, JobObjectBasicProcessIdList, pid_list, sizeof(buf), &ret_len);
-    todo_wine
     ok(ret, "QueryInformationJobObject error %u\n", GetLastError());
     if(ret)
     {
@@ -2539,12 +2548,17 @@ static void test_QueryInformationJobObject(void)
         {
             ULONG_PTR *list = pid_list->ProcessIdList;
 
+            todo_wine
             ok(ret_len == FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[2]),
                "QueryInformationJobObject returned ret_len=%u\n", ret_len);
 
+            todo_wine
             expect_eq_d(2, pid_list->NumberOfAssignedProcesses);
+            todo_wine
             expect_eq_d(2, pid_list->NumberOfProcessIdsInList);
+            todo_wine
             expect_eq_d(pi[0].dwProcessId, list[0]);
+            todo_wine
             expect_eq_d(pi[1].dwProcessId, list[1]);
         }
     }
@@ -2889,6 +2903,98 @@ static void test_StartupNoConsole(void)
 #endif
 }
 
+static void test_DetachConsoleHandles(void)
+{
+#ifndef _WIN64
+    char                buffer[MAX_PATH];
+    STARTUPINFOA        startup;
+    PROCESS_INFORMATION info;
+    UINT                result;
+
+    memset(&startup, 0, sizeof(startup));
+    startup.cb = sizeof(startup);
+    startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
+    startup.wShowWindow = SW_SHOWNORMAL;
+    startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+    startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+    startup.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+    get_file_name(resfile);
+    sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
+    ok(CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
+                      &info), "CreateProcess\n");
+    ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
+    WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
+
+    result = GetPrivateProfileIntA("StartupInfoA", "hStdInput", 0, resfile);
+    ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
+    result = GetPrivateProfileIntA("StartupInfoA", "hStdOutput", 0, resfile);
+    ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
+    result = GetPrivateProfileIntA("StartupInfoA", "hStdError", 0, resfile);
+    ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
+    result = GetPrivateProfileIntA("TEB", "hStdInput", 0, resfile);
+    ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
+    result = GetPrivateProfileIntA("TEB", "hStdOutput", 0, resfile);
+    ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
+    result = GetPrivateProfileIntA("TEB", "hStdError", 0, resfile);
+    ok(result != 0 && result != (UINT)INVALID_HANDLE_VALUE, "bad handle %x\n", result);
+
+    release_memory();
+    DeleteFileA(resfile);
+#endif
+}
+
+static void test_DetachStdHandles(void)
+{
+#ifndef _WIN64
+    char                buffer[MAX_PATH], tempfile[MAX_PATH];
+    STARTUPINFOA        startup;
+    PROCESS_INFORMATION info;
+    HANDLE              hstdin, hstdout, hstderr, htemp;
+    BOOL                res;
+
+    hstdin = GetStdHandle(STD_INPUT_HANDLE);
+    hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
+    hstderr = GetStdHandle(STD_ERROR_HANDLE);
+
+    get_file_name(tempfile);
+    htemp = CreateFileA(tempfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
+    ok(htemp != INVALID_HANDLE_VALUE, "failed opening temporary file\n");
+
+    memset(&startup, 0, sizeof(startup));
+    startup.cb = sizeof(startup);
+    startup.dwFlags = STARTF_USESHOWWINDOW;
+    startup.wShowWindow = SW_SHOWNORMAL;
+    get_file_name(resfile);
+    sprintf(buffer, "\"%s\" tests/process.c dump \"%s\"", selfname, resfile);
+
+    SetStdHandle(STD_INPUT_HANDLE, htemp);
+    SetStdHandle(STD_OUTPUT_HANDLE, htemp);
+    SetStdHandle(STD_ERROR_HANDLE, htemp);
+
+    res = CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &startup,
+                      &info);
+
+    SetStdHandle(STD_INPUT_HANDLE, hstdin);
+    SetStdHandle(STD_OUTPUT_HANDLE, hstdout);
+    SetStdHandle(STD_ERROR_HANDLE, hstderr);
+
+    ok(res, "CreateProcess failed\n");
+    ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n");
+    WritePrivateProfileStringA(NULL, NULL, NULL, resfile);
+    okChildInt("StartupInfoA", "hStdInput", (UINT)INVALID_HANDLE_VALUE);
+    okChildInt("StartupInfoA", "hStdOutput", (UINT)INVALID_HANDLE_VALUE);
+    okChildInt("StartupInfoA", "hStdError", (UINT)INVALID_HANDLE_VALUE);
+    okChildInt("TEB", "hStdInput", 0);
+    okChildInt("TEB", "hStdOutput", 0);
+    okChildInt("TEB", "hStdError", 0);
+    release_memory();
+    DeleteFileA(resfile);
+
+    CloseHandle(htemp);
+    DeleteFileA(tempfile);
+#endif
+}
+
 static void test_GetNumaProcessorNode(void)
 {
     SYSTEM_INFO si;
@@ -2981,23 +3087,23 @@ static void test_process_info(void)
         sizeof(buf) /* ProcessHandleTracing */,
         sizeof(ULONG) /* ProcessIoPriority */,
         sizeof(ULONG) /* ProcessExecuteFlags */,
-#if 0 /* FIXME: Add remaining classes */
-        ProcessResourceManagement,
-        sizeof(ULONG) /* ProcessCookie */,
+        0 /* FIXME: sizeof(?) ProcessTlsInformation */,
+        0 /* FIXME: sizeof(?) ProcessCookie */,
         sizeof(SECTION_IMAGE_INFORMATION) /* ProcessImageInformation */,
-        sizeof(PROCESS_CYCLE_TIME_INFORMATION) /* ProcessCycleTime */,
+        0 /* FIXME: sizeof(PROCESS_CYCLE_TIME_INFORMATION) ProcessCycleTime */,
         sizeof(ULONG) /* ProcessPagePriority */,
         40 /* ProcessInstrumentationCallback */,
-        sizeof(PROCESS_STACK_ALLOCATION_INFORMATION) /* ProcessThreadStackAllocation */,
-        sizeof(PROCESS_WS_WATCH_INFORMATION_EX[]) /* ProcessWorkingSetWatchEx */,
+        0 /* FIXME: sizeof(PROCESS_STACK_ALLOCATION_INFORMATION) ProcessThreadStackAllocation */,
+        0 /* FIXME: sizeof(PROCESS_WS_WATCH_INFORMATION_EX[]) ProcessWorkingSetWatchEx */,
         sizeof(buf) /* ProcessImageFileNameWin32 */,
         sizeof(HANDLE) /* ProcessImageFileMapping */,
-        sizeof(PROCESS_AFFINITY_UPDATE_MODE) /* ProcessAffinityUpdateMode */,
-        sizeof(PROCESS_MEMORY_ALLOCATION_MODE) /* ProcessMemoryAllocationMode */,
-        sizeof(USHORT[]) /* ProcessGroupInformation */,
+        0 /* FIXME: sizeof(PROCESS_AFFINITY_UPDATE_MODE) ProcessAffinityUpdateMode */,
+        0 /* FIXME: sizeof(PROCESS_MEMORY_ALLOCATION_MODE) ProcessMemoryAllocationMode */,
+        sizeof(USHORT) /* ProcessGroupInformation */,
         sizeof(ULONG) /* ProcessTokenVirtualizationEnabled */,
         sizeof(ULONG_PTR) /* ProcessConsoleHostProcess */,
-        sizeof(PROCESS_WINDOW_INFORMATION) /* ProcessWindowInformation */,
+        0 /* FIXME: sizeof(PROCESS_WINDOW_INFORMATION) ProcessWindowInformation */,
+#if 0 /* FIXME: Add remaining classes */
         sizeof(PROCESS_HANDLE_SNAPSHOT_INFORMATION) /* ProcessHandleInformation */,
         sizeof(PROCESS_MITIGATION_POLICY_INFORMATION) /* ProcessMitigationPolicy */,
         sizeof(ProcessDynamicFunctionTableInformation) /* ProcessDynamicFunctionTableInformation */,
@@ -3061,16 +3167,17 @@ static void test_process_info(void)
         case ProcessWow64Information:
         case ProcessDefaultHardErrorMode:
         case ProcessHandleCount:
-            ok(status == STATUS_SUCCESS, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len);
-            break;
-
         case ProcessImageFileName:
-todo_wine
+        case ProcessImageInformation:
+        case ProcessPagePriority:
+        case ProcessImageFileNameWin32:
             ok(status == STATUS_SUCCESS, "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len);
             break;
 
         case ProcessAffinityMask:
         case ProcessBreakOnTermination:
+        case ProcessGroupInformation:
+        case ProcessConsoleHostProcess:
             ok(status == STATUS_ACCESS_DENIED /* before win8 */ || status == STATUS_SUCCESS /* win8 is less strict */,
                "for info %u expected STATUS_SUCCESS, got %08x (ret_len %u)\n", i, status, ret_len);
             break;
@@ -3083,6 +3190,7 @@ todo_wine
         case ProcessExecuteFlags:
         case ProcessDebugPort:
         case ProcessDebugFlags:
+        case ProcessCookie:
 todo_wine
             ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
             break;
@@ -3141,6 +3249,142 @@ static void test_largepages(void)
     ok((size == 0) || (size == 2*1024*1024) || (size == 4*1024*1024), "GetLargePageMinimum reports %ld size\n", size);
 }
 
+struct proc_thread_attr
+{
+    DWORD_PTR attr;
+    SIZE_T size;
+    void *value;
+};
+
+struct _PROC_THREAD_ATTRIBUTE_LIST
+{
+    DWORD mask;  /* bitmask of items in list */
+    DWORD size;  /* max number of items in list */
+    DWORD count; /* number of items in list */
+    DWORD pad;
+    DWORD_PTR unk;
+    struct proc_thread_attr attrs[10];
+};
+
+static void test_ProcThreadAttributeList(void)
+{
+    BOOL ret;
+    SIZE_T size, needed;
+    int i;
+    struct _PROC_THREAD_ATTRIBUTE_LIST list, expect_list;
+    HANDLE handles[4];
+
+    if (!pInitializeProcThreadAttributeList)
+    {
+        win_skip("No support for ProcThreadAttributeList\n");
+        return;
+    }
+
+    for (i = 0; i <= 10; i++)
+    {
+        needed = FIELD_OFFSET(struct _PROC_THREAD_ATTRIBUTE_LIST, attrs[i]);
+        ret = pInitializeProcThreadAttributeList(NULL, i, 0, &size);
+        ok(!ret, "got %d\n", ret);
+        if(i >= 4 && GetLastError() == ERROR_INVALID_PARAMETER) /* Vista only allows a maximium of 3 slots */
+            break;
+        ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d\n", GetLastError());
+        ok(size == needed, "%d: got %ld expect %ld\n", i, size, needed);
+
+        memset(&list, 0xcc, sizeof(list));
+        ret = pInitializeProcThreadAttributeList(&list, i, 0, &size);
+        ok(ret, "got %d\n", ret);
+        ok(list.mask == 0, "%d: got %08x\n", i, list.mask);
+        ok(list.size == i, "%d: got %08x\n", i, list.size);
+        ok(list.count == 0, "%d: got %08x\n", i, list.count);
+        ok(list.unk == 0, "%d: got %08lx\n", i, list.unk);
+    }
+
+    memset(handles, 0, sizeof(handles));
+    memset(&expect_list, 0xcc, sizeof(expect_list));
+    expect_list.mask = 0;
+    expect_list.size = i - 1;
+    expect_list.count = 0;
+    expect_list.unk = 0;
+
+    ret = pUpdateProcThreadAttribute(&list, 0, 0xcafe, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL);
+    ok(!ret, "got %d\n", ret);
+    ok(GetLastError() == ERROR_NOT_SUPPORTED, "got %d\n", GetLastError());
+
+    ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) / 2, NULL, NULL);
+    ok(!ret, "got %d\n", ret);
+    ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError());
+
+    ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]) * 2, NULL, NULL);
+    ok(!ret, "got %d\n", ret);
+    ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError());
+
+    ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL);
+    ok(ret, "got %d\n", ret);
+
+    expect_list.mask |= 1 << ProcThreadAttributeParentProcess;
+    expect_list.attrs[0].attr = PROC_THREAD_ATTRIBUTE_PARENT_PROCESS;
+    expect_list.attrs[0].size = sizeof(handles[0]);
+    expect_list.attrs[0].value = handles;
+    expect_list.count++;
+
+    ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, handles, sizeof(handles[0]), NULL, NULL);
+    ok(!ret, "got %d\n", ret);
+    ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %d\n", GetLastError());
+
+    ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles) - 1, NULL, NULL);
+    ok(!ret, "got %d\n", ret);
+    ok(GetLastError() == ERROR_BAD_LENGTH, "got %d\n", GetLastError());
+
+    ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL);
+    ok(ret, "got %d\n", ret);
+
+    expect_list.mask |= 1 << ProcThreadAttributeHandleList;
+    expect_list.attrs[1].attr = PROC_THREAD_ATTRIBUTE_HANDLE_LIST;
+    expect_list.attrs[1].size = sizeof(handles);
+    expect_list.attrs[1].value = handles;
+    expect_list.count++;
+
+    ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handles, sizeof(handles), NULL, NULL);
+    ok(!ret, "got %d\n", ret);
+    ok(GetLastError() == ERROR_OBJECT_NAME_EXISTS, "got %d\n", GetLastError());
+
+    ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR, handles, sizeof(PROCESSOR_NUMBER), NULL, NULL);
+    ok(ret || (!ret && GetLastError() == ERROR_NOT_SUPPORTED), "got %d gle %d\n", ret, GetLastError());
+
+    if (ret)
+    {
+        expect_list.mask |= 1 << ProcThreadAttributeIdealProcessor;
+        expect_list.attrs[2].attr = PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR;
+        expect_list.attrs[2].size = sizeof(PROCESSOR_NUMBER);
+        expect_list.attrs[2].value = handles;
+        expect_list.count++;
+    }
+
+    ok(!memcmp(&list, &expect_list, size), "mismatch\n");
+
+    pDeleteProcThreadAttributeList(&list);
+}
+
+static void test_GetActiveProcessorCount(void)
+{
+    DWORD count;
+
+    if (!pGetActiveProcessorCount)
+    {
+        win_skip("GetActiveProcessorCount not available, skipping test\n");
+        return;
+    }
+
+    count = pGetActiveProcessorCount(0);
+    ok(count, "GetActiveProcessorCount failed, error %u\n", GetLastError());
+
+    /* Test would fail on systems with more than 6400 processors */
+    SetLastError(0xdeadbeef);
+    count = pGetActiveProcessorCount(101);
+    ok(count == 0, "Expeced GetActiveProcessorCount to fail\n");
+    ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
+}
+
 START_TEST(process)
 {
     HANDLE job;
@@ -3210,10 +3454,14 @@ START_TEST(process)
     test_RegistryQuota();
     test_DuplicateHandle();
     test_StartupNoConsole();
+    test_DetachConsoleHandles();
+    test_DetachStdHandles();
     test_GetNumaProcessorNode();
     test_session_info();
     test_GetLogicalProcessorInformationEx();
+    test_GetActiveProcessorCount();
     test_largepages();
+    test_ProcThreadAttributeList();
 
     /* things that can be tested:
      *  lookup:         check the way program to be executed is searched
index cb3a67c..28e35d4 100755 (executable)
@@ -1084,10 +1084,10 @@ static void test_SetThreadContext(void)
     ctx.ContextFlags = CONTEXT_FULL;
     SetLastError(0xdeadbeef);
     ret = GetThreadContext( thread, &ctx );
-    ok( (!ret && (GetLastError() == ERROR_GEN_FAILURE)) ||
+    ok( (!ret && ((GetLastError() == ERROR_GEN_FAILURE) || (GetLastError() == ERROR_ACCESS_DENIED))) ||
         (!ret && broken(GetLastError() == ERROR_INVALID_HANDLE)) || /* win2k */
         broken(ret),   /* 32bit application on NT 5.x 64bit */
-        "got %d with %u (expected FALSE with ERROR_GEN_FAILURE)\n",
+        "got %d with %u (expected FALSE with ERROR_GEN_FAILURE or ERROR_ACCESS_DENIED)\n",
         ret, GetLastError() );
 
     SetLastError(0xdeadbeef);
@@ -2042,6 +2042,7 @@ todo_wine
 
         case ThreadAffinityMask:
         case ThreadQuerySetWin32StartAddress:
+        case ThreadIsIoPending:
 todo_wine
             ok(status == STATUS_ACCESS_DENIED, "for info %u expected STATUS_ACCESS_DENIED, got %08x (ret_len %u)\n", i, status, ret_len);
             break;
index 860c061..6e3c751 100644 (file)
@@ -156,6 +156,9 @@ static void test_GetVersionEx(void)
     ok(ret ||
        broken(ret == 0), /* win95 */
        "Expected GetVersionExA to succeed\n");
+
+    if (!infoExA.wServicePackMajor && !infoExA.wServicePackMinor)
+        ok(!infoExA.szCSDVersion[0], "got '%s'\n", infoExA.szCSDVersion);
 }
 
 static void test_VerifyVersionInfo(void)
index b67c5e9..8824f32 100755 (executable)
@@ -4166,10 +4166,12 @@ START_TEST(virtual)
 #if defined(__i386__) || defined(__x86_64__)
     test_stack_commit();
 #endif
+#ifdef __i386__
     test_guard_page();
     /* The following tests should be executed as a last step, and in exactly this
      * order, since ATL thunk emulation cannot be enabled anymore on Windows. */
     test_atl_thunk_emulation( MEM_EXECUTE_OPTION_ENABLE );
     test_atl_thunk_emulation( MEM_EXECUTE_OPTION_DISABLE );
     test_atl_thunk_emulation( MEM_EXECUTE_OPTION_DISABLE | MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION );
+#endif
 }