From: Amine Khaldi Date: Sun, 4 Jun 2017 14:29:15 +0000 (+0000) Subject: [KERNEL32_WINETEST] Sync with Wine Staging 2.9. CORE-13362 X-Git-Tag: ReactOS-0.4.6~421 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=e7bfd194438612d863b6cce19546663aec7a5749 [KERNEL32_WINETEST] Sync with Wine Staging 2.9. CORE-13362 svn path=/trunk/; revision=74908 --- diff --git a/rostests/winetests/kernel32/actctx.c b/rostests/winetests/kernel32/actctx.c index 8120ddee3e0..e8a2cdfdc04 100644 --- a/rostests/winetests/kernel32/actctx.c +++ b/rostests/winetests/kernel32/actctx.c @@ -244,6 +244,61 @@ static const char manifest5[] = "" ""; +static const char manifest6[] = +"" +"" +"" +" " +" " +" " +" " +" " +"" +""; + +static const char manifest7[] = +"" +"" +"" +" " +" " +" " +" " +" " +"" +""; + +static const char manifest8[] = +"" +"" +"" +" " +" " +" " +" " +" " +" " +"" +""; + +static const char manifest9[] = +"" +"" +"" +" " +" " +" " +" " +" " +"" +"" +" " +" " +" " +" " +"" +""; + static const char testdep_manifest1[] = "" "" @@ -310,6 +365,38 @@ static const char wrong_manifest8[] = "" ""; +static const char wrong_manifest9[] = +"" +"" +"" +" " +" " +" " +" " +" " +" " +"" +""; + +static const char wrong_manifest10[] = +"" +"" +"" +" " +" " +" " +" " +" " +"" +"" +" " +" " +" " +" " +" " +"" +""; + static const char wrong_depmanifest1[] = "" "" @@ -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)) { diff --git a/rostests/winetests/kernel32/codepage.c b/rostests/winetests/kernel32/codepage.c index c98766ea4f2..ac8b90298b4 100755 --- a/rostests/winetests/kernel32/codepage.c +++ b/rostests/winetests/kernel32/codepage.c @@ -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) diff --git a/rostests/winetests/kernel32/console.c b/rostests/winetests/kernel32/console.c index c88db6acad0..a14bc450346 100755 --- a/rostests/winetests/kernel32/console.c +++ b/rostests/winetests/kernel32/console.c @@ -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); } diff --git a/rostests/winetests/kernel32/debugger.c b/rostests/winetests/kernel32/debugger.c index 3bab961fc2a..58f1f3c5dbb 100644 --- a/rostests/winetests/kernel32/debugger.c +++ b/rostests/winetests/kernel32/debugger.c @@ -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) diff --git a/rostests/winetests/kernel32/directory.c b/rostests/winetests/kernel32/directory.c index a3af05277ed..f57618e32fb 100755 --- a/rostests/winetests/kernel32/directory.c +++ b/rostests/winetests/kernel32/directory.c @@ -24,6 +24,28 @@ #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(); diff --git a/rostests/winetests/kernel32/file.c b/rostests/winetests/kernel32/file.c index 9b6377d3b6d..940e2fc27b7 100755 --- a/rostests/winetests/kernel32/file.c +++ b/rostests/winetests/kernel32/file.c @@ -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); diff --git a/rostests/winetests/kernel32/format_msg.c b/rostests/winetests/kernel32/format_msg.c index 4a1ae7d0429..1f88e2465b8 100755 --- a/rostests/winetests/kernel32/format_msg.c +++ b/rostests/winetests/kernel32/format_msg.c @@ -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(); } diff --git a/rostests/winetests/kernel32/heap.c b/rostests/winetests/kernel32/heap.c index d8ac787f70f..16d599e15d8 100755 --- a/rostests/winetests/kernel32/heap.c +++ b/rostests/winetests/kernel32/heap.c @@ -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"); diff --git a/rostests/winetests/kernel32/loader.c b/rostests/winetests/kernel32/loader.c index 0fd57cc0f64..9e5983430b4 100644 --- a/rostests/winetests/kernel32/loader.c +++ b/rostests/winetests/kernel32/loader.c @@ -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(); } diff --git a/rostests/winetests/kernel32/locale.c b/rostests/winetests/kernel32/locale.c index 70a3d24c9ed..5f0a83666c8 100755 --- a/rostests/winetests/kernel32/locale.c +++ b/rostests/winetests/kernel32/locale.c @@ -41,10 +41,12 @@ 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(); } diff --git a/rostests/winetests/kernel32/pipe.c b/rostests/winetests/kernel32/pipe.c index 434701bca9b..49c06436ef3 100755 --- a/rostests/winetests/kernel32/pipe.c +++ b/rostests/winetests/kernel32/pipe.c @@ -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); } diff --git a/rostests/winetests/kernel32/process.c b/rostests/winetests/kernel32/process.c index 77d21d8e9d0..e4553a35709 100755 --- a/rostests/winetests/kernel32/process.c +++ b/rostests/winetests/kernel32/process.c @@ -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 diff --git a/rostests/winetests/kernel32/thread.c b/rostests/winetests/kernel32/thread.c index cb3a67c1c62..28e35d4d819 100755 --- a/rostests/winetests/kernel32/thread.c +++ b/rostests/winetests/kernel32/thread.c @@ -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; diff --git a/rostests/winetests/kernel32/version.c b/rostests/winetests/kernel32/version.c index 860c0616a4e..6e3c7515162 100644 --- a/rostests/winetests/kernel32/version.c +++ b/rostests/winetests/kernel32/version.c @@ -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) diff --git a/rostests/winetests/kernel32/virtual.c b/rostests/winetests/kernel32/virtual.c index b67c5e967c0..8824f32992c 100755 --- a/rostests/winetests/kernel32/virtual.c +++ b/rostests/winetests/kernel32/virtual.c @@ -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 }