From 20d4a1d8992d662ed6bd0c80432add0e80ab6304 Mon Sep 17 00:00:00 2001 From: Gregor Schneider Date: Tue, 23 Dec 2008 20:02:47 +0000 Subject: [PATCH] - Update kernel32 winetest, thanks to Stefan100 for making this possible svn path=/trunk/; revision=38314 --- rostests/winetests/kernel32/actctx.c | 51 +- rostests/winetests/kernel32/atom.c | 2 +- rostests/winetests/kernel32/change.c | 23 +- rostests/winetests/kernel32/codepage.c | 149 ++++++ rostests/winetests/kernel32/comm.c | 2 +- rostests/winetests/kernel32/console.c | 45 ++ rostests/winetests/kernel32/debugger.c | 22 +- rostests/winetests/kernel32/environ.c | 11 +- rostests/winetests/kernel32/file.c | 229 +++++--- rostests/winetests/kernel32/format_msg.c | 4 +- rostests/winetests/kernel32/heap.c | 28 +- rostests/winetests/kernel32/loader.c | 108 +++- rostests/winetests/kernel32/locale.c | 630 +++++++++++++++-------- rostests/winetests/kernel32/mailslot.c | 93 ++-- rostests/winetests/kernel32/module.c | 120 ++++- rostests/winetests/kernel32/path.c | 8 + rostests/winetests/kernel32/pipe.c | 17 +- rostests/winetests/kernel32/process.c | 190 ++++++- rostests/winetests/kernel32/profile.c | 450 +++++++++++++++- rostests/winetests/kernel32/resource.c | 22 +- rostests/winetests/kernel32/sync.c | 594 ++++++++++++++++++++- rostests/winetests/kernel32/thread.c | 253 ++++++++- rostests/winetests/kernel32/timer.c | 8 +- rostests/winetests/kernel32/toolhelp.c | 16 +- rostests/winetests/kernel32/version.c | 12 +- rostests/winetests/kernel32/virtual.c | 550 ++++++++++++++++++-- rostests/winetests/kernel32/volume.c | 88 +++- 27 files changed, 3231 insertions(+), 494 deletions(-) diff --git a/rostests/winetests/kernel32/actctx.c b/rostests/winetests/kernel32/actctx.c index 4bc6135931f..1215ef587a0 100644 --- a/rostests/winetests/kernel32/actctx.c +++ b/rostests/winetests/kernel32/actctx.c @@ -17,7 +17,7 @@ */ #include "wine/test.h" -#include +#include #include #include #include @@ -223,7 +223,7 @@ static BOOL create_wide_manifest(const char *filename, const char *manifest, BOO BOOL ret; int offset = (fBOM ? 0 : 1); - MultiByteToWideChar(CP_ACP, 0, manifest, -1, &wmanifest[1], (strlen(manifest)+1) * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, manifest, -1, &wmanifest[1], (strlen(manifest)+1)); wmanifest[0] = 0xfeff; if (fReverse) { @@ -851,6 +851,42 @@ static void test_find_string_fail(void) ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetLastError()=%u\n", GetLastError()); } + +static void test_basic_info(HANDLE handle) +{ + ACTIVATION_CONTEXT_BASIC_INFORMATION basic; + SIZE_T size; + BOOL b; + + b = pQueryActCtxW(0, handle, NULL, + ActivationContextBasicInformation, &basic, + sizeof(basic), &size); + + ok (b,"ActivationContextBasicInformation failed\n"); + ok (size == sizeof(ACTIVATION_CONTEXT_BASIC_INFORMATION),"size mismatch\n"); + ok (basic.dwFlags == 0, "unexpected flags %x\n",basic.dwFlags); + ok (basic.hActCtx == handle, "unexpected handle\n"); + + b = pQueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, handle, NULL, + ActivationContextBasicInformation, &basic, + sizeof(basic), &size); + if (handle) + { + ok (!b,"ActivationContextBasicInformation succeeded\n"); + ok (size == 0,"size mismatch\n"); + ok (GetLastError() == ERROR_INVALID_PARAMETER, "Wrong last error\n"); + ok (basic.dwFlags == 0, "unexpected flags %x\n",basic.dwFlags); + ok (basic.hActCtx == handle, "unexpected handle\n"); + } + else + { + ok (b,"ActivationContextBasicInformation failed\n"); + ok (size == sizeof(ACTIVATION_CONTEXT_BASIC_INFORMATION),"size mismatch\n"); + ok (basic.dwFlags == 0, "unexpected flags %x\n",basic.dwFlags); + ok (basic.hActCtx == handle, "unexpected handle\n"); + } +} + static void test_actctx(void) { ULONG_PTR cookie; @@ -865,6 +901,7 @@ static void test_actctx(void) ok(handle == NULL, "handle = %p, expected NULL\n", handle); ok(b, "GetCurrentActCtx failed: %u\n", GetLastError()); if(b) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info0); pReleaseActCtx(handle); } @@ -879,6 +916,7 @@ static void test_actctx(void) handle = test_create("test1.manifest", manifest1); DeleteFileA("test1.manifest"); if(handle != INVALID_HANDLE_VALUE) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info1); test_info_in_assembly(handle, 1, &manifest1_info); @@ -904,6 +942,7 @@ static void test_actctx(void) DeleteFileA("test2.manifest"); DeleteFileA("testdep.manifest"); if(handle != INVALID_HANDLE_VALUE) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info2); test_info_in_assembly(handle, 1, &manifest2_info); test_info_in_assembly(handle, 2, &depmanifest1_info); @@ -921,6 +960,7 @@ static void test_actctx(void) DeleteFileA("test3.manifest"); DeleteFileA("testdep.manifest"); if(handle != INVALID_HANDLE_VALUE) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info2); test_info_in_assembly(handle, 1, &manifest2_info); test_info_in_assembly(handle, 2, &depmanifest2_info); @@ -948,6 +988,7 @@ static void test_actctx(void) DeleteFileA("test2-3.manifest"); DeleteFileA("testdep.manifest"); if(handle != INVALID_HANDLE_VALUE) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info2); test_info_in_assembly(handle, 1, &manifest2_info); test_info_in_assembly(handle, 2, &depmanifest3_info); @@ -976,6 +1017,7 @@ static void test_actctx(void) handle = test_create("test3.manifest", manifest3); DeleteFileA("test3.manifest"); if(handle != INVALID_HANDLE_VALUE) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info1); test_info_in_assembly(handle, 1, &manifest3_info); test_file_info(handle, 0, 0, testlib_dll); @@ -1002,6 +1044,7 @@ static void test_actctx(void) DeleteFileA("test4.manifest"); DeleteFileA("testdep.manifest"); if(handle != INVALID_HANDLE_VALUE) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info2); test_info_in_assembly(handle, 1, &manifest4_info); test_info_in_assembly(handle, 2, &manifest_comctrl_info); @@ -1020,6 +1063,7 @@ static void test_actctx(void) handle = test_create("..\\test1.manifest", manifest1); DeleteFileA("..\\test1.manifest"); if(handle != INVALID_HANDLE_VALUE) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info1); test_info_in_assembly(handle, 1, &manifest1_info); pReleaseActCtx(handle); @@ -1039,6 +1083,7 @@ static void test_actctx(void) handle = test_create("test1.manifest", manifest1); DeleteFileA("test1.manifest"); if (handle != INVALID_HANDLE_VALUE) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info1); test_info_in_assembly(handle, 1, &manifest1_info); pReleaseActCtx(handle); @@ -1053,6 +1098,7 @@ static void test_actctx(void) handle = test_create("test1.manifest", manifest1); DeleteFileA("test1.manifest"); if (handle != INVALID_HANDLE_VALUE) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info1); test_info_in_assembly(handle, 1, &manifest1_info); pReleaseActCtx(handle); @@ -1071,6 +1117,7 @@ static void test_app_manifest(void) ok(handle == NULL, "handle != NULL\n"); ok(b, "GetCurrentActCtx failed: %u\n", GetLastError()); if(b) { + test_basic_info(handle); test_detailed_info(handle, &detailed_info1_child); test_info_in_assembly(handle, 1, &manifest1_child_info); pReleaseActCtx(handle); diff --git a/rostests/winetests/kernel32/atom.c b/rostests/winetests/kernel32/atom.c index fcf60e2765d..9601fd616c9 100755 --- a/rostests/winetests/kernel32/atom.c +++ b/rostests/winetests/kernel32/atom.c @@ -304,7 +304,7 @@ static void test_get_atom_name(void) do_initW(inW, "abcdefghij", 255); atom = GlobalAddAtomW(inW); ok(atom, "couldn't add atom for %s\n", in); - len = GlobalGetAtomNameW(atom, outW, sizeof(outW)); + len = GlobalGetAtomNameW(atom, outW, sizeof(outW)/sizeof(outW[0])); ok(len == 255, "length mismatch (%u instead of 255)\n", len); for (i = 0; i < 255; i++) { diff --git a/rostests/winetests/kernel32/change.c b/rostests/winetests/kernel32/change.c index cdba120e95d..cb500ef4076 100755 --- a/rostests/winetests/kernel32/change.c +++ b/rostests/winetests/kernel32/change.c @@ -223,6 +223,7 @@ static void test_FindFirstChangeNotification(void) file = CreateFileA(filename2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); ok(file != INVALID_HANDLE_VALUE, "CreateFileA error: %d\n", GetLastError()); + memset(buffer, 0, sizeof(buffer)); ret = WriteFile(file, buffer, sizeof(buffer), &count, NULL); ok(ret && count == sizeof(buffer), "WriteFile error: %d\n", GetLastError()); ret = CloseHandle(file); @@ -559,8 +560,8 @@ static void test_readdirectorychanges(void) pfni = (PFILE_NOTIFY_INFORMATION) buffer; ok( pfni->NextEntryOffset == 0, "offset wrong\n" ); ok( pfni->Action == FILE_ACTION_ADDED, "action wrong\n" ); - ok( pfni->FileNameLength == 0x0c, "len wrong\n" ); - ok( !memcmp(pfni->FileName,&szGa[1],6), "name wrong\n" ); + ok( pfni->FileNameLength == 6*sizeof(WCHAR), "len wrong\n" ); + ok( !memcmp(pfni->FileName,&szGa[1],6*sizeof(WCHAR)), "name wrong\n" ); r = RemoveDirectoryW( subsubdir ); ok( r == TRUE, "failed to remove directory\n"); @@ -577,13 +578,21 @@ static void test_readdirectorychanges(void) ok( r == WAIT_OBJECT_0, "should be ready\n" ); pfni = (PFILE_NOTIFY_INFORMATION) buffer; - ok( pfni->NextEntryOffset == 0, "offset wrong\n" ); - ok( pfni->Action == FILE_ACTION_REMOVED, "action wrong\n" ); - ok( pfni->FileNameLength == 0x0c, "len wrong\n" ); - ok( !memcmp(pfni->FileName,&szGa[1],6), "name wrong\n" ); + /* we may get a notification for the parent dir too */ + if (pfni->Action == FILE_ACTION_MODIFIED && pfni->NextEntryOffset) + { + ok( pfni->FileNameLength == 3*sizeof(WCHAR), "len wrong %u\n", pfni->FileNameLength ); + ok( !memcmp(pfni->FileName,&szGa[1],3*sizeof(WCHAR)), "name wrong\n" ); + pfni = (PFILE_NOTIFY_INFORMATION)((char *)pfni + pfni->NextEntryOffset); + } + ok( pfni->NextEntryOffset == 0, "offset wrong %u\n", pfni->NextEntryOffset ); + ok( pfni->Action == FILE_ACTION_REMOVED, "action wrong %u\n", pfni->Action ); + ok( pfni->FileNameLength == 6*sizeof(WCHAR), "len wrong %u\n", pfni->FileNameLength ); + ok( !memcmp(pfni->FileName,&szGa[1],6*sizeof(WCHAR)), "name wrong\n" ); ok( ov.Internal == STATUS_SUCCESS, "ov.Internal wrong\n"); - ok( ov.InternalHigh == 0x18, "ov.InternalHigh wrong\n"); + dwCount = (char *)&pfni->FileName[pfni->FileNameLength/sizeof(WCHAR)] - buffer; + ok( ov.InternalHigh == dwCount, "ov.InternalHigh wrong %lu/%u\n",ov.InternalHigh, dwCount ); CloseHandle(hdir); diff --git a/rostests/winetests/kernel32/codepage.c b/rostests/winetests/kernel32/codepage.c index e8908f75c45..8dc6af949ed 100755 --- a/rostests/winetests/kernel32/codepage.c +++ b/rostests/winetests/kernel32/codepage.c @@ -2,6 +2,7 @@ * Unit tests for code page to/from unicode translations * * Copyright (c) 2002 Dmitry Timoshkov + * Copyright (c) 2008 Colin Finck * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -203,17 +204,165 @@ static void test_overlapped_buffers(void) char buf[256]; int ret; + SetLastError(0xdeadbeef); memcpy((WCHAR *)(buf + 1), strW, sizeof(strW)); ret = WideCharToMultiByte(CP_ACP, 0, (WCHAR *)(buf + 1), -1, buf, sizeof(buf), NULL, NULL); ok(ret == sizeof(strA), "unexpected ret %d\n", ret); ok(!memcmp(buf, strA, sizeof(strA)), "conversion failed: %s\n", buf); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); +} + +static void test_string_conversion(LPBOOL bUsedDefaultChar) +{ + char mbc; + char mbs[5]; + int ret; + WCHAR wc1 = 228; /* Western Windows-1252 character */ + WCHAR wc2 = 1088; /* Russian Windows-1251 character not displayable for Windows-1252 */ + WCHAR wcs[5] = {'T', 'h', 1088, 'i', 0}; /* String with ASCII characters and a Russian character */ + WCHAR dbwcs[3] = {28953, 25152, 0}; /* String with Chinese (codepage 950) characters */ + + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1252, 0, &wc1, 1, &mbc, 1, NULL, bUsedDefaultChar); + ok(ret == 1, "ret is %d\n", ret); + ok(mbc == -28, "mbc is %d\n", mbc); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1252, 0, &wc2, 1, &mbc, 1, NULL, bUsedDefaultChar); + ok(ret == 1, "ret is %d\n", ret); + ok(mbc == 63, "mbc is %d\n", mbc); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + + if (IsValidCodePage(1251)) + { + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1251, 0, &wc2, 1, &mbc, 1, NULL, bUsedDefaultChar); + ok(ret == 1, "ret is %d\n", ret); + ok(mbc == -16, "mbc is %d\n", mbc); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef || + broken(GetLastError() == 0), /* win95 */ + "GetLastError() is %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1251, 0, &wc1, 1, &mbc, 1, NULL, bUsedDefaultChar); + ok(ret == 1, "ret is %d\n", ret); + ok(mbc == 97, "mbc is %d\n", mbc); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + } + else + skip("Codepage 1251 not available\n"); + + /* This call triggers the last Win32 error */ + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1252, 0, wcs, -1, &mbc, 1, NULL, bUsedDefaultChar); + ok(ret == 0, "ret is %d\n", ret); + ok(mbc == 84, "mbc is %d\n", mbc); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetLastError() is %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1252, 0, wcs, -1, mbs, sizeof(mbs), NULL, bUsedDefaultChar); + ok(ret == 5, "ret is %d\n", ret); + ok(!strcmp(mbs, "Th?i"), "mbs is %s\n", mbs); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + mbs[0] = 0; + + /* WideCharToMultiByte mustn't add any null character automatically. + So in this case, we should get the same string again, even if we only copied the first three bytes. */ + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1252, 0, wcs, 3, mbs, sizeof(mbs), NULL, bUsedDefaultChar); + ok(ret == 3, "ret is %d\n", ret); + ok(!strcmp(mbs, "Th?i"), "mbs is %s\n", mbs); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + ZeroMemory(mbs, 5); + + /* Now this shouldn't be the case like above as we zeroed the complete string buffer. */ + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1252, 0, wcs, 3, mbs, sizeof(mbs), NULL, bUsedDefaultChar); + ok(ret == 3, "ret is %d\n", ret); + ok(!strcmp(mbs, "Th?"), "mbs is %s\n", mbs); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + + /* Double-byte tests */ + ret = WideCharToMultiByte(1252, 0, dbwcs, 3, mbs, sizeof(mbs), NULL, bUsedDefaultChar); + ok(ret == 3, "ret is %d\n", ret); + ok(!strcmp(mbs, "??"), "mbs is %s\n", mbs); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + + /* Length-only tests */ + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1252, 0, &wc2, 1, NULL, 0, NULL, bUsedDefaultChar); + ok(ret == 1, "ret is %d\n", ret); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(1252, 0, wcs, -1, NULL, 0, NULL, bUsedDefaultChar); + ok(ret == 5, "ret is %d\n", ret); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == TRUE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + + if (!IsValidCodePage(950)) + { + skip("Codepage 950 not available\n"); + return; + } + + /* Double-byte tests */ + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(950, 0, dbwcs, -1, mbs, sizeof(mbs), NULL, bUsedDefaultChar); + ok(ret == 5, "ret is %d\n", ret); + ok(!strcmp(mbs, "µH©Ò"), "mbs is %s\n", mbs); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(950, 0, dbwcs, 1, &mbc, 1, NULL, bUsedDefaultChar); + ok(ret == 0, "ret is %d\n", ret); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetLastError() is %u\n", GetLastError()); + ZeroMemory(mbs, 5); + + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(950, 0, dbwcs, 1, mbs, sizeof(mbs), NULL, bUsedDefaultChar); + ok(ret == 2, "ret is %d\n", ret); + ok(!strcmp(mbs, "µH"), "mbs is %s\n", mbs); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + + /* Length-only tests */ + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(950, 0, dbwcs, 1, NULL, 0, NULL, bUsedDefaultChar); + ok(ret == 2, "ret is %d\n", ret); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = WideCharToMultiByte(950, 0, dbwcs, -1, NULL, 0, NULL, bUsedDefaultChar); + ok(ret == 5, "ret is %d\n", ret); + if(bUsedDefaultChar) ok(*bUsedDefaultChar == FALSE, "bUsedDefaultChar is %d\n", *bUsedDefaultChar); + ok(GetLastError() == 0xdeadbeef, "GetLastError() is %u\n", GetLastError()); } START_TEST(codepage) { + BOOL bUsedDefaultChar; + test_destination_buffer(); test_null_source(); test_negative_source_length(); test_negative_dest_length(); test_overlapped_buffers(); + + /* WideCharToMultiByte has two code paths, test both here */ + test_string_conversion(NULL); + test_string_conversion(&bUsedDefaultChar); } diff --git a/rostests/winetests/kernel32/comm.c b/rostests/winetests/kernel32/comm.c index 36e46ad5c60..3c73eb54355 100755 --- a/rostests/winetests/kernel32/comm.c +++ b/rostests/winetests/kernel32/comm.c @@ -27,7 +27,7 @@ #define TIMEOUT 1000 /* one second for Timeouts*/ #define SLOWBAUD 150 #define FASTBAUD 115200 -#define TIMEDELTA 100 /* 100 ms uncertainty allowed */ +#define TIMEDELTA 150 /* 150 ms uncertainty allowed */ /* Define the appropriate LOOPBACK(s) TRUE if you have a Loopback cable with * the mentioned shorts connected to your Serial port diff --git a/rostests/winetests/kernel32/console.c b/rostests/winetests/kernel32/console.c index aacae9cb23c..6eed56bd07f 100755 --- a/rostests/winetests/kernel32/console.c +++ b/rostests/winetests/kernel32/console.c @@ -130,6 +130,49 @@ static void testCursor(HANDLE hCon, COORD sbSize) ERROR_INVALID_PARAMETER, GetLastError()); } +static void testCursorInfo(HANDLE hCon) +{ + BOOL ret; + CONSOLE_CURSOR_INFO info; + + SetLastError(0xdeadbeef); + ret = GetConsoleCursorInfo(NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n", + ERROR_INVALID_HANDLE, GetLastError()); + + SetLastError(0xdeadbeef); + info.dwSize = -1; + ret = GetConsoleCursorInfo(NULL, &info); + ok(!ret, "Expected failure\n"); + ok(info.dwSize == -1, "Expected no change for dwSize\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError: expecting %u got %u\n", + ERROR_INVALID_HANDLE, GetLastError()); + + /* Test the correct call first to distinguish between win9x and the rest */ + SetLastError(0xdeadbeef); + ret = GetConsoleCursorInfo(hCon, &info); + ok(ret, "Expected success\n"); + ok(info.dwSize == 25 || + info.dwSize == 12 /* win9x */, + "Expected 12 or 25, got %d\n", info.dwSize); + ok(info.bVisible, "Expected the cursor to be visible\n"); + ok(GetLastError() == 0xdeadbeef, "GetLastError: expecting %u got %u\n", + 0xdeadbeef, GetLastError()); + + if (info.dwSize == 12) + { + skip("NULL CONSOLE_CURSOR_INFO will crash on win9x\n"); + return; + } + + SetLastError(0xdeadbeef); + ret = GetConsoleCursorInfo(hCon, NULL); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_INVALID_ACCESS, "GetLastError: expecting %u got %u\n", + ERROR_INVALID_ACCESS, GetLastError()); +} + static void testWriteSimple(HANDLE hCon, COORD sbSize) { COORD c; @@ -863,6 +906,8 @@ START_TEST(console) /* Non interactive tests */ testCursor(hConOut, sbi.dwSize); + /* test parameters (FIXME: test functionality) */ + testCursorInfo(hConOut); /* will test wrapped (on/off) & processed (on/off) strings output */ testWrite(hConOut, sbi.dwSize); /* will test line scrolling at the bottom of the screen */ diff --git a/rostests/winetests/kernel32/debugger.c b/rostests/winetests/kernel32/debugger.c index c44eb18b5a0..1a5072c25d6 100644 --- a/rostests/winetests/kernel32/debugger.c +++ b/rostests/winetests/kernel32/debugger.c @@ -20,6 +20,8 @@ #include #include + +#define WIN32_NO_STATUS #include #include #include @@ -137,6 +139,7 @@ static void doDebugger(int argc, char** argv) logfile=(argc >= 4 ? argv[3] : NULL); blackbox.pid=(argc >= 5 ? atol(argv[4]) : 0); + blackbox.attach_err=0; if (strstr(myARGV[2], "attach")) { blackbox.attach_rc=DebugActiveProcess(blackbox.pid); @@ -147,6 +150,7 @@ static void doDebugger(int argc, char** argv) blackbox.attach_rc=TRUE; debug_event=(argc >= 6 ? (HANDLE)atol(argv[5]) : NULL); + blackbox.debug_err=0; if (debug_event && strstr(myARGV[2], "event")) { blackbox.debug_rc=SetEvent(debug_event); @@ -156,13 +160,18 @@ static void doDebugger(int argc, char** argv) else blackbox.debug_rc=TRUE; - get_events(logfile, &start_event, &done_event); + if (logfile) + { + get_events(logfile, &start_event, &done_event); + } + if (strstr(myARGV[2], "order")) { trace("debugger: waiting for the start signal...\n"); WaitForSingleObject(start_event, INFINITE); } + blackbox.nokill_err=0; if (strstr(myARGV[2], "nokill")) { blackbox.nokill_rc=pDebugSetProcessKillOnExit(FALSE); @@ -172,6 +181,7 @@ static void doDebugger(int argc, char** argv) else blackbox.nokill_rc=TRUE; + blackbox.detach_err=0; if (strstr(myARGV[2], "detach")) { blackbox.detach_rc=pDebugActiveProcessStop(blackbox.pid); @@ -181,7 +191,10 @@ static void doDebugger(int argc, char** argv) else blackbox.detach_rc=TRUE; - save_blackbox(logfile, &blackbox, sizeof(blackbox)); + if (logfile) + { + save_blackbox(logfile, &blackbox, sizeof(blackbox)); + } trace("debugger: done debugging...\n"); SetEvent(done_event); @@ -241,7 +254,9 @@ static void crash_and_debug(HKEY hkey, const char* argv0, const char* dbgtasks) "wrong exit code : %08x\n", exit_code); } else - ok(exit_code == STATUS_ACCESS_VIOLATION, "exit code = %08x instead of STATUS_ACCESS_VIOLATION\n", exit_code); + ok(exit_code == STATUS_ACCESS_VIOLATION || + exit_code == WAIT_ABANDONED, /* win2k3 */ + "exit code = %08x instead of STATUS_ACCESS_VIOLATION or WAIT_ABANDONED\n", exit_code); CloseHandle(info.hProcess); /* ...before the debugger */ @@ -333,6 +348,7 @@ static void test_ExitCode(void) { debugger_val=HeapAlloc(GetProcessHeap(), 0, debugger_size); RegQueryValueExA(hkey, "debugger", NULL, &debugger_type, debugger_val, &debugger_size); + trace("HKLM\\%s\\debugger is set to '%s'\n", AeDebug, debugger_val); } } else if (ret == ERROR_ACCESS_DENIED) diff --git a/rostests/winetests/kernel32/environ.c b/rostests/winetests/kernel32/environ.c index e6dd1fca5d3..70549e30240 100755 --- a/rostests/winetests/kernel32/environ.c +++ b/rostests/winetests/kernel32/environ.c @@ -24,6 +24,13 @@ #include "windef.h" #include "winbase.h" #include "winerror.h" +#include "winnls.h" + +static CHAR string[MAX_PATH]; +#define ok_w(res, format, szString) \ +\ + WideCharToMultiByte(CP_ACP, 0, szString, -1, string, MAX_PATH, NULL, NULL); \ + ok(res, format, string); static BOOL (WINAPI *pGetComputerNameExA)(COMPUTER_NAME_FORMAT,LPSTR,LPDWORD); static BOOL (WINAPI *pGetComputerNameExW)(COMPUTER_NAME_FORMAT,LPWSTR,LPDWORD); @@ -156,7 +163,9 @@ static void test_GetSetEnvironmentVariableW(void) lstrcpyW(buf, fooW); ret_size = GetEnvironmentVariableW(name, buf, lstrlenW(value)); - ok(lstrcmpW(buf, fooW) == 0, "should not touch the buffer\n"); + ok_w(lstrcmpW(buf, fooW) == 0 || + lstrlenW(buf) == 0, /* Vista */ + "Expected untouched or empty buffer, got \"%s\"\n", buf); ok(ret_size == lstrlenW(value) + 1, "should return length with terminating 0 ret_size=%d\n", ret_size); diff --git a/rostests/winetests/kernel32/file.c b/rostests/winetests/kernel32/file.c index f73f1046e49..2239558f677 100755 --- a/rostests/winetests/kernel32/file.c +++ b/rostests/winetests/kernel32/file.c @@ -2,6 +2,7 @@ * Unit tests for file functions in Wine * * Copyright (c) 2002, 2004 Jakob Eriksson + * Copyright (c) 2008 Jeff Zaroyko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,9 +24,6 @@ #include #include -/* ReplaceFile requires Windows 2000 or newer */ -#define _WIN32_WINNT 0x0500 - #include "wine/test.h" #include "windef.h" #include "winbase.h" @@ -777,6 +775,16 @@ static void test_CreateFileW(void) OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ok(hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND, "CreateFileW on invalid VxD name returned ret=%p error=%d\n",hFile,GetLastError()); + + ret = CreateDirectoryW(filename, NULL); + ok(ret == TRUE, "couldn't create temporary directory\n"); + hFile = CreateFileW(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL); + ok(hFile != INVALID_HANDLE_VALUE, + "expected CreateFile to succeed on existing directory, error: %d\n", GetLastError()); + CloseHandle(hFile); + ret = RemoveDirectoryW(filename); + ok(ret, "DeleteFileW: error %d\n", GetLastError()); } static void test_GetTempFileNameA(void) @@ -841,6 +849,10 @@ static void test_DeleteFileA( void ) static void test_DeleteFileW( void ) { BOOL ret; + WCHAR pathW[MAX_PATH]; + WCHAR pathsubW[MAX_PATH]; + static const WCHAR dirW[] = {'d','e','l','e','t','e','f','i','l','e',0}; + static const WCHAR subdirW[] = {'\\','s','u','b',0}; static const WCHAR emptyW[]={'\0'}; ret = DeleteFileW(NULL); @@ -852,6 +864,35 @@ static void test_DeleteFileW( void ) ret = DeleteFileW(emptyW); ok(!ret && GetLastError() == ERROR_PATH_NOT_FOUND, "DeleteFileW(\"\") returned ret=%d error=%d\n",ret,GetLastError()); + + /* test DeleteFile on empty directory */ + ret = GetTempPathW(MAX_PATH, pathW); + if (ret + sizeof(dirW)/sizeof(WCHAR)-1 + sizeof(subdirW)/sizeof(WCHAR)-1 >= MAX_PATH) + { + ok(0, "MAX_PATH exceeded in constructing paths\n"); + return; + } + lstrcatW(pathW, dirW); + lstrcpyW(pathsubW, pathW); + lstrcatW(pathsubW, subdirW); + ret = CreateDirectoryW(pathW, NULL); + ok(ret == TRUE, "couldn't create directory deletefile\n"); + ret = DeleteFileW(pathW); + ok(ret == FALSE, "DeleteFile should fail for empty directories\n"); + ret = RemoveDirectoryW(pathW); + ok(ret == TRUE, "expected to remove directory deletefile\n"); + + /* test DeleteFile on non-empty directory */ + ret = CreateDirectoryW(pathW, NULL); + ok(ret == TRUE, "couldn't create directory deletefile\n"); + ret = CreateDirectoryW(pathsubW, NULL); + ok(ret == TRUE, "couldn't create directory deletefile\\sub\n"); + ret = DeleteFileW(pathW); + ok(ret == FALSE, "DeleteFile should fail for non-empty directories\n"); + ret = RemoveDirectoryW(pathsubW); + ok(ret == TRUE, "expected to remove directory deletefile\\sub\n"); + ret = RemoveDirectoryW(pathW); + ok(ret == TRUE, "expected to remove directory deletefile\n"); } #define IsDotDir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0)))) @@ -1038,6 +1079,7 @@ static void test_LockFile(void) OVERLAPPED overlapped; int limited_LockFile; int limited_UnLockFile; + BOOL ret; handle = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, @@ -1097,10 +1139,15 @@ static void test_LockFile(void) "UnlockFileEx 150,100 again succeeded\n" ); } - ok( LockFile( handle, 0, 0x10000000, 0, 0xf0000000 ), "LockFile failed\n" ); - ok( !LockFile( handle, ~0, ~0, 1, 0 ), "LockFile ~0,1 succeeded\n" ); - ok( !LockFile( handle, 0, 0x20000000, 20, 0 ), "LockFile 0x20000000,20 succeeded\n" ); - ok( UnlockFile( handle, 0, 0x10000000, 0, 0xf0000000 ), "UnlockFile failed\n" ); + ret = LockFile( handle, 0, 0x10000000, 0, 0xf0000000 ); + if (ret) + { + ok( !LockFile( handle, ~0, ~0, 1, 0 ), "LockFile ~0,1 succeeded\n" ); + ok( !LockFile( handle, 0, 0x20000000, 20, 0 ), "LockFile 0x20000000,20 succeeded\n" ); + ok( UnlockFile( handle, 0, 0x10000000, 0, 0xf0000000 ), "UnlockFile failed\n" ); + } + else /* win9x */ + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong LockFile error %u\n", GetLastError() ); /* wrap-around lock should not do anything */ /* (but still succeeds on NT4 so we don't check result) */ @@ -1351,9 +1398,14 @@ static void test_FindFirstFileA(void) err = GetLastError(); ok( handle != INVALID_HANDLE_VALUE, "FindFirstFile on %s failed\n", buffer2 ); ok( 0 == lstrcmpiA(data.cFileName, "nul"), "wrong name %s\n", data.cFileName ); - ok( 0 == data.nFileSizeHigh, "wrong size %d\n", data.nFileSizeHigh ); - ok( 0 == data.nFileSizeLow, "wrong size %d\n", data.nFileSizeLow ); - ok( FILE_ATTRIBUTE_ARCHIVE == data.dwFileAttributes, "wrong attributes %x\n", data.dwFileAttributes ); + ok( FILE_ATTRIBUTE_ARCHIVE == data.dwFileAttributes || + FILE_ATTRIBUTE_DEVICE == data.dwFileAttributes /* Win9x */, + "wrong attributes %x\n", data.dwFileAttributes ); + if (data.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE) + { + ok( 0 == data.nFileSizeHigh, "wrong size %d\n", data.nFileSizeHigh ); + ok( 0 == data.nFileSizeLow, "wrong size %d\n", data.nFileSizeLow ); + } SetLastError( 0xdeadbeaf ); ok( !FindNextFileA( handle, &data ), "FindNextFileA succeeded\n" ); ok( GetLastError() == ERROR_NO_MORE_FILES, "bad error %d\n", GetLastError() ); @@ -1366,9 +1418,14 @@ static void test_FindFirstFileA(void) err = GetLastError(); ok( handle != INVALID_HANDLE_VALUE, "FindFirstFile on %s failed\n", buffer2 ); ok( 0 == lstrcmpiA(data.cFileName, "lpt1"), "wrong name %s\n", data.cFileName ); - ok( 0 == data.nFileSizeHigh, "wrong size %d\n", data.nFileSizeHigh ); - ok( 0 == data.nFileSizeLow, "wrong size %d\n", data.nFileSizeLow ); - ok( FILE_ATTRIBUTE_ARCHIVE == data.dwFileAttributes, "wrong attributes %x\n", data.dwFileAttributes ); + ok( FILE_ATTRIBUTE_ARCHIVE == data.dwFileAttributes || + FILE_ATTRIBUTE_DEVICE == data.dwFileAttributes /* Win9x */, + "wrong attributes %x\n", data.dwFileAttributes ); + if (data.dwFileAttributes == FILE_ATTRIBUTE_ARCHIVE) + { + ok( 0 == data.nFileSizeHigh, "wrong size %d\n", data.nFileSizeHigh ); + ok( 0 == data.nFileSizeLow, "wrong size %d\n", data.nFileSizeLow ); + } SetLastError( 0xdeadbeaf ); ok( !FindNextFileA( handle, &data ), "FindNextFileA succeeded\n" ); ok( GetLastError() == ERROR_NO_MORE_FILES, "bad error %d\n", GetLastError() ); @@ -1446,7 +1503,13 @@ static void test_FindFirstFileExA(void) _lclose(_lcreat("test-dir\\file2", 0)); CreateDirectoryA("test-dir\\dir1", NULL); /* FindExLimitToDirectories is ignored */ + SetLastError(0xdeadbeef); handle = pFindFirstFileExA("test-dir\\*", FindExInfoStandard, &search_results, FindExSearchLimitToDirectories, NULL, 0); + if (handle == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + skip("FindFirstFileExA is not implemented\n"); + goto cleanup; + } ok(handle != INVALID_HANDLE_VALUE, "FindFirstFile failed (err=%u)\n", GetLastError()); ok(strcmp(search_results.cFileName, ".") == 0, "First entry should be '.', is %s\n", search_results.cFileName); @@ -1456,7 +1519,7 @@ static void test_FindFirstFileExA(void) ok(strcmp(search_results.cFileName, "..") == 0, "Second entry should be '..' is %s\n", search_results.cFileName); ok(FindNextFile(handle, &search_results), "Fetching third file failed\n"); - ok(CHECK_NAME(search_results.cFileName), "Invalid thrid entry - %s\n", search_results.cFileName); + ok(CHECK_NAME(search_results.cFileName), "Invalid third entry - %s\n", search_results.cFileName); ok(FindNextFile(handle, &search_results), "Fetching fourth file failed\n"); ok(CHECK_NAME(search_results.cFileName), "Invalid fourth entry - %s\n", search_results.cFileName); @@ -1467,6 +1530,10 @@ static void test_FindFirstFileExA(void) #undef CHECK_NAME ok(FindNextFile(handle, &search_results) == FALSE, "Fetching sixth file should failed\n"); + + FindClose( handle ); + +cleanup: DeleteFileA("test-dir\\file1"); DeleteFileA("test-dir\\file2"); RemoveDirectoryA("test-dir\\dir1"); @@ -1514,12 +1581,16 @@ static void test_MapFile(void) ok( GetLastError() == ERROR_FILE_INVALID, "not ERROR_FILE_INVALID\n"); hmap = CreateFileMapping( handle, NULL, PAGE_READWRITE, 0x80000000, 0, NULL ); - ok( hmap == NULL, "mapping should fail\n"); + ok( hmap == NULL || broken(hmap != NULL) /* NT4 */, "mapping should fail\n"); /* GetLastError() varies between win9x and WinNT and also depends on the filesystem */ + if ( hmap ) + CloseHandle( hmap ); hmap = CreateFileMapping( handle, NULL, PAGE_READWRITE, 0x80000000, 0x10000, NULL ); - ok( hmap == NULL, "mapping should fail\n"); + ok( hmap == NULL || broken(hmap != NULL) /* NT4 */, "mapping should fail\n"); /* GetLastError() varies between win9x and WinNT and also depends on the filesystem */ + if ( hmap ) + CloseHandle( hmap ); /* On XP you can now map again, on Win 95 you cannot. */ @@ -1566,18 +1637,25 @@ static void test_async_file_errors(void) szFile[0] = '\0'; GetWindowsDirectoryA(szFile, sizeof(szFile)/sizeof(szFile[0])-1-strlen("\\win.ini")); strcat(szFile, "\\win.ini"); - hFile = CreateFileA(szFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED, NULL); - ok(hFile != NULL, "CreateFileA(%s ...) failed\n", szFile); + hFile = CreateFileA(szFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED, NULL); + if (hFile == INVALID_HANDLE_VALUE) /* win9x doesn't like FILE_SHARE_DELETE */ + hFile = CreateFileA(szFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED, NULL); + ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA(%s ...) failed\n", szFile); while (TRUE) { BOOL res; + DWORD count; while (WaitForSingleObjectEx(hSem, INFINITE, TRUE) == WAIT_IO_COMPLETION) ; res = ReadFileEx(hFile, lpBuffer, 4096, &ovl, FileIOComplete); /*printf("Offset = %ld, result = %s\n", ovl.Offset, res ? "TRUE" : "FALSE");*/ if (!res) break; - S(U(ovl)).Offset += 4096; + if (!GetOverlappedResult(hFile, &ovl, &count, FALSE)) + break; + S(U(ovl)).Offset += count; /* i/o completion routine only called if ReadFileEx returned success. * we only care about violations of this rule so undo what should have * been done */ @@ -1585,6 +1663,7 @@ static void test_async_file_errors(void) } ok(completion_count == 0, "completion routine should only be called when ReadFileEx succeeds (this rule was violated %d times)\n", completion_count); /*printf("Error = %ld\n", GetLastError());*/ + HeapFree(GetProcessHeap(), 0, lpBuffer); } static void test_read_write(void) @@ -1655,26 +1734,28 @@ static void test_OpenFile(void) BOOL ret; DWORD retval; - static const char *file = "\\regsvr32.exe"; - static const char *foo = ".\\foo-bar-foo.baz"; + static const char file[] = "regedit.exe"; + static const char foo[] = ".\\foo-bar-foo.baz"; static const char *foo_too_long = ".\\foo-bar-foo.baz+++++++++++++++" "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"; - static const char *backslash = "\\"; char buff[MAX_PATH]; char buff_long[4*MAX_PATH]; char filled_0xA5[OFS_MAXPATHNAME]; + char *p; UINT length; /* Check for existing file */ - length = GetSystemDirectoryA(buff, MAX_PATH); + length = GetWindowsDirectoryA(buff, MAX_PATH); - if (length + lstrlen(file) < MAX_PATH) + if (length + sizeof(file) < MAX_PATH) { - lstrcatA(buff, file); + p = buff + strlen(buff); + if (p > buff && p[-1] != '\\') *p++ = '\\'; + strcpy( p, file ); memset(&ofs, 0xA5, sizeof(ofs)); SetLastError(0xfaceabee); @@ -1693,9 +1774,11 @@ static void test_OpenFile(void) length = GetCurrentDirectoryA(MAX_PATH, buff); /* Check for nonexistent file */ - if (length + lstrlenA(foo + 1) < MAX_PATH) + if (length + sizeof(foo) < MAX_PATH) { - lstrcatA(buff, foo + 1); /* Avoid '.' during concatenation */ + p = buff + strlen(buff); + if (p > buff && p[-1] != '\\') *p++ = '\\'; + strcpy( p, foo + 2 ); memset(&ofs, 0xA5, sizeof(ofs)); SetLastError(0xfaceabee); @@ -1733,17 +1816,16 @@ static void test_OpenFile(void) ofs.szPathName ); } - length = GetCurrentDirectoryA(MAX_PATH, buff); - length += lstrlenA(backslash); - length += lstrlenA(filename); + length = GetCurrentDirectoryA(MAX_PATH, buff) + sizeof(filename); if (length >= MAX_PATH) { trace("Buffer too small, requested length = %d, but MAX_PATH = %d. Skipping test.\n", length, MAX_PATH); return; } - lstrcatA(buff, backslash); - lstrcatA(buff, filename); + p = buff + strlen(buff); + if (p > buff && p[-1] != '\\') *p++ = '\\'; + strcpy( p, filename ); memset(&ofs, 0xA5, sizeof(ofs)); SetLastError(0xfaceabee); @@ -1753,7 +1835,8 @@ static void test_OpenFile(void) ok( GetLastError() == 0xfaceabee || GetLastError() == ERROR_SUCCESS, "GetLastError() returns %d\n", GetLastError() ); ok( ofs.cBytes == sizeof(OFSTRUCT), "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); - ok( ofs.nErrCode == ERROR_SUCCESS, "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); + ok( ofs.nErrCode == ERROR_SUCCESS || broken(ofs.nErrCode != ERROR_SUCCESS) /* win9x */, + "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); ret = CloseHandle((HANDLE)hFile); ok( ret == TRUE, "CloseHandle() returns %d\n", ret ); retval = GetFileAttributesA(filename); @@ -1768,7 +1851,8 @@ static void test_OpenFile(void) ok( GetLastError() == 0xfaceabee || GetLastError() == ERROR_SUCCESS, "GetLastError() returns %d\n", GetLastError() ); ok( ofs.cBytes == sizeof(OFSTRUCT), "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); - ok( ofs.nErrCode == ERROR_SUCCESS, "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); + ok( ofs.nErrCode == ERROR_SUCCESS || broken(ofs.nErrCode != ERROR_SUCCESS) /* win9x */, + "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); ok( lstrcmpiA(ofs.szPathName, buff) == 0, "OpenFile returned '%s', but was expected to return '%s'\n", ofs.szPathName, buff ); ret = CloseHandle((HANDLE)hFile); @@ -1782,7 +1866,8 @@ static void test_OpenFile(void) ok( GetLastError() == 0xfaceabee || GetLastError() == ERROR_SUCCESS, "GetLastError() returns %d\n", GetLastError() ); ok( ofs.cBytes == sizeof(OFSTRUCT), "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); - ok( ofs.nErrCode == ERROR_SUCCESS, "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); + ok( ofs.nErrCode == ERROR_SUCCESS || broken(ofs.nErrCode != ERROR_SUCCESS) /* win9x */, + "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); ok( lstrcmpiA(ofs.szPathName, buff) == 0, "OpenFile returned '%s', but was expected to return '%s'\n", ofs.szPathName, buff ); ret = CloseHandle((HANDLE)hFile); @@ -1796,7 +1881,8 @@ static void test_OpenFile(void) ok( GetLastError() == 0xfaceabee || GetLastError() == ERROR_SUCCESS, "GetLastError() returns %d\n", GetLastError() ); ok( ofs.cBytes == sizeof(OFSTRUCT), "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); - ok( ofs.nErrCode == ERROR_SUCCESS, "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); + ok( ofs.nErrCode == ERROR_SUCCESS || broken(ofs.nErrCode != ERROR_SUCCESS) /* win9x */, + "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); ok( lstrcmpiA(ofs.szPathName, buff) == 0, "OpenFile returned '%s', but was expected to return '%s'\n", ofs.szPathName, buff ); ret = CloseHandle((HANDLE)hFile); @@ -1810,7 +1896,8 @@ static void test_OpenFile(void) ok( GetLastError() == 0xfaceabee || GetLastError() == ERROR_SUCCESS, "GetLastError() returns %d\n", GetLastError() ); ok( ofs.cBytes == sizeof(OFSTRUCT), "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); - ok( ofs.nErrCode == ERROR_SUCCESS, "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); + ok( ofs.nErrCode == ERROR_SUCCESS || broken(ofs.nErrCode != ERROR_SUCCESS) /* win9x */, + "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); ok( lstrcmpiA(ofs.szPathName, buff) == 0, "OpenFile returned '%s', but was expected to return '%s'\n", ofs.szPathName, buff ); @@ -1822,7 +1909,8 @@ static void test_OpenFile(void) ok( GetLastError() == 0xfaceabee || GetLastError() == ERROR_SUCCESS, "GetLastError() returns %d\n", GetLastError() ); ok( ofs.cBytes == sizeof(OFSTRUCT), "OpenFile set ofs.cBytes to %d\n", ofs.cBytes ); - ok( ofs.nErrCode == ERROR_SUCCESS, "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); + ok( ofs.nErrCode == ERROR_SUCCESS || broken(ofs.nErrCode != ERROR_SUCCESS) /* win9x */, + "OpenFile set ofs.nErrCode to %d\n", ofs.nErrCode ); ok( lstrcmpiA(ofs.szPathName, buff) == 0, "OpenFile returned '%s', but was expected to return '%s'\n", ofs.szPathName, buff ); @@ -1840,15 +1928,19 @@ static void test_overlapped(void) memset( &ov, 0, sizeof ov ); result = 1; r = GetOverlappedResult(0, &ov, &result, 0); - ok( r == TRUE, "should return false\n"); - ok( result == 0, "wrong result %u\n", result ); + if (r) + ok( result == 0, "wrong result %u\n", result ); + else /* win9x */ + ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() ); result = 0; ov.Internal = 0; ov.InternalHigh = 0xabcd; r = GetOverlappedResult(0, &ov, &result, 0); - ok( r == TRUE, "should return false\n"); - ok( result == 0xabcd, "wrong result %u\n", result ); + if (r) + ok( result == 0xabcd, "wrong result %u\n", result ); + else /* win9x */ + ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() ); SetLastError( 0xb00 ); result = 0; @@ -1857,14 +1949,15 @@ static void test_overlapped(void) r = GetOverlappedResult(0, &ov, &result, 0); ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() ); ok( r == FALSE, "should return false\n"); - ok( result == 0xabcd, "wrong result %u\n", result ); + ok( result == 0xabcd || result == 0 /* win9x */, "wrong result %u\n", result ); SetLastError( 0xb00 ); result = 0; ov.Internal = STATUS_PENDING; ov.InternalHigh = 0xabcd; r = GetOverlappedResult(0, &ov, &result, 0); - ok( GetLastError() == ERROR_IO_INCOMPLETE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_IO_INCOMPLETE || GetLastError() == ERROR_INVALID_HANDLE /* win9x */, + "wrong error %u\n", GetLastError() ); ok( r == FALSE, "should return false\n"); ok( result == 0, "wrong result %u\n", result ); @@ -1873,7 +1966,8 @@ static void test_overlapped(void) ov.Internal = STATUS_PENDING; ov.InternalHigh = 0xabcd; r = GetOverlappedResult(0, &ov, &result, 0); - ok( GetLastError() == ERROR_IO_INCOMPLETE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_IO_INCOMPLETE || GetLastError() == ERROR_INVALID_HANDLE /* win9x */, + "wrong error %u\n", GetLastError() ); ok( r == FALSE, "should return false\n"); ResetEvent( ov.hEvent ); @@ -1882,7 +1976,8 @@ static void test_overlapped(void) ov.Internal = STATUS_PENDING; ov.InternalHigh = 0; r = GetOverlappedResult(0, &ov, &result, 0); - ok( GetLastError() == ERROR_IO_INCOMPLETE, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_IO_INCOMPLETE || GetLastError() == ERROR_INVALID_HANDLE /* win9x */, + "wrong error %u\n", GetLastError() ); ok( r == FALSE, "should return false\n"); r = CloseHandle( ov.hEvent ); @@ -1901,19 +1996,23 @@ static void test_RemoveDirectory(void) ok( rc, "SetCurrentDirectory failed, gle=%d\n", GetLastError() ); rc = RemoveDirectory("."); - todo_wine { - ok( !rc, "RemoveDirectory unexpectedly worked\n" ); - } + if (!rc) + { + rc = SetCurrentDirectory(".."); + ok( rc, "SetCurrentDirectory failed, gle=%d\n", GetLastError() ); - rc = SetCurrentDirectory(".."); - ok( rc, "SetCurrentDirectory failed, gle=%d\n", GetLastError() ); - - rc = RemoveDirectory(directory); - todo_wine { - ok( rc, "RemoveDirectory failed, gle=%d\n", GetLastError() ); + rc = RemoveDirectory(directory); + ok( rc, "RemoveDirectory failed, gle=%d\n", GetLastError() ); } } +static BOOL check_file_time( const FILETIME *ft1, const FILETIME *ft2, UINT tolerance ) +{ + ULONGLONG t1 = ((ULONGLONG)ft1->dwHighDateTime << 32) | ft1->dwLowDateTime; + ULONGLONG t2 = ((ULONGLONG)ft2->dwHighDateTime << 32) | ft2->dwLowDateTime; + return abs(t1 - t2) <= tolerance; +} + static void test_ReplaceFileA(void) { char replaced[MAX_PATH], replacement[MAX_PATH], backup[MAX_PATH]; @@ -2021,14 +2120,15 @@ static void test_ReplaceFileA(void) /* make sure that the backup has the old "replaced" filetime */ ret = GetFileTime(hBackupFile, NULL, NULL, &ftBackup); ok( ret, "GetFileTime error (backup %d\n", GetLastError()); - ok(CompareFileTime(&ftBackup, &ftReplaced) == 0, - "backup file has wrong filetime\n"); + ok(check_file_time(&ftBackup, &ftReplaced, 20000000), "backup file has wrong filetime\n"); CloseHandle(hBackupFile); /* make sure that the "replaced" has the old replacement filetime */ ret = GetFileTime(hReplacedFile, NULL, NULL, &ftReplaced); ok( ret, "GetFileTime error (backup %d\n", GetLastError()); - ok(CompareFileTime(&ftReplaced, &ftReplacement) == 0, - "replaced file has wrong filetime\n"); + ok(check_file_time(&ftReplaced, &ftReplacement, 20000000), + "replaced file has wrong filetime %x%08x / %x%08x\n", + ftReplaced.dwHighDateTime, ftReplaced.dwLowDateTime, + ftReplacement.dwHighDateTime, ftReplacement.dwLowDateTime ); CloseHandle(hReplacedFile); /* re-create replacement file for pass w/o backup (blank) */ @@ -2066,7 +2166,8 @@ static void test_ReplaceFileA(void) ok(ret != ERROR_UNABLE_TO_REMOVE_REPLACED, "ReplaceFileA: unexpected error %d\n", GetLastError()); /* make sure that the replacement file still exists */ hReplacementFile = CreateFileA(replacement, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); - ok(hReplacementFile != INVALID_HANDLE_VALUE, + ok(hReplacementFile != INVALID_HANDLE_VALUE || + broken(GetLastError() == ERROR_FILE_NOT_FOUND), /* win2k */ "unexpected error, replacement file should still exist %d\n", GetLastError()); CloseHandle(hReplacementFile); ret = SetFileAttributesA(replaced, FILE_ATTRIBUTE_NORMAL); @@ -2099,7 +2200,9 @@ static void test_ReplaceFileA(void) /* delete temporary files, replacement and replaced are already deleted */ ret = DeleteFileA(backup); - ok(ret, "DeleteFileA: error (backup) %d\n", GetLastError()); + ok(ret || + broken(GetLastError() == ERROR_ACCESS_DENIED), /* win2k */ + "DeleteFileA: error (backup) %d\n", GetLastError()); } /* @@ -2170,7 +2273,9 @@ static void test_ReplaceFileW(void) "ReplaceFileW: unexpected error %d\n", GetLastError()); ret = DeleteFileW(backup); - ok(ret, "DeleteFileW: error %d\n", GetLastError()); + ok(ret || + broken(GetLastError() == ERROR_ACCESS_DENIED), /* win2k */ + "DeleteFileW: error (backup) %d\n", GetLastError()); } START_TEST(file) diff --git a/rostests/winetests/kernel32/format_msg.c b/rostests/winetests/kernel32/format_msg.c index 1f52da9a8f5..74d51090074 100755 --- a/rostests/winetests/kernel32/format_msg.c +++ b/rostests/winetests/kernel32/format_msg.c @@ -228,7 +228,9 @@ static void test_message_null_buffer(void) ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, 0, 0, NULL, 0, NULL); error = GetLastError(); ok(!ret, "FormatMessageA returned %u\n", ret); - ok(error == ERROR_NOT_ENOUGH_MEMORY, "last error %u\n", error); + ok(error == ERROR_NOT_ENOUGH_MEMORY || + error == ERROR_INVALID_PARAMETER, /* win9x */ + "last error %u\n", error); SetLastError(0xdeadbeef); ret = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, 0, 0, NULL, 0, NULL); diff --git a/rostests/winetests/kernel32/heap.c b/rostests/winetests/kernel32/heap.c index 29398622709..c196c23e3cd 100755 --- a/rostests/winetests/kernel32/heap.c +++ b/rostests/winetests/kernel32/heap.c @@ -72,6 +72,13 @@ START_TEST(heap) mem = HeapAlloc(GetProcessHeap(), 0, ~0UL); ok(mem == NULL, "memory allocated for size ~0UL\n"); + /* large blocks must be 16-byte aligned */ + mem = HeapAlloc(GetProcessHeap(), 0, 512 * 1024); + ok( mem != NULL, "failed for size 512K\n" ); + ok( (ULONG_PTR)mem % 16 == 0 || broken((ULONG_PTR)mem % 16) /* win9x */, + "512K block not 16-byte aligned\n" ); + HeapFree(GetProcessHeap(), 0, mem); + /* Global*() functions */ gbl = GlobalAlloc(GMEM_MOVEABLE, 0); ok(gbl != NULL, "global memory not allocated for size 0\n"); @@ -185,24 +192,31 @@ START_TEST(heap) /* invalid free */ SetLastError(MAGIC_DEAD); mem = GlobalFree(gbl); - ok(mem == gbl, "Expected gbl, got %p\n", mem); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + ok(mem == gbl || broken(mem == NULL) /* nt4 */, "Expected gbl, got %p\n", mem); + if (mem == gbl) + ok(GetLastError() == ERROR_INVALID_HANDLE || + GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ + "Expected ERROR_INVALID_HANDLE or ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); gbl = GlobalAlloc(GMEM_DDESHARE, 100); res = GlobalUnlock(gbl); - ok(res == 1, "Expected 1, got %d\n", res); + ok(res == 1 || + res == 0, /* win9x */ + "Expected 1 or 0, got %d\n", res); res = GlobalUnlock(gbl); - ok(res == 1, "Expected 1, got %d\n", res); + ok(res == 1 || + res == 0, /* win9x */ + "Expected 1 or 0, got %d\n", res); /* GlobalSize on an invalid handle */ SetLastError(MAGIC_DEAD); size = GlobalSize((HGLOBAL)0xc042); ok(size == 0, "Expected 0, got %ld\n", size); - ok(GetLastError() == ERROR_INVALID_HANDLE, - "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE || + GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ + "Expected ERROR_INVALID_HANDLE or ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); /* ####################################### */ /* Local*() functions */ diff --git a/rostests/winetests/kernel32/loader.c b/rostests/winetests/kernel32/loader.c index 363c2fdf254..5187d882a45 100644 --- a/rostests/winetests/kernel32/loader.c +++ b/rostests/winetests/kernel32/loader.c @@ -27,6 +27,13 @@ #define ALIGN_SIZE(size, alignment) (((size) + (alignment - 1)) & ~((alignment - 1))) +static PVOID RVAToAddr(DWORD_PTR rva, HMODULE module) +{ + if (rva == 0) + return NULL; + return ((char*) module) + rva; +} + static const struct { WORD e_magic; /* 00: MZ Header signature */ @@ -103,7 +110,7 @@ static IMAGE_SECTION_HEADER section = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ, /* Characteristics */ }; -START_TEST(loader) +static void test_Loader(void) { static const struct test_data { @@ -113,6 +120,7 @@ START_TEST(loader) DWORD section_alignment, file_alignment; DWORD size_of_image, size_of_headers; DWORD error; /* 0 means LoadLibrary should succeed */ + DWORD alt_error; /* alternate error */ } td[] = { { &dos_header, sizeof(dos_header), @@ -141,7 +149,7 @@ START_TEST(loader) 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x200, sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER) + 0x200, sizeof(dos_header) + sizeof(nt_header) + sizeof(IMAGE_SECTION_HEADER), - ERROR_SUCCESS + ERROR_SUCCESS, ERROR_INVALID_ADDRESS /* vista is more strict */ }, { &dos_header, sizeof(dos_header), 1, sizeof(IMAGE_OPTIONAL_HEADER), 0x200, 0x1000, @@ -168,25 +176,25 @@ START_TEST(loader) 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, sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER), - ERROR_SUCCESS + ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */ }, { &dos_header, sizeof(dos_header), 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200, 0xd0, /* beyond of the end of file */ 0xc0, /* beyond of the end of file */ - ERROR_SUCCESS + ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */ }, { &dos_header, sizeof(dos_header), 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200, 0x1000, 0, - ERROR_SUCCESS + ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */ }, { &dos_header, sizeof(dos_header), 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200, 1, 0, - ERROR_SUCCESS + ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */ }, #if 0 /* not power of 2 alignments need more test cases */ { &dos_header, sizeof(dos_header), @@ -200,13 +208,13 @@ START_TEST(loader) 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 4, 4, 1, 0, - ERROR_SUCCESS + ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */ }, { &dos_header, sizeof(dos_header), 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 1, 1, 1, 0, - ERROR_SUCCESS + ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */ }, { &dos_header, sizeof(dos_header), 0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200, @@ -227,7 +235,7 @@ START_TEST(loader) 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04, 1, 0, - ERROR_SUCCESS + ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT /* vista is more strict */ } }; static const char filler[0x1000]; @@ -323,18 +331,11 @@ START_TEST(loader) SetLastError(0xdeadbeef); hlib = LoadLibrary(dll_name); - if (td[i].error == ERROR_SUCCESS) + if (hlib) { MEMORY_BASIC_INFORMATION info; - ok(hlib != 0, "%d: LoadLibrary error %d\n", i, GetLastError()); - - /* No point in crashing. Test crashes on Vista with some of the given files */ - if (hlib == 0) - { - skip("Failed to load dll number %d\n", i); - goto endloop; - } + ok( td[i].error == ERROR_SUCCESS, "%d: should have failed\n", i ); SetLastError(0xdeadbeef); ok(VirtualQuery(hlib, &info, sizeof(info)) == sizeof(info), @@ -461,8 +462,8 @@ START_TEST(loader) ok(FreeLibrary(hlib_as_data_file), "FreeLibrary error %d\n", GetLastError()); } else - { /* LoadLibrary is expected to fail */ - ok(!hlib, "%d: LoadLibrary should fail\n", i); + { + ok(td[i].error || td[i].alt_error, "%d: LoadLibrary should succeed\n", i); if (GetLastError() == ERROR_GEN_FAILURE) /* Win9x, broken behaviour */ { @@ -471,12 +472,73 @@ START_TEST(loader) return; } - ok(td[i].error == GetLastError(), "%d: expected error %d, got %d\n", - i, td[i].error, GetLastError()); + ok(td[i].error == GetLastError() || td[i].alt_error == GetLastError(), + "%d: expected error %d or %d, got %d\n", + i, td[i].error, td[i].alt_error, GetLastError()); } -endloop: SetLastError(0xdeadbeef); ok(DeleteFile(dll_name), "DeleteFile error %d\n", GetLastError()); } } + +/* Verify linking style of import descriptors */ +static void test_ImportDescriptors(void) +{ + HMODULE kernel32_module = NULL; + PIMAGE_DOS_HEADER d_header; + PIMAGE_NT_HEADERS nt_headers; + DWORD import_dir_size; + DWORD_PTR dir_offset; + PIMAGE_IMPORT_DESCRIPTOR import_chunk; + + /* Load kernel32 module */ + kernel32_module = GetModuleHandleA("kernel32.dll"); + assert( kernel32_module != NULL ); + + /* Get PE header info from module image */ + d_header = (PIMAGE_DOS_HEADER) kernel32_module; + nt_headers = (PIMAGE_NT_HEADERS) (((char*) d_header) + + d_header->e_lfanew); + + /* Get size of import entry directory */ + import_dir_size = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size; + if (!import_dir_size) + { + skip("Unable to continue testing due to missing import directory.\n"); + return; + } + + /* Get address of first import chunk */ + dir_offset = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; + import_chunk = RVAToAddr(dir_offset, kernel32_module); + ok(import_chunk != 0, "Invalid import_chunk: %p\n", import_chunk); + if (!import_chunk) return; + + /* Iterate through import descriptors and verify set name, + * OriginalFirstThunk, and FirstThunk. Core Windows DLLs, such as + * kernel32.dll, don't use Borland-style linking, where the table of + * imported names is stored directly in FirstThunk and overwritten + * by the relocation, instead of being stored in OriginalFirstThunk. + * */ + for (; import_chunk->FirstThunk; import_chunk++) + { + LPCSTR module_name = RVAToAddr(import_chunk->Name, kernel32_module); + PIMAGE_THUNK_DATA name_table = RVAToAddr( + U(*import_chunk).OriginalFirstThunk, kernel32_module); + PIMAGE_THUNK_DATA iat = RVAToAddr( + import_chunk->FirstThunk, kernel32_module); + ok(module_name != NULL, "Imported module name should not be NULL\n"); + ok(name_table != NULL, + "Name table for imported module %s should not be NULL\n", + module_name); + ok(iat != NULL, "IAT for imported module %s should not be NULL\n", + module_name); + } +} + +START_TEST(loader) +{ + test_Loader(); + test_ImportDescriptors(); +} diff --git a/rostests/winetests/kernel32/locale.c b/rostests/winetests/kernel32/locale.c index 60e6f114a8c..4dce7335e0b 100755 --- a/rostests/winetests/kernel32/locale.c +++ b/rostests/winetests/kernel32/locale.c @@ -102,32 +102,16 @@ static void InitFunctionPointers(void) #define BUFFER_SIZE 128 #define COUNTOF(x) (sizeof(x)/sizeof(x)[0]) -#define EXPECT_LEN(len) ok(ret == (len), "Expected Len %d, got %d\n", (int)(len), ret) -#define EXPECT_INVALID ok(GetLastError() == ERROR_INVALID_PARAMETER, \ - "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()) -#define EXPECT_BUFFER ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, \ - "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()) -#define EXPECT_FLAGS ok(GetLastError() == ERROR_INVALID_FLAGS, \ - "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()) -#define EXPECT_INVALIDFLAGS ok(GetLastError() == ERROR_INVALID_FLAGS || \ - GetLastError() == ERROR_INVALID_PARAMETER, \ - "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()) -#define EXPECT_LASTERROR_0 ok(GetLastError() == 0, \ - "Expected GetLastError() == 0, got %d\n", GetLastError()) -#define EXPECT_VALID ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()) - -#define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0); buffer[0] = '\0' -#define EXPECT_LENA EXPECT_LEN((int)strlen(Expected)+1) +#define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0xdeadbeef); buffer[0] = '\0' +#define EXPECT_LENA ok(ret == lstrlen(Expected)+1, "Expected Len %d, got %d\n", lstrlen(Expected)+1, ret) #define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \ "Expected '%s', got '%s'\n", Expected, buffer) #define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \ MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \ - SetLastError(0); buffer[0] = '\0' -#define EXPECT_LENW EXPECT_LEN((int)strlenW(Expected)+1) + SetLastError(0xdeadbeef); buffer[0] = '\0' +#define EXPECT_LENW ok(ret == lstrlenW(Expected)+1, "Expected Len %d, got %d\n", lstrlenW(Expected)+1, ret) #define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n") -#define EXPECT_FALSE ok(FALSE == ret, "Expected return value FALSE, got TRUE\n") -#define EXPECT_TRUE ok(FALSE != ret, "Expected return value TRUE, got FALSE\n") #define NUO LOCALE_NOUSEROVERRIDE @@ -148,12 +132,13 @@ static void test_GetLocaleInfoA(void) SetLastError(0); memset(buffer, 0, COUNTOF(buffer)); ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3); - EXPECT_BUFFER; EXPECT_LEN(0); + ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer); SetLastError(0); memset(buffer, 0, COUNTOF(buffer)); ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10); - EXPECT_VALID; EXPECT_LEN(7); + ok(ret == 7, "Expected ret == 7, got %d, error %d\n", ret, GetLastError()); ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer); } @@ -168,7 +153,8 @@ static void test_GetTimeFormatA(void) STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */ SetLastError(0xdeadbeef); ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); curtime.wHour = 8; curtime.wMinute = 56; @@ -177,83 +163,104 @@ static void test_GetTimeFormatA(void) STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */ SetLastError(0xdeadbeef); ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; /* MSDN: LOCALE_NOUSEROVERRIDE can't be specified with a format string */ SetLastError(0xdeadbeef); ret = GetTimeFormatA(lcid, NUO|TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA; + ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficient buffer */ SetLastError(0xdeadbeef); ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2); - EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */ ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0); - EXPECT_VALID; EXPECT_LENA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */ ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */ ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "4" )), /* win9x */ + "Expected '', got '%s'\n", buffer ); STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */ ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */ strcpy(Expected, "8:56 AM"); ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */ ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + ok( !strcmp( buffer, "8.@:56AM" ) || broken( !strcmp( buffer, "8.@:56.@:AM" )) /* win9x */, + "Expected '8.@:56AM', got '%s'\n", buffer ); STRINGSA("s1s2s3", ""); /* Duplicate tokens */ ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret == strlen(buffer)+1, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + ok( !strcmp( buffer, "" ) || broken( !strcmp( buffer, "3" )), /* win9x */ + "Expected '', got '%s'\n", buffer ); STRINGSA("t/tt", "A/AM"); /* AM time marker */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; curtime.wHour = 13; STRINGSA("t/tt", "P/PM"); /* PM time marker */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */ ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */ ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */ ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; curtime.wHour = 14; /* change this to 14 or 2pm */ curtime.wMinute = 5; curtime.wSecond = 3; STRINGSA("h hh H HH m mm s ss t tt", "2 02 14 14 5 05 3 03 P PM"); /* 24 hrs, leading 0 */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; curtime.wHour = 0; STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; /* try to convert formatting strings with more than two letters * "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS" @@ -268,55 +275,66 @@ static void test_GetTimeFormatA(void) STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS", "8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS"); ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */ strcpy(buffer, "text"); ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0); - EXPECT_VALID; EXPECT_LEN(2); EXPECT_EQA; + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); + EXPECT_EQA; STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'", "8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("'''", "'"); /* invalid quoted string */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; /* test that msdn suggested single quotation usage works as expected */ STRINGSA("''''", "'"); /* single quote mark */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("''HHHHHH", "08"); /* Normal use */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; /* and test for normal use of the single quotation mark */ STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */ ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; curtime.wHour = 25; STRINGSA("'123'tt", ""); /* Invalid time */ SetLastError(0xdeadbeef); ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); curtime.wHour = 12; curtime.wMonth = 60; /* Invalid */ STRINGSA("h:m:s", "12:56:13"); /* Invalid date */ ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; } static void test_GetDateFormatA(void) @@ -330,7 +348,8 @@ static void test_GetDateFormatA(void) STRINGSA("ddd',' MMM dd yy",""); SetLastError(0xdeadbeef); ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); curtime.wYear = 2002; curtime.wMonth = 5; @@ -338,48 +357,58 @@ static void test_GetDateFormatA(void) curtime.wDayOfWeek = 3; STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Simple case */ ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; /* Same as above but with LOCALE_NOUSEROVERRIDE */ STRINGSA("ddd',' MMM dd yy",""); /* Simple case */ SetLastError(0xdeadbeef); ret = GetDateFormatA(lcid, NUO, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA; + ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); + EXPECT_EQA; STRINGSA("ddd',' MMM dd yy","Sat, May 04 02"); /* Format containing "'" */ ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; curtime.wHour = 36; /* Invalid */ STRINGSA("ddd',' MMM dd ''''yy","Sat, May 04 '02"); /* Invalid time */ ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("ddd',' MMM dd ''''yy",""); /* Get size only */ ret = GetDateFormatA(lcid, 0, &curtime, input, NULL, 0); - EXPECT_VALID; EXPECT_LEN(16); EXPECT_EQA; + ok(ret == 16, "Expected ret == 16, got %d, error %d\n", ret, GetLastError()); + EXPECT_EQA; STRINGSA("ddd',' MMM dd ''''yy",""); /* Buffer too small */ SetLastError(0xdeadbeef); ret = GetDateFormatA(lcid, 0, &curtime, input, buffer, 2); - EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); STRINGSA("ddd',' MMM dd ''''yy","5/4/2002"); /* Default to DATE_SHORTDATE */ ret = GetDateFormat(lcid, NUO, &curtime, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); if (strncmp(buffer, Expected, strlen(Expected)) && strncmp(buffer, "5/4/02", strlen(Expected)) != 0) ok (0, "Expected '%s' or '5/4/02', got '%s'\n", Expected, buffer); STRINGSA("ddd',' MMM dd ''''yy", "Saturday, May 04, 2002"); /* DATE_LONGDATE */ ret = GetDateFormat(lcid, NUO|DATE_LONGDATE, &curtime, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; /* test for expected DATE_YEARMONTH behavior with null format */ /* NT4 returns ERROR_INVALID_FLAGS for DATE_YEARMONTH */ STRINGSA("ddd',' MMM dd ''''yy", ""); /* DATE_YEARMONTH */ SetLastError(0xdeadbeef); ret = GetDateFormat(lcid, NUO|DATE_YEARMONTH, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA; + ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); + EXPECT_EQA; /* Test that using invalid DATE_* flags results in the correct error */ /* and return values */ @@ -387,7 +416,9 @@ static void test_GetDateFormatA(void) SetLastError(0xdeadbeef); ret = GetDateFormat(lcid, DATE_YEARMONTH|DATE_SHORTDATE|DATE_LONGDATE, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQA; + ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); + EXPECT_EQA; } static void test_GetDateFormatW(void) @@ -402,16 +433,20 @@ static void test_GetDateFormatW(void) input, buffer, COUNTOF(buffer)); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) return; - EXPECT_FLAGS; EXPECT_LEN(0); EXPECT_EQW; + ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); + EXPECT_EQW; STRINGSW("",""); /* NULL buffer, len > 0 */ SetLastError(0xdeadbeef); ret = GetDateFormatW (lcid, 0, NULL, input, NULL, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQW; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSW("",""); /* NULL buffer, len == 0 */ ret = GetDateFormatW (lcid, 0, NULL, input, NULL, 0); - EXPECT_VALID; EXPECT_LENW; EXPECT_EQW; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENW; EXPECT_EQW; curtime.wYear = 2002; curtime.wMonth = 10; @@ -423,7 +458,8 @@ static void test_GetDateFormatW(void) curtime.wMilliseconds = 12345; STRINGSW("dddd d MMMM yyyy","Wednesday 23 October 2002"); /* Incorrect DOW and time */ ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENW; EXPECT_EQW; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENW; EXPECT_EQW; /* Limit tests */ @@ -438,7 +474,8 @@ static void test_GetDateFormatW(void) STRINGSW("dddd d MMMM yyyy","Monday 1 January 1601"); SetLastError(0xdeadbeef); ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENW; EXPECT_EQW; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENW; EXPECT_EQW; curtime.wYear = 1600; curtime.wMonth = 12; @@ -451,7 +488,8 @@ static void test_GetDateFormatW(void) STRINGSW("dddd d MMMM yyyy","Friday 31 December 1600"); SetLastError(0xdeadbeef); ret = GetDateFormatW (lcid, 0, &curtime, input, buffer, COUNTOF(buffer)); - EXPECT_INVALID; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); } @@ -475,67 +513,82 @@ static void test_GetCurrencyFormatA(void) STRINGSA("23",""); /* NULL output, length > 0 --> Error */ SetLastError(0xdeadbeef); ret = GetCurrencyFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("23,53",""); /* Invalid character --> Error */ SetLastError(0xdeadbeef); ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("--",""); /* Double '-' --> Error */ SetLastError(0xdeadbeef); ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("0-",""); /* Trailing '-' --> Error */ SetLastError(0xdeadbeef); ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("0..",""); /* Double '.' --> Error */ SetLastError(0xdeadbeef); ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA(" 0.1",""); /* Leading space --> Error */ SetLastError(0xdeadbeef); ret = GetCurrencyFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("1234","$"); /* Length too small --> Write up to length chars */ SetLastError(0xdeadbeef); ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, 2); - EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); STRINGSA("2353",""); /* Format and flags given --> Error */ SetLastError(0xdeadbeef); ret = GetCurrencyFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer)); - EXPECT_INVALIDFLAGS; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret, "Expected ret == 0, got %d\n", ret); + ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); STRINGSA("2353",""); /* Invalid format --> Error */ SetLastError(0xdeadbeef); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("2353","$2,353.00"); /* Valid number */ ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("-2353","($2,353.00)"); /* Valid negative number */ ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("2353.1","$2,353.10"); /* Valid real number */ ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("2353.111","$2,353.11"); /* Too many DP --> Truncated */ ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("2353.119","$2,353.12"); /* Too many DP --> Rounded */ ret = GetCurrencyFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NumDigits = 0; /* No decimal separator */ format.LeadingZero = 0; @@ -548,117 +601,140 @@ static void test_GetCurrencyFormatA(void) STRINGSA("2353","$2353"); /* No decimal or grouping chars expected */ ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NumDigits = 1; /* 1 DP --> Expect decimal separator */ STRINGSA("2353","$2353.0"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.Grouping = 2; /* Group by 100's */ STRINGSA("2353","$23,53.0"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.LeadingZero = 1; /* Always provide leading zero */ STRINGSA(".5","$0.5"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.PositiveOrder = CY_POS_RIGHT; STRINGSA("1","1.0$"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.PositiveOrder = CY_POS_LEFT_SPACE; STRINGSA("1","$ 1.0"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.PositiveOrder = CY_POS_RIGHT_SPACE; STRINGSA("1","1.0 $"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 0; STRINGSA("-1","($1.0)"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 1; STRINGSA("-1","-$1.0"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 2; STRINGSA("-1","$-1.0"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 3; STRINGSA("-1","$1.0-"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 4; STRINGSA("-1","(1.0$)"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 5; STRINGSA("-1","-1.0$"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 6; STRINGSA("-1","1.0-$"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 7; STRINGSA("-1","1.0$-"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 8; STRINGSA("-1","-1.0 $"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 9; STRINGSA("-1","-$ 1.0"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 10; STRINGSA("-1","1.0 $-"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 11; STRINGSA("-1","$ 1.0-"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 12; STRINGSA("-1","$ -1.0"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 13; STRINGSA("-1","1.0- $"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 14; STRINGSA("-1","($ 1.0)"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = 15; STRINGSA("-1","(1.0 $)"); ret = GetCurrencyFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; } #define NEG_PARENS 0 /* "(1.1)" */ @@ -681,71 +757,87 @@ static void test_GetNumberFormatA(void) STRINGSA("23",""); /* NULL output, length > 0 --> Error */ SetLastError(0xdeadbeef); ret = GetNumberFormatA(lcid, 0, input, NULL, NULL, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("23,53",""); /* Invalid character --> Error */ SetLastError(0xdeadbeef); ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("--",""); /* Double '-' --> Error */ SetLastError(0xdeadbeef); ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("0-",""); /* Trailing '-' --> Error */ SetLastError(0xdeadbeef); ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("0..",""); /* Double '.' --> Error */ SetLastError(0xdeadbeef); ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA(" 0.1",""); /* Leading space --> Error */ SetLastError(0xdeadbeef); ret = GetNumberFormatA(lcid, 0, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("1234","1"); /* Length too small --> Write up to length chars */ SetLastError(0xdeadbeef); ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, 2); - EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); STRINGSA("2353",""); /* Format and flags given --> Error */ SetLastError(0xdeadbeef); ret = GetNumberFormatA(lcid, NUO, input, &format, buffer, COUNTOF(buffer)); - EXPECT_INVALIDFLAGS; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret, "Expected ret == 0, got %d\n", ret); + ok( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); STRINGSA("2353",""); /* Invalid format --> Error */ SetLastError(0xdeadbeef); ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); STRINGSA("2353","2,353.00"); /* Valid number */ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("-2353","-2,353.00"); /* Valid negative number */ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("-353","-353.00"); /* test for off by one error in grouping */ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("2353.1","2,353.10"); /* Valid real number */ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("2353.111","2,353.11"); /* Too many DP --> Truncated */ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; STRINGSA("2353.119","2,353.12"); /* Too many DP --> Rounded */ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NumDigits = 0; /* No decimal separator */ format.LeadingZero = 0; @@ -756,47 +848,56 @@ static void test_GetNumberFormatA(void) STRINGSA("2353","2353"); /* No decimal or grouping chars expected */ ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NumDigits = 1; /* 1 DP --> Expect decimal separator */ STRINGSA("2353","2353.0"); ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.Grouping = 2; /* Group by 100's */ STRINGSA("2353","23,53.0"); ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.LeadingZero = 1; /* Always provide leading zero */ STRINGSA(".5","0.5"); ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = NEG_PARENS; STRINGSA("-1","(1.0)"); ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = NEG_LEFT; STRINGSA("-1","-1.0"); ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = NEG_LEFT_SPACE; STRINGSA("-1","- 1.0"); ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = NEG_RIGHT; STRINGSA("-1","1.0-"); ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; format.NegativeOrder = NEG_RIGHT_SPACE; STRINGSA("-1","1.0 -"); ret = GetNumberFormatA(lcid, 0, input, &format, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; lcid = MAKELCID(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), SORT_DEFAULT); @@ -805,7 +906,8 @@ static void test_GetNumberFormatA(void) STRINGSA("-12345","-12 345,00"); /* Try French formatting */ Expected[3] = 160; /* Non breaking space */ ret = GetNumberFormatA(lcid, NUO, input, NULL, buffer, COUNTOF(buffer)); - EXPECT_VALID; EXPECT_LENA; EXPECT_EQA; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); + EXPECT_LENA; EXPECT_EQA; } } @@ -840,7 +942,7 @@ static void test_CompareStringA(void) /* test for CompareStringA flags */ SetLastError(0xdeadbeef); - ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x10, "NULL", -1, "NULL", -1); + ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x8, "NULL", -1, "NULL", -1); ok(GetLastError() == ERROR_INVALID_FLAGS, "unexpected error code %d\n", GetLastError()); ok(!ret, "CompareStringA must fail with invalid flag\n"); @@ -855,14 +957,14 @@ static void test_CompareStringA(void) ok (ret == 0, "lstrcmpA(\"\", \"\") should return 0, got %d\n", ret); ret = lstrcmpA(NULL, NULL); - ok (ret == 0, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret); + ok (ret == 0 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, NULL) should return 0, got %d\n", ret); ret = lstrcmpA("", NULL); - ok (ret == 1, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret); + ok (ret == 1 || broken(ret == -2) /* win9x */, "lstrcmpA(\"\", NULL) should return 1, got %d\n", ret); ret = lstrcmpA(NULL, ""); - ok (ret == -1, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret); - + ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret); + ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"EndDialog",-1,"_Property",-1); ok( ret == 3, "EndDialog vs _Property ... expected 3, got %d\n", ret); @@ -1193,7 +1295,7 @@ static void test_LCMapStringW(void) upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR)); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - trace("Skipping LCMapStringW tests on Win9x\n"); + win_skip("LCMapStringW is not implemented\n"); return; } ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n"); @@ -1332,14 +1434,14 @@ static void test_LCMapStringW(void) /* test srclen = 0 */ SetLastError(0xdeadbeef); - ret = LCMapStringW(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf)); + ret = LCMapStringW(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf)/sizeof(WCHAR)); ok(!ret, "LCMapStringW should fail with srclen = 0\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, "unexpected error code %d\n", GetLastError()); } /* this requires collation table patch to make it MS compatible */ -const char *strings_sorted[] = +static const char * const strings_sorted[] = { "'", "-", @@ -1371,7 +1473,7 @@ const char *strings_sorted[] = "C" }; -const char *strings[] = +static const char * const strings[] = { "C", "\"", @@ -1523,7 +1625,7 @@ static void test_FoldStringA(void) ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256); if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) return; - EXPECT_LEN(4); EXPECT_VALID; + ok(ret == 4, "Expected ret == 4, got %d, error %d\n", ret, GetLastError()); ok(strcmp(dst, digits_dst) == 0, "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", digits_dst, dst); for (i = 1; i < 256; i++) @@ -1534,7 +1636,7 @@ static void test_FoldStringA(void) src[1] = '\0'; SetLastError(0); ret = pFoldStringA(MAP_FOLDDIGITS, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); ok(dst[0] == src[0], "MAP_FOLDDIGITS: Expected '%s', got '%s'\n", src, dst); } @@ -1545,7 +1647,7 @@ static void test_FoldStringA(void) ret = pFoldStringA(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256); /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */ if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) { - EXPECT_LEN(sizeof(ligatures_dst)); EXPECT_VALID; + ok(ret == sizeof(ligatures_dst), "Got %d, error %d\n", ret, GetLastError()); ok(strcmp(dst, ligatures_dst) == 0, "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", ligatures_dst, dst); for (i = 1; i < 256; i++) @@ -1556,7 +1658,7 @@ static void test_FoldStringA(void) src[1] = '\0'; SetLastError(0); ret = pFoldStringA(MAP_EXPAND_LIGATURES, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); ok(dst[0] == src[0], "MAP_EXPAND_LIGATURES: Expected '%s', got '%s'\n", src, dst); } @@ -1566,11 +1668,11 @@ static void test_FoldStringA(void) /* MAP_COMPOSITE */ SetLastError(0); ret = pFoldStringA(MAP_COMPOSITE, composite_src, -1, dst, 256); - EXPECT_VALID; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); todo_wine { /* Wine gets close, but doesn't produce quite the same result as native */ - EXPECT_LEN(121); + ok(ret == 121, "Expected 121, got %d\n", ret); ok(strcmp(dst, composite_dst) == 0, "MAP_COMPOSITE: Expected '%s', got '%s'\n", composite_dst, dst); } @@ -1583,7 +1685,7 @@ static void test_FoldStringA(void) src[1] = '\0'; SetLastError(0); ret = pFoldStringA(MAP_COMPOSITE, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); ok(dst[0] == src[0], "0x%02x, 0x%02x,0x%02x,0x%02x,\n", (unsigned char)src[0], (unsigned char)dst[0],(unsigned char)dst[1],(unsigned char)dst[2]); @@ -1597,7 +1699,7 @@ static void test_FoldStringA(void) src[1] = '\0'; SetLastError(0); ret = pFoldStringA(MAP_FOLDCZONE, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); ok(src[0] == dst[0], "MAP_FOLDCZONE: Expected 0x%02x, got 0x%02x\n", (unsigned char)src[0], (unsigned char)dst[0]); @@ -1610,7 +1712,7 @@ static void test_FoldStringA(void) src[1] = '\0'; SetLastError(0); ret = pFoldStringA(MAP_PRECOMPOSED, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); ok(src[0] == dst[0], "MAP_PRECOMPOSED: Expected 0x%02x, got 0x%02x\n", (unsigned char)src[0], (unsigned char)dst[0]); @@ -1620,7 +1722,7 @@ static void test_FoldStringA(void) static void test_FoldStringW(void) { int ret; - unsigned int i, j; + unsigned int i, j, failures; WCHAR src[256], dst[256], ch, prev_ch = 1; static const DWORD badFlags[] = { @@ -1814,28 +1916,33 @@ static void test_FoldStringW(void) skip("FoldStringW is not implemented\n"); return; } - EXPECT_LEN(0); EXPECT_FLAGS; + ok(!ret && GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); } /* src & dst cannot be the same */ SetLastError(0); ret = pFoldStringW(MAP_FOLDCZONE, src, -1, src, 256); - EXPECT_LEN(0); EXPECT_INVALID; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); /* src can't be NULL */ SetLastError(0); ret = pFoldStringW(MAP_FOLDCZONE, NULL, -1, dst, 256); - EXPECT_LEN(0); EXPECT_INVALID; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); /* srclen can't be 0 */ SetLastError(0); ret = pFoldStringW(MAP_FOLDCZONE, src, 0, dst, 256); - EXPECT_LEN(0); EXPECT_INVALID; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); /* dstlen can't be < 0 */ SetLastError(0); ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, -1); - EXPECT_LEN(0); EXPECT_INVALID; + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); /* Ret includes terminating NUL which is appended if srclen = -1 */ SetLastError(0); @@ -1843,7 +1950,7 @@ static void test_FoldStringW(void) src[1] = '\0'; dst[0] = '\0'; ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); ok(dst[0] == 'A' && dst[1] == '\0', "srclen=-1: Expected ret=2 [%d,%d], got ret=%d [%d,%d], err=%d\n", 'A', '\0', ret, dst[0], dst[1], GetLastError()); @@ -1855,7 +1962,7 @@ static void test_FoldStringW(void) dst[0] = 'X'; dst[1] = 'X'; ret = pFoldStringW(MAP_FOLDCZONE, src, 1, dst, 256); - EXPECT_LEN(1); EXPECT_VALID; + ok(ret == 1, "Expected ret == 1, got %d, error %d\n", ret, GetLastError()); ok(dst[0] == 'A' && dst[1] == 'X', "srclen=1: Expected ret=1, [%d,%d], got ret=%d,[%d,%d], err=%d\n", 'A','X', ret, dst[0], dst[1], GetLastError()); @@ -1870,7 +1977,7 @@ static void test_FoldStringW(void) src[0] = ch; src[1] = dst[0] = '\0'; ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); ok(dst[0] == ch || strchrW(outOfSequenceDigits, ch) || /* Wine (correctly) maps all Unicode 4.0+ digits */ @@ -1896,9 +2003,10 @@ static void test_FoldStringW(void) src[0] = c; src[1] = dst[0] = '\0'; ret = pFoldStringW(MAP_FOLDDIGITS, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); ok((dst[0] == '0' + ch - digitRanges[j] && dst[1] == '\0') || + broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */ strchrW(noDigitAvailable, c), "MAP_FOLDDIGITS: ch %d Expected %d got %d\n", ch, '0' + digitRanges[j] - ch, dst[0]); @@ -1907,7 +2015,7 @@ static void test_FoldStringW(void) } /* MAP_FOLDCZONE */ - for (ch = 1; ch <0xffff; ch++) + for (ch = 1, failures = 0; ch <0xffff; ch++) { WCHAR expected = 0; @@ -1925,8 +2033,9 @@ static void test_FoldStringW(void) src[0] = ch; src[1] = dst[0] = '\0'; ret = pFoldStringW(MAP_FOLDCZONE, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); ok(dst[0] == expected || + broken( dst[0] == ch ) || /* old Windows versions don't have all mappings */ /* Wine (correctly) uses updated mappings for some Unicode 4.0 chars */ /* FIXME: But they should be re-checked */ ch == 0xf92c || ch == 0xf979 || ch == 0xf995 || ch == 0xf9e7 || @@ -1939,6 +2048,11 @@ static void test_FoldStringW(void) ch == 0xff9e || ch == 0xff9f, "MAP_FOLDCZONE: ch %d 0x%04x Expected 0x%04x got 0x%04x\n", ch, ch, expected, dst[0]); + if (dst[0] != expected && ch < 0xf000 && ++failures > 50) + { + trace( "MAP_FOLDCZONE: Too many failures, giving up\n" ); + break; + } } /* MAP_EXPAND_LIGATURES */ @@ -1946,10 +2060,11 @@ static void test_FoldStringW(void) ret = pFoldStringW(MAP_EXPAND_LIGATURES, ligatures_src, -1, dst, 256); /* NT 4.0 doesn't support MAP_EXPAND_LIGATURES */ if (!(ret == 0 && GetLastError() == ERROR_INVALID_FLAGS)) { - EXPECT_LEN(sizeof(ligatures_dst)/sizeof(ligatures_dst[0])); EXPECT_VALID; + ok(ret == sizeof(ligatures_dst)/sizeof(ligatures_dst[0]), + "Got %d, error %d\n", ret, GetLastError()); ok(!memcmp(dst, ligatures_dst, sizeof(ligatures_dst)), "MAP_EXPAND_LIGATURES: Expanded incorrectly\n"); - for (i = 1; i <= 0xffff; i++) + for (i = 1, failures = 0; i <= 0xffff; i++) { if (!strchrW(ligatures_src, i)) { @@ -1957,10 +2072,19 @@ static void test_FoldStringW(void) src[1] = '\0'; SetLastError(0); ret = pFoldStringW(MAP_EXPAND_LIGATURES, src, -1, dst, 256); - EXPECT_LEN(2); EXPECT_VALID; - ok(dst[0] == src[0], - "MAP_EXPAND_LIGATURES: 0x%02x : Expected 0x%02x, got 0x%02x\n", - i, src[0], dst[0]); + ok(ret == 2, "Expected ret == 2, got %d, error %d\n", ret, GetLastError()); + if (ret == 3) + ok(0, "MAP_EXPAND_LIGATURES: %04x : Expected %04x, got %04x %04x\n", + i, src[0], dst[0], dst[1]); + else + ok(dst[0] == src[0], + "MAP_EXPAND_LIGATURES: %04x : Expected %04x, got %04x\n", + i, src[0], dst[0]); + if (dst[0] != src[0] && ++failures > 50) + { + trace( "MAP_EXPAND_LIGATURES: Too many failures, giving up\n" ); + break; + } } } } @@ -2028,23 +2152,34 @@ static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName, static void test_EnumSystemLanguageGroupsA(void) { + BOOL ret; + if (!pEnumSystemLanguageGroupsA || !pIsValidLanguageGroup) + { + win_skip("EnumSystemLanguageGroupsA and/or IsValidLanguageGroup are not available\n"); return; + } /* No enumeration proc */ SetLastError(0); - pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0); - EXPECT_INVALID; + ret = pEnumSystemLanguageGroupsA(0, LGRPID_INSTALLED, 0); + if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("EnumSystemLanguageGroupsA is not implemented\n"); + return; + } + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); /* Invalid flags */ SetLastError(0); pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED|LGRPID_SUPPORTED, 0); - EXPECT_FLAGS; + ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); /* No flags - defaults to LGRPID_INSTALLED */ - SetLastError(0); + SetLastError(0xdeadbeef); pEnumSystemLanguageGroupsA(langgrp_procA, 0, 1); - EXPECT_LASTERROR_0; + ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError()); pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_INSTALLED, 0); pEnumSystemLanguageGroupsA(langgrp_procA, LGRPID_SUPPORTED, 0); @@ -2056,6 +2191,10 @@ static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum, { trace("%08x, %08x, %s, %08lx\n", lgrpid, lcid, lpszNum, lParam); + /* invalid locale enumerated on some platforms */ + if (lcid == 0) + return TRUE; + ok(pIsValidLanguageGroup(lgrpid, LGRPID_SUPPORTED) == TRUE, "Enumerated grp %d not valid\n", lgrpid); ok(IsValidLocale(lcid, LCID_SUPPORTED) == TRUE, @@ -2065,28 +2204,42 @@ static BOOL CALLBACK lgrplocale_procA(LGRPID lgrpid, LCID lcid, LPSTR lpszNum, static void test_EnumLanguageGroupLocalesA(void) { + BOOL ret; + if (!pEnumLanguageGroupLocalesA || !pIsValidLanguageGroup) + { + win_skip("EnumLanguageGroupLocalesA and/or IsValidLanguageGroup are not available\n"); return; + } /* No enumeration proc */ SetLastError(0); - pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0); - EXPECT_INVALID; + ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0, 0); + if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("EnumLanguageGroupLocalesA is not implemented\n"); + return; + } + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); /* lgrpid too small */ SetLastError(0); - pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0); - EXPECT_INVALID; + ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, 0, 0, 0); + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); /* lgrpid too big */ SetLastError(0); - pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0); - EXPECT_INVALID; + ret = pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_ARMENIAN + 1, 0, 0); + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); /* dwFlags is reserved */ SetLastError(0); - pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0); - EXPECT_INVALID; + ret = pEnumLanguageGroupLocalesA(0, LGRPID_WESTERN_EUROPE, 0x1, 0); + ok( !ret && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); pEnumLanguageGroupLocalesA(lgrplocale_procA, LGRPID_WESTERN_EUROPE, 0, 0); } @@ -2099,17 +2252,20 @@ static void test_SetLocaleInfoA(void) /* Null data */ SetLastError(0); bRet = SetLocaleInfoA(lcid, LOCALE_SDATE, 0); - EXPECT_INVALID; + ok( !bRet && GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); /* IDATE */ SetLastError(0); bRet = SetLocaleInfoA(lcid, LOCALE_IDATE, (LPSTR)test_SetLocaleInfoA); - EXPECT_FLAGS; + ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); /* ILDATE */ SetLastError(0); bRet = SetLocaleInfoA(lcid, LOCALE_ILDATE, (LPSTR)test_SetLocaleInfoA); - EXPECT_FLAGS; + ok(!bRet && GetLastError() == ERROR_INVALID_FLAGS, + "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); } static BOOL CALLBACK luilocale_proc1A(LPSTR value, LONG_PTR lParam) @@ -2135,30 +2291,40 @@ static void test_EnumUILanguageA(void) { BOOL ret; if (!pEnumUILanguagesA) { - trace("EnumUILanguagesA is not available on Win9x\n"); + skip("EnumUILanguagesA is not available on Win9x or NT4\n"); return; } SetLastError(ERROR_SUCCESS); ret = pEnumUILanguagesA(luilocale_proc1A, 0, 0); - EXPECT_TRUE; EXPECT_VALID; + if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("EnumUILanguagesA is not implemented\n"); + return; + } + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); enumCount = 0; SetLastError(ERROR_SUCCESS); ret = pEnumUILanguagesA(luilocale_proc2A, 0, 0); - EXPECT_TRUE; EXPECT_VALID; + ok(ret, "Expected ret != 0, got %d, error %d\n", ret, GetLastError()); SetLastError(ERROR_SUCCESS); ret = pEnumUILanguagesA(NULL, 0, 0); - EXPECT_FALSE; EXPECT_INVALID; + ok(!ret, "Expected return value FALSE, got %u\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); SetLastError(ERROR_SUCCESS); ret = pEnumUILanguagesA(luilocale_proc3A, 0x5a5a5a5a, 0); - EXPECT_FALSE; EXPECT_FLAGS; + ok(!ret, "Expected return value FALSE, got %u\n", ret); + ok(GetLastError() == ERROR_INVALID_FLAGS, "Expected ERROR_INVALID_FLAGS, got %d\n", GetLastError()); SetLastError(ERROR_SUCCESS); ret = pEnumUILanguagesA(NULL, 0x5a5a5a5a, 0); - EXPECT_FALSE; EXPECT_INVALID; + ok(!ret, "Expected return value FALSE, got %u\n", ret); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); } static char date_fmt_buf[1024]; @@ -2178,25 +2344,41 @@ static void test_EnumDateFormatsA(void) trace("EnumDateFormatsA 0\n"); date_fmt_buf[0] = 0; + SetLastError(0xdeadbeef); ret = EnumDateFormatsA(enum_datetime_procA, lcid, 0); - ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError()); - trace("%s\n", date_fmt_buf); - /* test the 1st enumerated format */ - if ((p = strchr(date_fmt_buf, '\n'))) *p = 0; - ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf)); - ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError()); - ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf); + if (!ret && (GetLastError() == ERROR_INVALID_FLAGS)) + { + win_skip("0 for dwFlags is not supported\n"); + } + else + { + ok(ret, "EnumDateFormatsA(0) error %d\n", GetLastError()); + trace("%s\n", date_fmt_buf); + /* test the 1st enumerated format */ + if ((p = strchr(date_fmt_buf, '\n'))) *p = 0; + ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf)); + ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError()); + ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf); + } trace("EnumDateFormatsA LOCALE_USE_CP_ACP\n"); date_fmt_buf[0] = 0; + SetLastError(0xdeadbeef); ret = EnumDateFormatsA(enum_datetime_procA, lcid, LOCALE_USE_CP_ACP); - ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError()); - trace("%s\n", date_fmt_buf); - /* test the 1st enumerated format */ - if ((p = strchr(date_fmt_buf, '\n'))) *p = 0; - ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf)); - ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError()); - ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf); + if (!ret && (GetLastError() == ERROR_INVALID_FLAGS)) + { + win_skip("LOCALE_USE_CP_ACP is not supported\n"); + } + else + { + ok(ret, "EnumDateFormatsA(LOCALE_USE_CP_ACP) error %d\n", GetLastError()); + trace("%s\n", date_fmt_buf); + /* test the 1st enumerated format */ + if ((p = strchr(date_fmt_buf, '\n'))) *p = 0; + ret = GetLocaleInfoA(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf)); + ok(ret, "GetLocaleInfoA(LOCALE_SSHORTDATE) error %d\n", GetLastError()); + ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf); + } trace("EnumDateFormatsA DATE_SHORTDATE\n"); date_fmt_buf[0] = 0; @@ -2235,7 +2417,8 @@ static void test_EnumDateFormatsA(void) if ((p = strchr(date_fmt_buf, '\n'))) *p = 0; ret = GetLocaleInfoA(lcid, LOCALE_SYEARMONTH, buf, sizeof(buf)); ok(ret, "GetLocaleInfoA(LOCALE_SYEARMONTH) error %d\n", GetLastError()); - ok(!lstrcmpA(date_fmt_buf, buf), "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf); + ok(!lstrcmpA(date_fmt_buf, buf) || broken(!buf[0]) /* win9x */, + "expected \"%s\" got \"%s\"\n", date_fmt_buf, buf); } static void test_EnumTimeFormatsA(void) @@ -2280,21 +2463,36 @@ static void test_GetCPInfo(void) SetLastError(0xdeadbeef); ret = GetCPInfo(CP_UTF7, &cpinfo); - ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError()); - ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]); - ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]); - ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]); - ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]); - ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize); + if (!ret && GetLastError() == ERROR_INVALID_PARAMETER) + { + skip("Codepage CP_UTF7 is not installed/available\n"); + } + else + { + ok(ret, "GetCPInfo(CP_UTF7) error %u\n", GetLastError()); + ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]); + ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]); + ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]); + ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]); + ok(cpinfo.MaxCharSize == 5, "expected 5, got 0x%x\n", cpinfo.MaxCharSize); + } SetLastError(0xdeadbeef); ret = GetCPInfo(CP_UTF8, &cpinfo); - ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError()); - ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]); - ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]); - ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]); - ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]); - ok(cpinfo.MaxCharSize == 4, "expected 5, got 0x%x\n", cpinfo.MaxCharSize); + if (!ret && GetLastError() == ERROR_INVALID_PARAMETER) + { + skip("Codepage CP_UTF8 is not installed/available\n"); + } + else + { + ok(ret, "GetCPInfo(CP_UTF8) error %u\n", GetLastError()); + ok(cpinfo.DefaultChar[0] == 0x3f, "expected 0x3f, got 0x%x\n", cpinfo.DefaultChar[0]); + ok(cpinfo.DefaultChar[1] == 0, "expected 0, got 0x%x\n", cpinfo.DefaultChar[1]); + ok(cpinfo.LeadByte[0] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[0]); + ok(cpinfo.LeadByte[1] == 0, "expected 0, got 0x%x\n", cpinfo.LeadByte[1]); + ok(cpinfo.MaxCharSize == 4 || broken(cpinfo.MaxCharSize == 3) /* win9x */, + "expected 4, got %u\n", cpinfo.MaxCharSize); + } } START_TEST(locale) diff --git a/rostests/winetests/kernel32/mailslot.c b/rostests/winetests/kernel32/mailslot.c index 995f144b1a9..2cea68a40c9 100755 --- a/rostests/winetests/kernel32/mailslot.c +++ b/rostests/winetests/kernel32/mailslot.c @@ -34,6 +34,7 @@ static int mailslot_test(void) HANDLE hSlot, hSlot2, hWriter, hWriter2; unsigned char buffer[16]; DWORD count, dwMax, dwNext, dwMsgCount, dwTimeout; + BOOL ret; /* sanity check on GetMailslotInfo */ dwMax = dwNext = dwMsgCount = dwTimeout = 0; @@ -54,10 +55,13 @@ static int mailslot_test(void) /* open a mailslot with a null name */ hSlot = CreateMailslot( NULL, 0, 0, NULL ); - ok( hSlot == INVALID_HANDLE_VALUE, - "Created mailslot with invalid name\n"); - ok( GetLastError() == ERROR_PATH_NOT_FOUND, + ok( hSlot == INVALID_HANDLE_VALUE || broken(hSlot != INVALID_HANDLE_VALUE), /* win9x */ + "Created mailslot with invalid name\n"); + if (hSlot == INVALID_HANDLE_VALUE) + ok( GetLastError() == ERROR_PATH_NOT_FOUND, "error should be ERROR_PATH_NOT_FOUND\n"); + else /* succeeds on win9x */ + CloseHandle( hSlot ); /* valid open, but with wacky parameters ... then check them */ hSlot = CreateMailslot( szmspath, -1, -1, NULL ); @@ -80,32 +84,36 @@ static int mailslot_test(void) /* try and read/write to it */ count = 0; memset(buffer, 0, sizeof buffer); - ok( !ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), - "slot read\n"); - ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + ret = ReadFile( hSlot, buffer, sizeof buffer, &count, NULL); + ok( !ret || broken(ret), /* win9x */ "slot read\n"); + if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + else ok( count == 0, "wrong count %u\n", count ); ok( !WriteFile( hSlot, buffer, sizeof buffer, &count, NULL), "slot write\n"); ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\n", GetLastError() ); - /* now try and openthe client, but with the wrong sharing mode */ - hWriter = CreateFile(szmspath, GENERIC_READ|GENERIC_WRITE, + /* now try and open the client, but with the wrong sharing mode */ + hWriter = CreateFile(szmspath, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); - ok( hWriter == INVALID_HANDLE_VALUE, "bad sharing mode\n"); - ok( GetLastError() == ERROR_SHARING_VIOLATION, - "error should be ERROR_SHARING_VIOLATION\n"); + ok( hWriter != INVALID_HANDLE_VALUE /* vista */ || GetLastError() == ERROR_SHARING_VIOLATION, + "error should be ERROR_SHARING_VIOLATION got %p / %u\n", hWriter, GetLastError()); + if (hWriter != INVALID_HANDLE_VALUE) CloseHandle( hWriter ); /* now open the client with the correct sharing mode */ hWriter = CreateFile(szmspath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - ok( hWriter != INVALID_HANDLE_VALUE, "existing mailslot\n"); + if (hWriter == INVALID_HANDLE_VALUE) /* win9x doesn't like GENERIC_READ */ + hWriter = CreateFile(szmspath, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + ok( hWriter != INVALID_HANDLE_VALUE, "existing mailslot err %u\n", GetLastError()); /* * opening a client should make no difference to * whether we can read or write the mailslot */ - ok( !ReadFile( hSlot, buffer, sizeof buffer/2, &count, NULL), - "slot read\n"); - ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + ret = ReadFile( hSlot, buffer, sizeof buffer/2, &count, NULL); + ok( !ret || broken(ret), /* win9x */ "slot read\n"); + if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + else ok( count == 0, "wrong count %u\n", count ); ok( !WriteFile( hSlot, buffer, sizeof buffer/2, &count, NULL), "slot write\n"); ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\n", GetLastError() ); @@ -116,12 +124,14 @@ static int mailslot_test(void) */ ok( !ReadFile( hWriter, buffer, sizeof buffer/2, &count, NULL), "can read client\n"); - todo_wine ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_ACCESS_DENIED, + "wrong error %u\n", GetLastError() ); ok( WriteFile( hWriter, buffer, sizeof buffer/2, &count, NULL), "can't write client\n"); ok( !ReadFile( hWriter, buffer, sizeof buffer/2, &count, NULL), "can read client\n"); - todo_wine ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_ACCESS_DENIED, + "wrong error %u\n", GetLastError() ); /* * seeing as there's something in the slot, @@ -132,24 +142,28 @@ static int mailslot_test(void) ok( count == (sizeof buffer/2), "short read\n" ); /* but not again */ - ok( !ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), - "slot read\n"); - ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + ret = ReadFile( hSlot, buffer, sizeof buffer, &count, NULL); + ok( !ret || broken(ret), /* win9x */ "slot read\n"); + if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + else ok( count == 0, "wrong count %u\n", count ); /* now try open another writer... should fail */ hWriter2 = CreateFile(szmspath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - ok( hWriter2 == INVALID_HANDLE_VALUE, "two writers\n"); + /* succeeds on vista, don't test */ + if (hWriter2 != INVALID_HANDLE_VALUE) CloseHandle( hWriter2 ); /* now try open another as a reader ... also fails */ hWriter2 = CreateFile(szmspath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - ok( hWriter2 == INVALID_HANDLE_VALUE, "writer + reader\n"); + /* succeeds on vista, don't test */ + if (hWriter2 != INVALID_HANDLE_VALUE) CloseHandle( hWriter2 ); /* now try open another as a writer ... still fails */ hWriter2 = CreateFile(szmspath, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - ok( hWriter2 == INVALID_HANDLE_VALUE, "writer\n"); + /* succeeds on vista, don't test */ + if (hWriter2 != INVALID_HANDLE_VALUE) CloseHandle( hWriter2 ); /* now open another one */ hSlot2 = CreateMailslot( szmspath, 0, 0, NULL ); @@ -172,7 +186,8 @@ static int mailslot_test(void) */ hWriter2 = CreateFile(szmspath, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - ok( hWriter2 == INVALID_HANDLE_VALUE, "greedy writer succeeded\n"); + /* succeeds on vista, don't test */ + if (hWriter2 != INVALID_HANDLE_VALUE) CloseHandle( hWriter2 ); /* now try open another as a writer ... and share with the first */ hWriter2 = CreateFile(szmspath, GENERIC_WRITE, @@ -189,8 +204,10 @@ static int mailslot_test(void) ok( dwTimeout == 0, "dwTimeout incorrect\n"); /* check there's still no data */ - ok( !ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), "slot read\n"); - ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + ret = ReadFile( hSlot, buffer, sizeof buffer, &count, NULL); + ok( !ret || broken(ret), /* win9x */ "slot read\n"); + if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + else ok( count == 0, "wrong count %u\n", count ); /* write two messages */ buffer[0] = 'a'; @@ -224,9 +241,9 @@ static int mailslot_test(void) ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ), "getmailslotinfo failed\n"); ok( dwNext == 1, "dwNext incorrect\n"); - todo_wine { - ok( dwMsgCount == 3, "dwMsgCount incorrect\n"); - } + todo_wine + ok( dwMsgCount == 3 || broken(dwMsgCount == 2), /* win9x */ + "dwMsgCount incorrect %u\n", dwMsgCount); buffer[0]=buffer[1]=0; @@ -245,7 +262,8 @@ static int mailslot_test(void) "getmailslotinfo failed\n"); ok( dwNext == 2, "dwNext incorrect\n"); todo_wine { - ok( dwMsgCount == 2, "dwMsgCount incorrect\n"); + ok( dwMsgCount == 2 || broken(dwMsgCount == 1), /* win9x */ + "dwMsgCount incorrect %u\n", dwMsgCount); } /* read the second message */ @@ -258,9 +276,10 @@ static int mailslot_test(void) dwNext = dwMsgCount = 0; ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ), "getmailslotinfo failed\n"); - ok( dwNext == 0, "dwNext incorrect\n"); + ok( dwNext == 0 || broken(dwNext == ~0u), /* win9x */ "dwNext incorrect %u\n", dwNext); todo_wine { - ok( dwMsgCount == 1, "dwMsgCount incorrect\n"); + ok( dwMsgCount == 1 || broken(dwMsgCount == 0), /* win9x */ + "dwMsgCount incorrect %u\n", dwMsgCount); } /* read the 3rd (zero length) message */ @@ -281,9 +300,10 @@ static int mailslot_test(void) ok( dwMsgCount == 0, "dwMsgCount incorrect\n"); /* check that reads fail */ - ok( !ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), - "3rd slot read succeeded\n"); - ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + ret = ReadFile( hSlot, buffer, sizeof buffer, &count, NULL); + ok( !ret || broken(ret), /* win9x */ "3rd slot read succeeded\n"); + if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + else ok( count == 0, "wrong count %u\n", count ); /* finally close the mailslot and its client */ ok( CloseHandle( hWriter2 ), "closing 2nd client\n"); @@ -297,7 +317,8 @@ static int mailslot_test(void) memset(buffer, 0, sizeof buffer); dwTimeout = GetTickCount(); ok( !ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), "slot read\n"); - ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %u\n", GetLastError() ); + ok( GetLastError() == ERROR_SEM_TIMEOUT || broken(GetLastError() == ERROR_ACCESS_DENIED), /* win9x */ + "wrong error %u\n", GetLastError() ); dwTimeout = GetTickCount() - dwTimeout; ok( dwTimeout >= 990, "timeout too short %u\n", dwTimeout ); ok( CloseHandle( hSlot ), "closing the mailslot\n"); diff --git a/rostests/winetests/kernel32/module.c b/rostests/winetests/kernel32/module.c index f524be70d56..73d7946cdd6 100755 --- a/rostests/winetests/kernel32/module.c +++ b/rostests/winetests/kernel32/module.c @@ -216,6 +216,123 @@ static void testGetProcAddress_Wrong(void) "Expected ERROR_MOD_NOT_FOUND or ERROR_INVALID_HANDLE(win9x), got %d\n", GetLastError()); } +static void testLoadLibraryEx(void) +{ + CHAR path[MAX_PATH]; + HMODULE hmodule; + HANDLE hfile; + + hfile = CreateFileA("testfile.dll", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + ok(hfile != INVALID_HANDLE_VALUE, "Expected a valid file handle\n"); + + /* NULL lpFileName */ + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA(NULL, NULL, 0); + ok(hmodule == 0, "Expected 0, got %p\n", hmodule); + ok(GetLastError() == ERROR_MOD_NOT_FOUND || + GetLastError() == ERROR_INVALID_PARAMETER, /* win9x */ + "Expected ERROR_MOD_NOT_FOUND or ERROR_INVALID_PARAMETER, got %d\n", + GetLastError()); + + /* empty lpFileName */ + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA("", NULL, 0); + ok(hmodule == 0, "Expected 0, got %p\n", hmodule); + ok(GetLastError() == ERROR_MOD_NOT_FOUND || + GetLastError() == ERROR_DLL_NOT_FOUND, /* win9x */ + "Expected ERROR_MOD_NOT_FOUND or ERROR_DLL_NOT_FOUND, got %d\n", + GetLastError()); + + /* hFile is non-NULL */ + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA("testfile.dll", hfile, 0); + ok(hmodule == 0, "Expected 0, got %p\n", hmodule); + ok(GetLastError() == ERROR_SHARING_VIOLATION || + GetLastError() == ERROR_INVALID_PARAMETER || /* win2k3 */ + GetLastError() == ERROR_FILE_NOT_FOUND, /* win9x */ + "Unexpected last error, got %d\n", GetLastError()); + + /* try to open a file that is locked */ + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA("testfile.dll", NULL, 0); + ok(hmodule == 0, "Expected 0, got %p\n", hmodule); + todo_wine + { + ok(GetLastError() == ERROR_SHARING_VIOLATION || + GetLastError() == ERROR_FILE_NOT_FOUND, /* win9x */ + "Expected ERROR_SHARING_VIOLATION or ERROR_FILE_NOT_FOUND, got %d\n", + GetLastError()); + } + + /* lpFileName does not matter */ + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA(NULL, hfile, 0); + ok(hmodule == 0, "Expected 0, got %p\n", hmodule); + ok(GetLastError() == ERROR_MOD_NOT_FOUND || + GetLastError() == ERROR_INVALID_PARAMETER, /* win2k3 */ + "Expected ERROR_MOD_NOT_FOUND or ERROR_INVALID_PARAMETER, got %d\n", + GetLastError()); + + CloseHandle(hfile); + + /* load empty file */ + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA("testfile.dll", NULL, LOAD_LIBRARY_AS_DATAFILE); + ok(hmodule == 0, "Expected 0, got %p\n", hmodule); + todo_wine + { + ok(GetLastError() == ERROR_FILE_INVALID || + GetLastError() == ERROR_BAD_FORMAT, /* win9x */ + "Expected ERROR_FILE_INVALID or ERROR_BAD_FORMAT, got %d\n", + GetLastError()); + } + + DeleteFileA("testfile.dll"); + + GetSystemDirectoryA(path, MAX_PATH); + if (path[lstrlenA(path) - 1] != '\\') + lstrcatA(path, "\\"); + lstrcatA(path, "kernel32.dll"); + + /* load kernel32.dll with an absolute path */ + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA(path, NULL, LOAD_LIBRARY_AS_DATAFILE); + ok(hmodule != 0, "Expected valid module handle\n"); + ok(GetLastError() == 0xdeadbeef || + GetLastError() == ERROR_SUCCESS, /* win9x */ + "Expected 0xdeadbeef or ERROR_SUCCESS, got %d\n", GetLastError()); + + CloseHandle(hmodule); + + /* load kernel32.dll with no path */ + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA("kernel32.dll", NULL, LOAD_LIBRARY_AS_DATAFILE); + ok(hmodule != 0, "Expected valid module handle\n"); + ok(GetLastError() == 0xdeadbeef || + GetLastError() == ERROR_SUCCESS, /* win9x */ + "Expected 0xdeadbeef or ERROR_SUCCESS, got %d\n", GetLastError()); + + CloseHandle(hmodule); + + GetCurrentDirectoryA(MAX_PATH, path); + if (path[lstrlenA(path) - 1] != '\\') + lstrcatA(path, "\\"); + lstrcatA(path, "kernel32.dll"); + + /* load kernel32.dll with an absolute path that does not exist */ + SetLastError(0xdeadbeef); + hmodule = LoadLibraryExA(path, NULL, LOAD_LIBRARY_AS_DATAFILE); + todo_wine + { + ok(hmodule == 0, "Expected 0, got %p\n", hmodule); + } + ok(GetLastError() == ERROR_FILE_NOT_FOUND || + broken(GetLastError() == ERROR_INVALID_HANDLE), /* nt4 */ + "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); +} + START_TEST(module) { WCHAR filenameW[MAX_PATH]; @@ -226,7 +343,7 @@ START_TEST(module) GetModuleFileNameW(NULL, filenameW, MAX_PATH); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - trace("GetModuleFileNameW not existing on this platform, skipping W-calls\n"); + win_skip("GetModuleFileNameW not existing on this platform, skipping W-calls\n"); is_unicode_enabled = FALSE; } @@ -238,4 +355,5 @@ START_TEST(module) testNestedLoadLibraryA(); testLoadLibraryA_Wrong(); testGetProcAddress_Wrong(); + testLoadLibraryEx(); } diff --git a/rostests/winetests/kernel32/path.c b/rostests/winetests/kernel32/path.c index d158df1dbcc..e8e6c1e1ce1 100755 --- a/rostests/winetests/kernel32/path.c +++ b/rostests/winetests/kernel32/path.c @@ -465,6 +465,14 @@ static void test_CurrentDirectoryA(CHAR *origdir, CHAR *newdir) /* starting with a '.' */ sprintf(tmpstr,".\\%s",LONGDIR); test_setdir(newdir,tmpstr,tmpstr1,1,"check 9"); +/* change to root without a trailing backslash. The function call succeeds + but the directory is not changed. +*/ + strcpy(tmpstr,"C:"); + test_setdir(newdir,tmpstr,newdir,1,"check 10"); +/* works however with a trailing backslash */ + strcpy(tmpstr,"C:\\"); + test_setdir(newdir,tmpstr,NULL,1,"check 11"); } /* Cleanup the mess we made while executing these tests */ diff --git a/rostests/winetests/kernel32/pipe.c b/rostests/winetests/kernel32/pipe.c index 8fcf4157615..a4b6853317a 100755 --- a/rostests/winetests/kernel32/pipe.c +++ b/rostests/winetests/kernel32/pipe.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -713,14 +712,17 @@ static int test_DisconnectNamedPipe(void) DWORD written; DWORD readden; + SetLastError(0xdeadbeef); hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT, /* nMaxInstances */ 1, /* nOutBufSize */ 1024, /* nInBufSize */ 1024, /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT, /* lpSecurityAttrib */ NULL); - if (INVALID_HANDLE_VALUE == hnp) { - trace ("Seems we have no named pipes.\n"); + if ((hnp == INVALID_HANDLE_VALUE /* Win98 */ || !hnp /* Win95 */) + && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { + + win_skip("Named pipes are not implemented\n"); return 1; } @@ -793,7 +795,7 @@ static void test_CreatePipe(void) size = 32768; buffer = HeapAlloc( GetProcessHeap(), 0, size ); for (i = 0; i < size; i++) buffer[i] = i; - ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, size) != 0, "CreatePipe failed\n"); + ok(CreatePipe(&piperead, &pipewrite, &pipe_attr, (size + 24)) != 0, "CreatePipe failed\n"); ok(WriteFile(pipewrite, buffer, size, &written, NULL), "Write to anonymous pipe failed\n"); ok(written == size, "Write to anonymous pipe wrote %d bytes\n", written); /* and close the write end, read should still succeed*/ @@ -952,8 +954,8 @@ static void test_ImpersonateNamedPipeClient(HANDLE hClientToken, DWORD security_ SetLastError(0xdeadbeef); ret = ImpersonateNamedPipeClient(hPipeServer); error = GetLastError(); - todo_wine - ok(!ret && (error == ERROR_CANNOT_IMPERSONATE), "ImpersonateNamedPipeClient should have failed with ERROR_CANNOT_IMPERSONATE instead of %d\n", GetLastError()); + ok(ret /* win2k3 */ || (error == ERROR_CANNOT_IMPERSONATE), + "ImpersonateNamedPipeClient should have failed with ERROR_CANNOT_IMPERSONATE instead of %d\n", GetLastError()); ret = ConnectNamedPipe(hPipeServer, NULL); ok(ret || (GetLastError() == ERROR_PIPE_CONNECTED), "ConnectNamedPipe failed with error %d\n", GetLastError()); @@ -1325,9 +1327,6 @@ START_TEST(pipe) { HMODULE hmod; - skip("ROS-HACK: Skipping pipe tests -- ros' npfs is in a sorry state\n"); - return; - hmod = GetModuleHandle("advapi32.dll"); pDuplicateTokenEx = (void *) GetProcAddress(hmod, "DuplicateTokenEx"); diff --git a/rostests/winetests/kernel32/process.c b/rostests/winetests/kernel32/process.c index d7db6c76d2b..0568b527e03 100755 --- a/rostests/winetests/kernel32/process.c +++ b/rostests/winetests/kernel32/process.c @@ -24,12 +24,16 @@ #include #include -#include "wine/test.h" +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "winuser.h" #include "wincon.h" #include "winnls.h" +#include "winternl.h" + +#include "wine/test.h" static HINSTANCE hkernel32; static LPVOID (WINAPI *pVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD); @@ -124,7 +128,6 @@ static char* decodeA(const char* str) return ptr; } -#if 0 /* This will be needed to decode Unicode strings saved by the child process * when we test Unicode functions. */ @@ -145,7 +148,6 @@ static WCHAR* decodeW(const char* str) ptr[len] = '\0'; return ptr; } -#endif /****************************************************************** * init @@ -348,8 +350,18 @@ static void doChild(const char* file, const char* option) childPrintf(hFile, "OutputMode=%ld\n", modeOut); /* now that we have written all relevant information, let's change it */ - ok(SetConsoleCP(1252), "Setting CP\n"); - ok(SetConsoleOutputCP(1252), "Setting SB CP\n"); + SetLastError(0xdeadbeef); + ret = SetConsoleCP(1252); + if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("Setting the codepage is not implemented"); + } + else + { + ok(ret, "Setting CP\n"); + ok(SetConsoleOutputCP(1252), "Setting SB CP\n"); + } + ret = SetConsoleMode(hConIn, modeIn ^ 1); ok( ret, "Setting mode (%d)\n", GetLastError()); ret = SetConsoleMode(hConOut, modeOut ^ 1); @@ -397,6 +409,18 @@ static char* getChildString(const char* sect, const char* key) return ret; } +static WCHAR* getChildStringW(const char* sect, const char* key) +{ + char buf[1024+4*MAX_LISTED_ENV_VAR]; + WCHAR* ret; + + GetPrivateProfileStringA(sect, key, "-", buf, sizeof(buf), resfile); + if (buf[0] == '\0' || (buf[0] == '-' && buf[1] == '\0')) return NULL; + assert(!(strlen(buf) & 1)); + ret = decodeW(buf); + return ret; +} + /* FIXME: this may be moved to the wtmain.c file, because it may be needed by * others... (windows uses stricmp while Un*x uses strcasecmp...) */ @@ -432,8 +456,35 @@ static void ok_child_string( int line, const char *sect, const char *key, sect, key, expect ? expect : "(null)", result ); } +static void ok_child_stringWA( int line, const char *sect, const char *key, + const char *expect, int sensitive ) +{ + WCHAR* expectW; + CHAR* resultA; + DWORD len; + WCHAR* result = getChildStringW( sect, key ); + + len = MultiByteToWideChar( CP_ACP, 0, expect, -1, NULL, 0); + expectW = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); + MultiByteToWideChar( CP_ACP, 0, expect, -1, expectW, len); + + len = WideCharToMultiByte( CP_ACP, 0, result, -1, NULL, 0, NULL, NULL); + resultA = HeapAlloc(GetProcessHeap(),0,len*sizeof(CHAR)); + WideCharToMultiByte( CP_ACP, 0, result, -1, resultA, len, NULL, NULL); + + if (sensitive) + ok_(__FILE__, line)( lstrcmpW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n", + sect, key, expect ? expect : "(null)", resultA ); + else + ok_(__FILE__, line)( lstrcmpiW(result, expectW) == 0, "%s:%s expected '%s', got '%s'\n", + sect, key, expect ? expect : "(null)", resultA ); + HeapFree(GetProcessHeap(),0,expectW); + HeapFree(GetProcessHeap(),0,resultA); +} + #define okChildString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 1 ) #define okChildIString(sect, key, expect) ok_child_string(__LINE__, (sect), (key), (expect), 0 ) +#define okChildStringWA(sect, key, expect) ok_child_stringWA(__LINE__, (sect), (key), (expect), 1 ) /* using !expect ensures that the test will fail if the sect/key isn't present * in result file @@ -450,7 +501,7 @@ static void test_Startup(void) PROCESS_INFORMATION info; STARTUPINFOA startup,si; static CHAR title[] = "I'm the title string", - desktop[] = "I'm the desktop string", + desktop[] = "winsta0\\default", empty[] = ""; /* let's start simplistic */ @@ -470,8 +521,6 @@ static void test_Startup(void) GetStartupInfoA(&si); okChildInt("StartupInfoA", "cb", startup.cb); okChildString("StartupInfoA", "lpDesktop", si.lpDesktop); - ok (si.lpTitle == NULL || !strncmp(si.lpTitle, selfname, strlen(selfname)), - "StartupInfoA:lpTitle expected something starting with '%s' or null, got '%s'\n", selfname, si.lpTitle); okChildInt("StartupInfoA", "dwX", startup.dwX); okChildInt("StartupInfoA", "dwY", startup.dwY); okChildInt("StartupInfoA", "dwXSize", startup.dwXSize); @@ -719,6 +768,7 @@ static void test_Startup(void) static void test_CommandLine(void) { char buffer[MAX_PATH], fullpath[MAX_PATH], *lpFilePart, *p; + char buffer2[MAX_PATH]; PROCESS_INFORMATION info; STARTUPINFOA startup; DWORD len; @@ -804,9 +854,9 @@ static void test_CommandLine(void) assert ( lpFilePart != 0); *(lpFilePart -1 ) = 0; p = strrchr(fullpath, '\\'); - assert (p); /* Use exename to avoid buffer containing things like 'C:' */ - sprintf(buffer, "..%s/%s tests/process.c %s \"a\\\"b\\\\\" c\\\" d", p, exename, resfile); + if (p) sprintf(buffer, "..%s/%s tests/process.c %s \"a\\\"b\\\\\" c\\\" d", p, exename, resfile); + else sprintf(buffer, "./%s tests/process.c %s \"a\\\"b\\\\\" c\\\" d", exename, resfile); SetLastError(0xdeadbeef); ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError()); @@ -814,11 +864,35 @@ static void test_CommandLine(void) ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); /* child process has changed result file, so let profile functions know about it */ WritePrivateProfileStringA(NULL, NULL, NULL, resfile); - sprintf(buffer, "..%s/%s", p, exename); + if (p) sprintf(buffer, "..%s/%s", p, exename); + else sprintf(buffer, "./%s", exename); okChildString("Arguments", "argvA0", buffer); release_memory(); assert(DeleteFileA(resfile) != 0); - + + /* Using AppName */ + get_file_name(resfile); + len = GetFullPathNameA(selfname, MAX_PATH, fullpath, &lpFilePart); + assert ( lpFilePart != 0); + *(lpFilePart -1 ) = 0; + p = strrchr(fullpath, '\\'); + /* Use exename to avoid buffer containing things like 'C:' */ + if (p) sprintf(buffer, "..%s/%s", p, exename); + else sprintf(buffer, "./%s", exename); + sprintf(buffer2, "dummy tests/process.c %s \"a\\\"b\\\\\" c\\\" d", resfile); + SetLastError(0xdeadbeef); + ret = CreateProcessA(buffer, buffer2, NULL, NULL, FALSE, 0L, NULL, NULL, &startup, &info); + ok(ret, "CreateProcess (%s) failed : %d\n", buffer, GetLastError()); + /* wait for child to terminate */ + ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0, "Child process termination\n"); + /* child process has changed result file, so let profile functions know about it */ + WritePrivateProfileStringA(NULL, NULL, NULL, resfile); + sprintf(buffer, "tests/process.c %s", resfile); + okChildString("Arguments", "argvA0", "dummy"); + okChildString("Arguments", "CommandLineA", buffer2); + okChildStringWA("Arguments", "CommandLineW", buffer2); + release_memory(); + assert(DeleteFileA(resfile) != 0); } static void test_Directory(void) @@ -1127,9 +1201,7 @@ static void test_Console(void) HANDLE hChildIn, hChildInInh, hChildOut, hChildOutInh, hParentIn, hParentOut; const char* msg = "This is a std-handle inheritance test."; unsigned msg_len; - - skip("ROS-HACK: Skipping process console tests\n"); - return; + BOOL run_tests = TRUE; memset(&startup, 0, sizeof(startup)); startup.cb = sizeof(startup); @@ -1185,13 +1257,18 @@ static void test_Console(void) /* Try to set invalid CP */ SetLastError(0xdeadbeef); ok(!SetConsoleCP(0), "Shouldn't succeed\n"); - ok(GetLastError()==ERROR_INVALID_PARAMETER, + ok(GetLastError()==ERROR_INVALID_PARAMETER || + broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */ "GetLastError: expecting %u got %u\n", ERROR_INVALID_PARAMETER, GetLastError()); + if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + run_tests = FALSE; + SetLastError(0xdeadbeef); ok(!SetConsoleOutputCP(0), "Shouldn't succeed\n"); - ok(GetLastError()==ERROR_INVALID_PARAMETER, + ok(GetLastError()==ERROR_INVALID_PARAMETER || + broken(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), /* win9x */ "GetLastError: expecting %u got %u\n", ERROR_INVALID_PARAMETER, GetLastError()); @@ -1234,8 +1311,14 @@ static void test_Console(void) okChildInt("Console", "InputMode", modeIn); okChildInt("Console", "OutputMode", modeOut); - ok(cpInC == 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC, cpIn); - ok(cpOutC == 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC, cpOut); + if (run_tests) + { + ok(cpInC == 1252, "Wrong console CP (expected 1252 got %d/%d)\n", cpInC, cpIn); + ok(cpOutC == 1252, "Wrong console-SB CP (expected 1252 got %d/%d)\n", cpOutC, cpOut); + } + else + win_skip("Setting the codepage is not implemented\n"); + ok(modeInC == (modeIn ^ 1), "Wrong console mode\n"); ok(modeOutC == (modeOut ^ 1), "Wrong console-SB mode\n"); trace("cursor position(X): %d/%d\n",sbi.dwCursorPosition.X, sbiC.dwCursorPosition.X); @@ -1402,6 +1485,73 @@ static void test_OpenProcess(void) ok(VirtualFree(addr1, 0, MEM_RELEASE), "VirtualFree failed\n"); } +static void test_GetProcessVersion(void) +{ + static char cmdline[] = "winver.exe"; + PROCESS_INFORMATION pi; + STARTUPINFOA si; + DWORD ret; + + SetLastError(0xdeadbeef); + ret = GetProcessVersion(0); + ok(ret, "GetProcessVersion error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = GetProcessVersion(GetCurrentProcessId()); + ok(ret, "GetProcessVersion error %u\n", GetLastError()); + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags = STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; + ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + SetLastError(0xdeadbeef); + ok(ret, "CreateProcess error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = GetProcessVersion(pi.dwProcessId); + ok(ret, "GetProcessVersion error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = TerminateProcess(pi.hProcess, 0); + ok(ret, "TerminateProcess error %u\n", GetLastError()); + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); +} + +static void test_Handles(void) +{ + HANDLE handle = GetCurrentProcess(); + BOOL ret; + DWORD code; + + ok( handle == (HANDLE)~(ULONG_PTR)0 || + handle == (HANDLE)(ULONG_PTR)0x7fffffff /* win9x */, + "invalid current process handle %p\n", handle ); + ret = GetExitCodeProcess( handle, &code ); + ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() ); +#ifdef _WIN64 + /* truncated handle */ + SetLastError( 0xdeadbeef ); + handle = (HANDLE)((ULONG_PTR)handle & ~0u); + ret = GetExitCodeProcess( handle, &code ); + ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() ); + /* sign-extended handle */ + SetLastError( 0xdeadbeef ); + handle = (HANDLE)((LONG_PTR)(int)(ULONG_PTR)handle); + ret = GetExitCodeProcess( handle, &code ); + ok( ret, "GetExitCodeProcess failed err %u\n", GetLastError() ); + /* invalid high-word */ + SetLastError( 0xdeadbeef ); + handle = (HANDLE)(((ULONG_PTR)handle & ~0u) + ((ULONG_PTR)1 << 32)); + ret = GetExitCodeProcess( handle, &code ); + ok( !ret, "GetExitCodeProcess succeeded for %p\n", handle ); + ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() ); +#endif +} + START_TEST(process) { int b = init(); @@ -1422,6 +1572,8 @@ START_TEST(process) test_Console(); test_ExitCode(); test_OpenProcess(); + test_GetProcessVersion(); + test_Handles(); /* things that can be tested: * lookup: check the way program to be executed is searched * handles: check the handle inheritance stuff (+sec options) diff --git a/rostests/winetests/kernel32/profile.c b/rostests/winetests/kernel32/profile.c index 8611c114594..3cd8af13712 100755 --- a/rostests/winetests/kernel32/profile.c +++ b/rostests/winetests/kernel32/profile.c @@ -19,6 +19,7 @@ */ #include +#include #include "wine/test.h" #include "windef.h" @@ -182,13 +183,14 @@ static void test_profile_sections(void) ok( GetLastError() == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError()); /* And a real one */ + SetLastError(0xdeadbeef); ret=GetPrivateProfileSectionA("section1", buf, sizeof(buf), testfile4); for( p = buf + strlen(buf) + 1; *p;p += strlen(p)+1) p[-1] = ','; ok( ret == 35 && !strcmp( buf, "name1=val1,name2=,name3,name4=val4"), "wrong section returned(%d): %s\n", ret, buf); ok( buf[ret-1] == 0 && buf[ret] == 0, "returned buffer not terminated with double-null\n" ); - ok( GetLastError() == S_OK, "expected S_OK, got %d\n", GetLastError()); + ok( GetLastError() == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", GetLastError()); DeleteFileA( testfile4 ); } @@ -266,10 +268,456 @@ static void test_profile_sections_names(void) ok( bufW[1] != 0, "returned buffer terminated with double-null\n" ); } +/* If the ini-file has already been opened with CreateFile, WritePrivateProfileString failed in wine with an error ERROR_SHARING_VIOLATION, some testing here */ +static void test_profile_existing(void) +{ + static const char *testfile1 = ".\\winesharing1.ini"; + static const char *testfile2 = ".\\winesharing2.ini"; + + static const struct { + DWORD dwDesiredAccess; + DWORD dwShareMode; + DWORD write_error; + BOOL read_error; + DWORD broken_error; + } pe[] = { + {GENERIC_READ, FILE_SHARE_READ, ERROR_SHARING_VIOLATION, FALSE }, + {GENERIC_READ, FILE_SHARE_WRITE, ERROR_SHARING_VIOLATION, TRUE }, + {GENERIC_WRITE, FILE_SHARE_READ, ERROR_SHARING_VIOLATION, FALSE }, + {GENERIC_WRITE, FILE_SHARE_WRITE, ERROR_SHARING_VIOLATION, TRUE }, + {GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, ERROR_SHARING_VIOLATION, FALSE }, + {GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE, ERROR_SHARING_VIOLATION, TRUE }, + {GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, FALSE, ERROR_SHARING_VIOLATION /* nt4 */}, + {GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, FALSE, ERROR_SHARING_VIOLATION /* nt4 */}, + /*Thief demo (bug 5024) opens .ini file like this*/ + {GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, FALSE, ERROR_SHARING_VIOLATION /* nt4 */} + }; + + int i; + BOOL ret; + DWORD size; + HANDLE h = 0; + char buffer[MAX_PATH]; + + for (i=0; i < sizeof(pe)/sizeof(pe[0]); i++) + { + h = CreateFile(testfile1, pe[i].dwDesiredAccess, pe[i].dwShareMode, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + ok(INVALID_HANDLE_VALUE != h, "%d: CreateFile failed\n",i); + SetLastError(0xdeadbeef); + + ret = WritePrivateProfileString(SECTION, KEY, "12345", testfile1); + if (!pe[i].write_error) + { + if (!ret) + ok( broken(GetLastError() == pe[i].broken_error), + "%d: WritePrivateProfileString failed with error %u\n", i, GetLastError() ); + CloseHandle(h); + size = GetPrivateProfileString(SECTION, KEY, 0, buffer, MAX_PATH, testfile1); + if (ret) + ok( size == 5, "%d: test failed, number of characters copied: %d instead of 5\n", i, size ); + else + ok( !size, "%d: test failed, number of characters copied: %d instead of 0\n", i, size ); + } + else + { + DWORD err = GetLastError(); + ok( !ret, "%d: WritePrivateProfileString succeeded\n", i ); + if (!ret) + ok( err == pe[i].write_error, "%d: WritePrivateProfileString failed with error %u/%u\n", + i, err, pe[i].write_error ); + CloseHandle(h); + size = GetPrivateProfileString(SECTION, KEY, 0, buffer, MAX_PATH, testfile1); + ok( !size, "%d: test failed, number of characters copied: %d instead of 0\n", i, size ); + } + + ok( DeleteFile(testfile1), "delete failed\n" ); + } + + h = CreateFile(testfile2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + sprintf( buffer, "[%s]\r\n%s=123\r\n", SECTION, KEY ); + ok( WriteFile( h, buffer, strlen(buffer), &size, NULL ), "failed to write\n" ); + CloseHandle( h ); + + for (i=0; i < sizeof(pe)/sizeof(pe[0]); i++) + { + h = CreateFile(testfile2, pe[i].dwDesiredAccess, pe[i].dwShareMode, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + ok(INVALID_HANDLE_VALUE != h, "%d: CreateFile failed\n",i); + SetLastError(0xdeadbeef); + ret = GetPrivateProfileStringA(SECTION, KEY, NULL, buffer, MAX_PATH, testfile2); + if (!pe[i].read_error) + ok( ret, "%d: GetPrivateProfileString failed with error %u\n", i, GetLastError() ); + else + ok( !ret, "%d: GetPrivateProfileString succeeded\n", i ); + CloseHandle(h); + } + ok( DeleteFile(testfile2), "delete failed\n" ); +} + +static void test_profile_delete_on_close() +{ + static CHAR testfile[] = ".\\testwine5.ini"; + HANDLE h; + DWORD size, res; + static const char contents[] = "[" SECTION "]\n" KEY "=123\n"; + + h = CreateFile(testfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, + CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); + ok( WriteFile( h, contents, sizeof contents - 1, &size, NULL ), + "Cannot write test file: %x\n", GetLastError() ); + ok( size == sizeof contents - 1, "Test file: partial write\n"); + + res = GetPrivateProfileInt(SECTION, KEY, 0, testfile); + ok( res == 123, "Got %d instead of 123\n", res); + + /* This also deletes the file */ + CloseHandle(h); +} + +static void test_profile_refresh(void) +{ + static CHAR testfile[] = ".\\winetest4.ini"; + HANDLE h; + DWORD size, res; + static const char contents1[] = "[" SECTION "]\n" KEY "=123\n"; + static const char contents2[] = "[" SECTION "]\n" KEY "=124\n"; + + h = CreateFile(testfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, + CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); + ok( WriteFile( h, contents1, sizeof contents1 - 1, &size, NULL ), + "Cannot write test file: %x\n", GetLastError() ); + ok( size == sizeof contents1 - 1, "Test file: partial write\n"); + + res = GetPrivateProfileInt(SECTION, KEY, 0, testfile); + ok( res == 123, "Got %d instead of 123\n", res); + + CloseHandle(h); + + /* Test proper invalidation of wine's profile file cache */ + + h = CreateFile(testfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, + CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL); + ok( WriteFile( h, contents2, sizeof contents2 - 1, &size, NULL ), + "Cannot write test file: %x\n", GetLastError() ); + ok( size == sizeof contents2 - 1, "Test file: partial write\n"); + + res = GetPrivateProfileInt(SECTION, KEY, 0, testfile); + ok( res == 124, "Got %d instead of 124\n", res); + + /* This also deletes the file */ + CloseHandle(h); +} + +static void create_test_file(LPCSTR name, LPCSTR data, DWORD size) +{ + HANDLE hfile; + DWORD count; + + hfile = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + ok(hfile != INVALID_HANDLE_VALUE, "cannot create %s\n", name); + WriteFile(hfile, data, size, &count, NULL); + CloseHandle(hfile); +} + +static BOOL emptystr_ok(CHAR emptystr[MAX_PATH]) +{ + int i; + + for(i = 0;i < MAX_PATH;++i) + if(emptystr[i] != 0) + { + trace("emptystr[%d] = %d\n",i,emptystr[i]); + return FALSE; + } + + return TRUE; +} + +static void test_GetPrivateProfileString(const char *content, const char *descript) +{ + DWORD ret; + CHAR buf[MAX_PATH]; + CHAR def_val[MAX_PATH]; + CHAR path[MAX_PATH]; + CHAR windir[MAX_PATH]; + /* NT series crashes on r/o empty strings, so pass an r/w + empty string and check for modification */ + CHAR emptystr[MAX_PATH] = ""; + LPSTR tempfile; + + static const char filename[] = ".\\winetest.ini"; + + trace("test_GetPrivateProfileStringA: %s\n", descript); + + create_test_file(filename, content, lstrlenA(content)); + + /* Run this test series with caching. Wine won't cache profile + files younger than 2.1 seconds. */ + Sleep(2500); + + /* lpAppName is NULL */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA(NULL, "name1", "default", + buf, MAX_PATH, filename); + ok(ret == 18, "Expected 18, got %d\n", ret); + ok(!memcmp(buf, "section1\0section2\0", ret + 1), + "Expected \"section1\\0section2\\0\", got \"%s\"\n", buf); + + /* lpAppName is empty */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA(emptystr, "name1", "default", + buf, MAX_PATH, filename); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "AppName modified\n"); + + /* lpAppName is missing */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("notasection", "name1", "default", + buf, MAX_PATH, filename); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); + + /* lpAppName is empty, lpDefault is NULL */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA(emptystr, "name1", NULL, + buf, MAX_PATH, filename); + ok(ret == 0, "Expected 0, got %d\n", ret); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "AppName modified\n"); + + /* lpAppName is empty, lpDefault is empty */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA(emptystr, "name1", "", + buf, MAX_PATH, filename); + ok(ret == 0, "Expected 0, got %d\n", ret); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "AppName modified\n"); + + /* lpAppName is empty, lpDefault has trailing blank characters */ + lstrcpyA(buf, "kumquat"); + /* lpDefault must be writable (trailing blanks are removed inplace in win9x) */ + lstrcpyA(def_val, "default "); + ret = GetPrivateProfileStringA(emptystr, "name1", def_val, + buf, MAX_PATH, filename); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "AppName modified\n"); + + /* lpAppName is empty, many blank characters in lpDefault */ + lstrcpyA(buf, "kumquat"); + /* lpDefault must be writable (trailing blanks are removed inplace in win9x) */ + lstrcpyA(def_val, "one two "); + ret = GetPrivateProfileStringA(emptystr, "name1", def_val, + buf, MAX_PATH, filename); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "one two"), "Expected \"one two\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "AppName modified\n"); + + /* lpAppName is empty, blank character but not trailing in lpDefault */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA(emptystr, "name1", "one two", + buf, MAX_PATH, filename); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "one two"), "Expected \"one two\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "AppName modified\n"); + + /* lpKeyName is NULL */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", NULL, "default", + buf, MAX_PATH, filename); + ok(ret == 18, "Expected 18, got %d\n", ret); + ok(!memcmp(buf, "name1\0name2\0name4\0", ret + 1), + "Expected \"name1\\0name2\\0name4\\0\", got \"%s\"\n", buf); + + /* lpKeyName is empty */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", emptystr, "default", + buf, MAX_PATH, filename); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "KeyName modified\n"); + + /* lpKeyName is missing */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "notakey", "default", + buf, MAX_PATH, filename); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); + + /* lpKeyName is empty, lpDefault is NULL */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", emptystr, NULL, + buf, MAX_PATH, filename); + ok(ret == 0, "Expected 0, got %d\n", ret); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "KeyName modified\n"); + + /* lpKeyName is empty, lpDefault is empty */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", emptystr, "", + buf, MAX_PATH, filename); + ok(ret == 0, "Expected 0, got %d\n", ret); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "KeyName modified\n"); + + /* lpKeyName is empty, lpDefault has trailing blank characters */ + lstrcpyA(buf, "kumquat"); + /* lpDefault must be writable (trailing blanks are removed inplace in win9x) */ + lstrcpyA(def_val, "default "); + ret = GetPrivateProfileStringA("section1", emptystr, def_val, + buf, MAX_PATH, filename); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); + ok(emptystr_ok(emptystr), "KeyName modified\n"); + + if (0) /* crashes */ + { + /* lpReturnedString is NULL */ + ret = GetPrivateProfileStringA("section1", "name1", "default", + NULL, MAX_PATH, filename); + } + + /* lpFileName is NULL */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name1", "default", + buf, MAX_PATH, NULL); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); + + /* lpFileName is empty */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name1", "default", + buf, MAX_PATH, ""); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); + + /* lpFileName is nonexistent */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name1", "default", + buf, MAX_PATH, "nonexistent"); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); + + /* nSize is 0 */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name1", "default", + buf, 0, filename); + ok(ret == 0, "Expected 0, got %d\n", ret); + ok(!lstrcmpA(buf, "kumquat"), "Expected buf to be unchanged, got \"%s\"\n", buf); + + /* nSize is exact size of output */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name1", "default", + buf, 4, filename); + ok(ret == 3, "Expected 3, got %d\n", ret); + ok(!lstrcmpA(buf, "val"), "Expected \"val\", got \"%s\"\n", buf); + + /* nSize has room for NULL terminator */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name1", "default", + buf, 5, filename); + ok(ret == 4, "Expected 4, got %d\n", ret); + ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf); + + /* output is 1 character */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name4", "default", + buf, MAX_PATH, filename); + ok(ret == 1, "Expected 1, got %d\n", ret); + ok(!lstrcmpA(buf, "a"), "Expected \"a\", got \"%s\"\n", buf); + + /* output is 1 character, no room for NULL terminator */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name4", "default", + buf, 1, filename); + ok(ret == 0, "Expected 0, got %d\n", ret); + ok(!lstrcmpA(buf, ""), "Expected \"\", got \"%s\"\n", buf); + + /* lpAppName is NULL, not enough room for final section name */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA(NULL, "name1", "default", + buf, 16, filename); + ok(ret == 14, "Expected 14, got %d\n", ret); + ok(!memcmp(buf, "section1\0secti\0", ret + 1), + "Expected \"section1\\0secti\\0\", got \"%s\"\n", buf); + + /* lpKeyName is NULL, not enough room for final key name */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", NULL, "default", + buf, 16, filename); + ok(ret == 14, "Expected 14, got %d\n", ret); + ok(!memcmp(buf, "name1\0name2\0na\0", ret + 1), + "Expected \"name1\\0name2\\0na\\0\", got \"%s\"\n", buf); + + /* key value has quotation marks which are stripped */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name2", "default", + buf, MAX_PATH, filename); + ok(ret == 4, "Expected 4, got %d\n", ret); + ok(!lstrcmpA(buf, "val2"), "Expected \"val2\", got \"%s\"\n", buf); + + /* case does not match */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "NaMe1", "default", + buf, MAX_PATH, filename); + ok(ret == 4, "Expected 4, got %d\n", ret); + ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf); + + /* only filename is used */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "NaMe1", "default", + buf, MAX_PATH, "winetest.ini"); + ok(ret == 7, "Expected 7, got %d\n", ret); + ok(!lstrcmpA(buf, "default"), "Expected \"default\", got \"%s\"\n", buf); + + GetWindowsDirectoryA(windir, MAX_PATH); + GetTempFileNameA(windir, "pre", 0, path); + tempfile = strrchr(path, '\\') + 1; + create_test_file(path, content, lstrlenA(content)); + + /* only filename is used, file exists in windows directory */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "NaMe1", "default", + buf, MAX_PATH, tempfile); + ok(ret == 4, "Expected 4, got %d\n", ret); + ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf); + + /* successful case */ + lstrcpyA(buf, "kumquat"); + ret = GetPrivateProfileStringA("section1", "name1", "default", + buf, MAX_PATH, filename); + ok(ret == 4, "Expected 4, got %d\n", ret); + ok(!lstrcmpA(buf, "val1"), "Expected \"val1\", got \"%s\"\n", buf); + + DeleteFileA(path); + DeleteFileA(filename); +} + START_TEST(profile) { test_profile_int(); test_profile_string(); test_profile_sections(); test_profile_sections_names(); + test_profile_existing(); + test_profile_delete_on_close(); + test_profile_refresh(); + test_GetPrivateProfileString( + "[section1]\r\n" + "name1=val1\r\n" + "name2=\"val2\"\r\n" + "name3\r\n" + "name4=a\r\n" + "[section2]\r\n", + "CR+LF"); + test_GetPrivateProfileString( + "[section1]\r" + "name1=val1\r" + "name2=\"val2\"\r" + "name3\r" + "name4=a\r" + "[section2]\r", + "CR only"); } diff --git a/rostests/winetests/kernel32/resource.c b/rostests/winetests/kernel32/resource.c index 79d17f13fae..cde27a8d535 100644 --- a/rostests/winetests/kernel32/resource.c +++ b/rostests/winetests/kernel32/resource.c @@ -173,22 +173,25 @@ static void update_resources_version(void) res = BeginUpdateResource( filename, TRUE ); ok( res != NULL, "BeginUpdateResource failed\n"); - r = UpdateResource( res, - MAKEINTRESOURCE(0x1230), - MAKEINTRESOURCE(0x4567), - 0xabcd, - NULL, 0 ); - ok( r == FALSE, "UpdateResource failed\n"); + if (0) /* this causes subsequent tests to fail on Vista */ + { + r = UpdateResource( res, + MAKEINTRESOURCE(0x1230), + MAKEINTRESOURCE(0x4567), + 0xabcd, + NULL, 0 ); + ok( r == FALSE, "UpdateResource failed\n"); + } r = UpdateResource( res, MAKEINTRESOURCE(0x1230), MAKEINTRESOURCE(0x4567), 0xabcd, foo, sizeof foo ); - ok( r == TRUE, "UpdateResource failed\n"); + ok( r == TRUE, "UpdateResource failed: %d\n", GetLastError()); r = EndUpdateResource( res, FALSE ); - ok( r, "EndUpdateResource failed\n"); + ok( r, "EndUpdateResource failed: %d\n", GetLastError()); } @@ -249,7 +252,8 @@ static void check_exe( res_check_func fn ) dir = (void*) ((BYTE*) dos + sec[1].VirtualAddress); ok( dir->Characteristics == 0, "Characteristics wrong\n"); - ok( dir->TimeDateStamp == 0, "TimeDateStamp wrong\n"); + ok( dir->TimeDateStamp == 0 || abs( dir->TimeDateStamp - GetTickCount() ) < 1000 /* nt4 */, + "TimeDateStamp wrong %u\n", dir->TimeDateStamp); ok( dir->MajorVersion == 4, "MajorVersion wrong\n"); ok( dir->MinorVersion == 0, "MinorVersion wrong\n"); diff --git a/rostests/winetests/kernel32/sync.c b/rostests/winetests/kernel32/sync.c index b5778fccd99..32d37e868b8 100755 --- a/rostests/winetests/kernel32/sync.c +++ b/rostests/winetests/kernel32/sync.c @@ -26,6 +26,15 @@ #include "wine/test.h" +static BOOL (WINAPI *pChangeTimerQueueTimer)(HANDLE, HANDLE, ULONG, ULONG); +static HANDLE (WINAPI *pCreateTimerQueue)(void); +static BOOL (WINAPI *pCreateTimerQueueTimer)(PHANDLE, HANDLE, WAITORTIMERCALLBACK, + PVOID, DWORD, DWORD, ULONG); +static HANDLE (WINAPI *pCreateWaitableTimerA)(SECURITY_ATTRIBUTES*,BOOL,LPCSTR); +static BOOL (WINAPI *pDeleteTimerQueueEx)(HANDLE, HANDLE); +static BOOL (WINAPI *pDeleteTimerQueueTimer)(HANDLE, HANDLE, HANDLE); +static HANDLE (WINAPI *pOpenWaitableTimerA)(DWORD,BOOL,LPCSTR); + static void test_signalandwait(void) { DWORD (WINAPI *pSignalObjectAndWait)(HANDLE, HANDLE, DWORD, BOOL); @@ -44,7 +53,7 @@ static void test_signalandwait(void) r = pSignalObjectAndWait(NULL, NULL, 0, 0); if (r == ERROR_INVALID_FUNCTION) { - trace("SignalObjectAndWait not implemented, skipping tests\n"); + skip("SignalObjectAndWait is not implemented\n"); return; /* Win98/ME */ } ok( r == WAIT_FAILED, "should fail\n"); @@ -148,7 +157,34 @@ static void test_mutex(void) todo_wine ok(!ret && (GetLastError() == ERROR_NOT_OWNER), "ReleaseMutex should have failed with ERROR_NOT_OWNER instead of %d\n", GetLastError()); + /* test case sensitivity */ + + SetLastError(0xdeadbeef); + hOpened = OpenMutex(READ_CONTROL, FALSE, "WINETESTMUTEX"); + ok(!hOpened, "OpenMutex succeeded\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_INVALID_NAME, /* win9x */ + "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + hOpened = OpenMutex(READ_CONTROL, FALSE, "winetestmutex"); + ok(!hOpened, "OpenMutex succeeded\n"); + ok(GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_INVALID_NAME, /* win9x */ + "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + hOpened = CreateMutex(NULL, FALSE, "WineTestMutex"); + ok(hOpened != NULL, "CreateMutex failed with error %d\n", GetLastError()); + ok(GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError()); CloseHandle(hOpened); + + SetLastError(0xdeadbeef); + hOpened = CreateMutex(NULL, FALSE, "WINETESTMUTEX"); + ok(hOpened != NULL, "CreateMutex failed with error %d\n", GetLastError()); + ok(GetLastError() == 0, "wrong error %u\n", GetLastError()); + CloseHandle(hOpened); + CloseHandle(hCreated); } @@ -245,9 +281,9 @@ static void test_slist(void) ok(((struct item*)entry->Next)->value == 1, "item 1 not at the back of list\n"); } -static void test_event_security(void) +static void test_event(void) { - HANDLE handle; + HANDLE handle, handle2; SECURITY_ATTRIBUTES sa; SECURITY_DESCRIPTOR sd; ACL acl; @@ -280,6 +316,121 @@ static void test_event_security(void) handle = CreateEventA(&sa, FALSE, FALSE, __FILE__ ": Test Event"); ok(handle != NULL, "CreateEventW with blank sd failed with error %d\n", GetLastError()); CloseHandle(handle); + + /* test case sensitivity */ + + SetLastError(0xdeadbeef); + handle = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event"); + ok( handle != NULL, "CreateEvent failed with error %u\n", GetLastError()); + ok( GetLastError() == 0, "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + handle2 = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event"); + ok( handle2 != NULL, "CreateEvent failed with error %d\n", GetLastError()); + ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": TEST EVENT"); + ok( handle2 != NULL, "CreateEvent failed with error %d\n", GetLastError()); + ok( GetLastError() == 0, "wrong error %u\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, __FILE__ ": Test Event"); + ok( handle2 != NULL, "OpenEvent failed with error %d\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = OpenEventA( EVENT_ALL_ACCESS, FALSE, __FILE__ ": TEST EVENT"); + ok( !handle2, "OpenEvent succeeded\n"); + ok( GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_INVALID_NAME, /* win9x */ + "wrong error %u\n", GetLastError()); + + CloseHandle( handle ); +} + +static void test_semaphore(void) +{ + HANDLE handle, handle2; + + /* test case sensitivity */ + + SetLastError(0xdeadbeef); + handle = CreateSemaphoreA(NULL, 0, 1, __FILE__ ": Test Semaphore"); + ok(handle != NULL, "CreateSemaphore failed with error %u\n", GetLastError()); + ok(GetLastError() == 0, "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + handle2 = CreateSemaphoreA(NULL, 0, 1, __FILE__ ": Test Semaphore"); + ok( handle2 != NULL, "CreateSemaphore failed with error %d\n", GetLastError()); + ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = CreateSemaphoreA(NULL, 0, 1, __FILE__ ": TEST SEMAPHORE"); + ok( handle2 != NULL, "CreateSemaphore failed with error %d\n", GetLastError()); + ok( GetLastError() == 0, "wrong error %u\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, __FILE__ ": Test Semaphore"); + ok( handle2 != NULL, "OpenSemaphore failed with error %d\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = OpenSemaphoreA( SEMAPHORE_ALL_ACCESS, FALSE, __FILE__ ": TEST SEMAPHORE"); + ok( !handle2, "OpenSemaphore succeeded\n"); + ok( GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_INVALID_NAME, /* win9x */ + "wrong error %u\n", GetLastError()); + + CloseHandle( handle ); +} + +static void test_waitable_timer(void) +{ + HANDLE handle, handle2; + + if (!pCreateWaitableTimerA || !pOpenWaitableTimerA) + { + skip("{Create,Open}WaitableTimerA() is not available\n"); + return; + } + + /* test case sensitivity */ + + SetLastError(0xdeadbeef); + handle = pCreateWaitableTimerA(NULL, FALSE, __FILE__ ": Test WaitableTimer"); + ok(handle != NULL, "CreateWaitableTimer failed with error %u\n", GetLastError()); + ok(GetLastError() == 0, "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + handle2 = pCreateWaitableTimerA(NULL, FALSE, __FILE__ ": Test WaitableTimer"); + ok( handle2 != NULL, "CreateWaitableTimer failed with error %d\n", GetLastError()); + ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = pCreateWaitableTimerA(NULL, FALSE, __FILE__ ": TEST WAITABLETIMER"); + ok( handle2 != NULL, "CreateWaitableTimer failed with error %d\n", GetLastError()); + ok( GetLastError() == 0, "wrong error %u\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = pOpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, __FILE__ ": Test WaitableTimer"); + ok( handle2 != NULL, "OpenWaitableTimer failed with error %d\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = pOpenWaitableTimerA( TIMER_ALL_ACCESS, FALSE, __FILE__ ": TEST WAITABLETIMER"); + ok( !handle2, "OpenWaitableTimer succeeded\n"); + ok( GetLastError() == ERROR_FILE_NOT_FOUND || + GetLastError() == ERROR_INVALID_NAME, /* win98 */ + "wrong error %u\n", GetLastError()); + + CloseHandle( handle ); } static HANDLE sem = 0; @@ -289,7 +440,7 @@ static void CALLBACK iocp_callback(DWORD dwErrorCode, DWORD dwNumberOfBytesTrans ReleaseSemaphore(sem, 1, NULL); } -static BOOL WINAPI (*p_BindIoCompletionCallback)( HANDLE FileHandle, LPOVERLAPPED_COMPLETION_ROUTINE Function, ULONG Flags) = NULL; +static BOOL (WINAPI *p_BindIoCompletionCallback)( HANDLE FileHandle, LPOVERLAPPED_COMPLETION_ROUTINE Function, ULONG Flags) = NULL; static void test_iocp_callback(void) { @@ -360,16 +511,6 @@ static void test_iocp_callback(void) ret = DeleteFileA(filename); ok( ret, "DeleteFileA: error %d\n", GetLastError()); - hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, - CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_OVERLAPPED, 0); - ok(hFile != INVALID_HANDLE_VALUE, "CreateFileA: error %d\n", GetLastError()); - retb = p_BindIoCompletionCallback(hFile, NULL, 0); - ok(retb == TRUE, "BindIoCompletionCallback failed with a NULL callback(first time set)\n"); - ret = CloseHandle(hFile); - ok( ret, "CloseHandle: error %d\n", GetLastError()); - ret = DeleteFileA(filename); - ok( ret, "DeleteFileA: error %d\n", GetLastError()); - /* win2k3 requires the Flags parameter to be zero */ SetLastError(0xdeadbeef); hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, @@ -388,14 +529,435 @@ static void test_iocp_callback(void) retb = p_BindIoCompletionCallback(NULL, iocp_callback, 0); ok(retb == FALSE, "BindIoCompletionCallback succeeded on a NULL file\n"); - ok(GetLastError() == ERROR_INVALID_HANDLE, "Last error is %d\n", GetLastError()); + ok(GetLastError() == ERROR_INVALID_HANDLE || + GetLastError() == ERROR_INVALID_PARAMETER, /* vista */ + "Last error is %d\n", GetLastError()); +} + +static void CALLBACK timer_queue_cb1(PVOID p, BOOLEAN timedOut) +{ + int *pn = (int *) p; + ok(timedOut, "Timer callbacks should always time out\n"); + ++*pn; +} + +struct timer_queue_data1 +{ + int num_calls; + int max_calls; + HANDLE q, t; +}; + +static void CALLBACK timer_queue_cb2(PVOID p, BOOLEAN timedOut) +{ + struct timer_queue_data1 *d = p; + ok(timedOut, "Timer callbacks should always time out\n"); + if (d->t && ++d->num_calls == d->max_calls) + { + BOOL ret; + SetLastError(0xdeadbeef); + /* Note, XP SP2 does *not* do any deadlock checking, so passing + INVALID_HANDLE_VALUE here will just hang. */ + ret = pDeleteTimerQueueTimer(d->q, d->t, NULL); + ok(!ret, "DeleteTimerQueueTimer\n"); + ok(GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueTimer\n"); + } +} + +static void CALLBACK timer_queue_cb3(PVOID p, BOOLEAN timedOut) +{ + struct timer_queue_data1 *d = p; + ok(timedOut, "Timer callbacks should always time out\n"); + if (d->t && ++d->num_calls == d->max_calls) + { + /* Basically kill the timer since it won't have time to run + again. */ + BOOL ret = pChangeTimerQueueTimer(d->q, d->t, 10000, 0); + ok(ret, "ChangeTimerQueueTimer\n"); + } +} + +static void CALLBACK timer_queue_cb4(PVOID p, BOOLEAN timedOut) +{ + struct timer_queue_data1 *d = p; + ok(timedOut, "Timer callbacks should always time out\n"); + if (d->t) + { + /* This tests whether a timer gets flagged for deletion before + or after the callback runs. If we start this timer with a + period of zero (run once), then ChangeTimerQueueTimer will + fail if the timer is already flagged. Hence we really run + only once. Otherwise we will run multiple times. */ + BOOL ret = pChangeTimerQueueTimer(d->q, d->t, 50, 50); + ok(ret, "ChangeTimerQueueTimer\n"); + ++d->num_calls; + } +} + +static void CALLBACK timer_queue_cb5(PVOID p, BOOLEAN timedOut) +{ + DWORD delay = (DWORD) p; + ok(timedOut, "Timer callbacks should always time out\n"); + if (delay) + Sleep(delay); +} + +static void CALLBACK timer_queue_cb6(PVOID p, BOOLEAN timedOut) +{ + struct timer_queue_data1 *d = p; + ok(timedOut, "Timer callbacks should always time out\n"); + /* This tests an original implementation bug where a deleted timer may get + to run, but it is tricky to set up. */ + if (d->q && d->num_calls++ == 0) + { + /* First run: delete ourselves, then insert and remove a timer + that goes in front of us in the sorted timeout list. Once + removed, we will still timeout at the faster timer's due time, + but this should be a no-op if we are bug-free. There should + not be a second run. We can test the value of num_calls later. */ + BOOL ret; + HANDLE t; + + /* The delete will pend while we are in this callback. */ + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueTimer(d->q, d->t, NULL); + ok(!ret, "DeleteTimerQueueTimer\n"); + ok(GetLastError() == ERROR_IO_PENDING, "DeleteTimerQueueTimer\n"); + + ret = pCreateTimerQueueTimer(&t, d->q, timer_queue_cb1, NULL, 100, 0, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t != NULL, "CreateTimerQueueTimer\n"); + + ret = pDeleteTimerQueueTimer(d->q, t, INVALID_HANDLE_VALUE); + ok(ret, "DeleteTimerQueueTimer\n"); + + /* Now we stay alive by hanging around in the callback. */ + Sleep(500); + } +} + +static void test_timer_queue(void) +{ + HANDLE q, t1, t2, t3, t4, t5; + int n1, n2, n3, n4, n5; + struct timer_queue_data1 d1, d2, d3, d4; + HANDLE e, et1, et2; + BOOL ret; + + if (!pChangeTimerQueueTimer || !pCreateTimerQueue || !pCreateTimerQueueTimer + || !pDeleteTimerQueueEx || !pDeleteTimerQueueTimer) + { + skip("TimerQueue API not present\n"); + return; + } + + /* Test asynchronous deletion of the queue. */ + q = pCreateTimerQueue(); + ok(q != NULL, "CreateTimerQueue\n"); + + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueEx(q, NULL); + ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, + "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n", + GetLastError()); + + /* Test synchronous deletion of the queue and running timers. */ + q = pCreateTimerQueue(); + ok(q != NULL, "CreateTimerQueue\n"); + + /* Called once. */ + t1 = NULL; + n1 = 0; + ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb1, &n1, 0, + 0, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t1 != NULL, "CreateTimerQueueTimer\n"); + + /* A slow one. */ + t2 = NULL; + n2 = 0; + ret = pCreateTimerQueueTimer(&t2, q, timer_queue_cb1, &n2, 0, + 100, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t2 != NULL, "CreateTimerQueueTimer\n"); + + /* A fast one. */ + t3 = NULL; + n3 = 0; + ret = pCreateTimerQueueTimer(&t3, q, timer_queue_cb1, &n3, 0, + 10, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t3 != NULL, "CreateTimerQueueTimer\n"); + + /* Start really late (it won't start). */ + t4 = NULL; + n4 = 0; + ret = pCreateTimerQueueTimer(&t4, q, timer_queue_cb1, &n4, 10000, + 10, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t4 != NULL, "CreateTimerQueueTimer\n"); + + /* Start soon, but delay so long it won't run again. */ + t5 = NULL; + n5 = 0; + ret = pCreateTimerQueueTimer(&t5, q, timer_queue_cb1, &n5, 0, + 10000, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t5 != NULL, "CreateTimerQueueTimer\n"); + + /* Give them a chance to do some work. */ + Sleep(500); + + /* Test deleting a once-only timer. */ + ret = pDeleteTimerQueueTimer(q, t1, INVALID_HANDLE_VALUE); + ok(ret, "DeleteTimerQueueTimer\n"); + + /* A periodic timer. */ + ret = pDeleteTimerQueueTimer(q, t2, INVALID_HANDLE_VALUE); + ok(ret, "DeleteTimerQueueTimer\n"); + + ret = pDeleteTimerQueueEx(q, INVALID_HANDLE_VALUE); + ok(ret, "DeleteTimerQueueEx\n"); + ok(n1 == 1, "Timer callback 1\n"); + ok(n2 < n3, "Timer callback 2 should be much slower than 3\n"); + ok(n4 == 0, "Timer callback 4\n"); + ok(n5 == 1, "Timer callback 5\n"); + + /* Test synchronous deletion of the timer/queue with event trigger. */ + e = CreateEvent(NULL, TRUE, FALSE, NULL); + et1 = CreateEvent(NULL, TRUE, FALSE, NULL); + et2 = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!e || !et1 || !et2) + { + skip("Failed to create timer queue descruction event\n"); + return; + } + + q = pCreateTimerQueue(); + ok(q != NULL, "CreateTimerQueue\n"); + + /* Run once and finish quickly (should be done when we delete it). */ + t1 = NULL; + ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb5, NULL, 0, 0, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t1 != NULL, "CreateTimerQueueTimer\n"); + + /* Run once and finish slowly (shouldn't be done when we delete it). */ + t2 = NULL; + ret = pCreateTimerQueueTimer(&t2, q, timer_queue_cb5, (PVOID) 1000, 0, + 0, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t2 != NULL, "CreateTimerQueueTimer\n"); + + /* Run once and finish quickly (should be done when we delete it). */ + t3 = NULL; + ret = pCreateTimerQueueTimer(&t3, q, timer_queue_cb5, NULL, 0, 0, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t3 != NULL, "CreateTimerQueueTimer\n"); + + /* Run once and finish slowly (shouldn't be done when we delete it). */ + t4 = NULL; + ret = pCreateTimerQueueTimer(&t4, q, timer_queue_cb5, (PVOID) 1000, 0, + 0, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t4 != NULL, "CreateTimerQueueTimer\n"); + + /* Give them a chance to start. */ + Sleep(400); + + /* DeleteTimerQueueTimer always returns PENDING with a NULL event, + even if the timer is finished. */ + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueTimer(q, t1, NULL); + ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, + "DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %d\n", + GetLastError()); + + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueTimer(q, t2, NULL); + ok(!ret, "DeleteTimerQueueTimer call was expected to fail\n"); + ok(GetLastError() == ERROR_IO_PENDING, + "DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %d\n", + GetLastError()); + + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueTimer(q, t3, et1); + ok(ret, "DeleteTimerQueueTimer call was expected to fail\n"); + ok(GetLastError() == 0xdeadbeef, + "DeleteTimerQueueTimer, GetLastError: expected 0xdeadbeef, got %d\n", + GetLastError()); + ok(WaitForSingleObject(et1, 250) == WAIT_OBJECT_0, + "Timer destruction event not triggered\n"); + + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueTimer(q, t4, et2); + ok(!ret, "DeleteTimerQueueTimer call was expected to fail\n"); + ok(GetLastError() == ERROR_IO_PENDING, + "DeleteTimerQueueTimer, GetLastError: expected ERROR_IO_PENDING, got %d\n", + GetLastError()); + ok(WaitForSingleObject(et2, 1000) == WAIT_OBJECT_0, + "Timer destruction event not triggered\n"); + + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueEx(q, e); + ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, + "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n", + GetLastError()); + ok(WaitForSingleObject(e, 250) == WAIT_OBJECT_0, + "Queue destruction event not triggered\n"); + CloseHandle(e); + + /* Test deleting/changing a timer in execution. */ + q = pCreateTimerQueue(); + ok(q != NULL, "CreateTimerQueue\n"); + + /* Test changing a once-only timer before it fires (this is allowed, + whereas after it fires you cannot). */ + n1 = 0; + ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb1, &n1, 10000, + 0, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t1 != NULL, "CreateTimerQueueTimer\n"); + ret = pChangeTimerQueueTimer(q, t1, 0, 0); + ok(ret, "ChangeTimerQueueTimer\n"); + + d2.t = t2 = NULL; + d2.num_calls = 0; + d2.max_calls = 3; + d2.q = q; + ret = pCreateTimerQueueTimer(&t2, q, timer_queue_cb2, &d2, 10, + 10, 0); + d2.t = t2; + ok(ret, "CreateTimerQueueTimer\n"); + ok(t2 != NULL, "CreateTimerQueueTimer\n"); + + d3.t = t3 = NULL; + d3.num_calls = 0; + d3.max_calls = 4; + d3.q = q; + ret = pCreateTimerQueueTimer(&t3, q, timer_queue_cb3, &d3, 10, + 10, 0); + d3.t = t3; + ok(ret, "CreateTimerQueueTimer\n"); + ok(t3 != NULL, "CreateTimerQueueTimer\n"); + + d4.t = t4 = NULL; + d4.num_calls = 0; + d4.q = q; + ret = pCreateTimerQueueTimer(&t4, q, timer_queue_cb4, &d4, 10, + 0, 0); + d4.t = t4; + ok(ret, "CreateTimerQueueTimer\n"); + ok(t4 != NULL, "CreateTimerQueueTimer\n"); + + Sleep(500); + + ret = pDeleteTimerQueueEx(q, INVALID_HANDLE_VALUE); + ok(ret, "DeleteTimerQueueEx\n"); + ok(n1 == 1, "ChangeTimerQueueTimer\n"); + ok(d2.num_calls == d2.max_calls, "DeleteTimerQueueTimer\n"); + ok(d3.num_calls == d3.max_calls, "ChangeTimerQueueTimer\n"); + ok(d4.num_calls == 1, "Timer flagged for deletion incorrectly\n"); + + /* Test an obscure bug that was in the original implementation. */ + q = pCreateTimerQueue(); + ok(q != NULL, "CreateTimerQueue\n"); + + /* All the work is done in the callback. */ + d1.t = t1 = NULL; + d1.num_calls = 0; + d1.q = q; + ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb6, &d1, 100, + 100, WT_EXECUTELONGFUNCTION); + d1.t = t1; + ok(ret, "CreateTimerQueueTimer\n"); + ok(t1 != NULL, "CreateTimerQueueTimer\n"); + + Sleep(750); + + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueEx(q, NULL); + ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, + "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n", + GetLastError()); + ok(d1.num_calls == 1, "DeleteTimerQueueTimer\n"); + + /* Test functions on the default timer queue. */ + t1 = NULL; + n1 = 0; + ret = pCreateTimerQueueTimer(&t1, NULL, timer_queue_cb1, &n1, 1000, + 1000, 0); + ok(ret, "CreateTimerQueueTimer, default queue\n"); + ok(t1 != NULL, "CreateTimerQueueTimer, default queue\n"); + + ret = pChangeTimerQueueTimer(NULL, t1, 2000, 2000); + ok(ret, "ChangeTimerQueueTimer, default queue\n"); + + ret = pDeleteTimerQueueTimer(NULL, t1, INVALID_HANDLE_VALUE); + ok(ret, "DeleteTimerQueueTimer, default queue\n"); + + /* Try mixing default and non-default queues. Apparently this works. */ + q = pCreateTimerQueue(); + ok(q != NULL, "CreateTimerQueue\n"); + + t1 = NULL; + n1 = 0; + ret = pCreateTimerQueueTimer(&t1, q, timer_queue_cb1, &n1, 1000, + 1000, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t1 != NULL, "CreateTimerQueueTimer\n"); + + t2 = NULL; + n2 = 0; + ret = pCreateTimerQueueTimer(&t2, NULL, timer_queue_cb1, &n2, 1000, + 1000, 0); + ok(ret, "CreateTimerQueueTimer\n"); + ok(t2 != NULL, "CreateTimerQueueTimer\n"); + + ret = pChangeTimerQueueTimer(NULL, t1, 2000, 2000); + ok(ret, "ChangeTimerQueueTimer\n"); + + ret = pChangeTimerQueueTimer(q, t2, 2000, 2000); + ok(ret, "ChangeTimerQueueTimer\n"); + + ret = pDeleteTimerQueueTimer(NULL, t1, INVALID_HANDLE_VALUE); + ok(ret, "DeleteTimerQueueTimer\n"); + + ret = pDeleteTimerQueueTimer(q, t2, INVALID_HANDLE_VALUE); + ok(ret, "DeleteTimerQueueTimer\n"); + + /* Try to delete the default queue? In any case: not allowed. */ + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueEx(NULL, NULL); + ok(!ret, "DeleteTimerQueueEx call was expected to fail\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, + "DeleteTimerQueueEx, GetLastError: expected ERROR_INVALID_HANDLE, got %d\n", + GetLastError()); + + SetLastError(0xdeadbeef); + ret = pDeleteTimerQueueEx(q, NULL); + ok(ret /* vista */ || GetLastError() == ERROR_IO_PENDING, + "DeleteTimerQueueEx, GetLastError: expected ERROR_IO_PENDING, got %d\n", + GetLastError()); } START_TEST(sync) { + HMODULE hdll = GetModuleHandle("kernel32"); + pChangeTimerQueueTimer = (void*)GetProcAddress(hdll, "ChangeTimerQueueTimer"); + pCreateTimerQueue = (void*)GetProcAddress(hdll, "CreateTimerQueue"); + pCreateTimerQueueTimer = (void*)GetProcAddress(hdll, "CreateTimerQueueTimer"); + pCreateWaitableTimerA = (void*)GetProcAddress(hdll, "CreateWaitableTimerA"); + pDeleteTimerQueueEx = (void*)GetProcAddress(hdll, "DeleteTimerQueueEx"); + pDeleteTimerQueueTimer = (void*)GetProcAddress(hdll, "DeleteTimerQueueTimer"); + pOpenWaitableTimerA = (void*)GetProcAddress(hdll, "OpenWaitableTimerA"); + test_signalandwait(); test_mutex(); test_slist(); - test_event_security(); + test_event(); + test_semaphore(); + test_waitable_timer(); test_iocp_callback(); + test_timer_queue(); } diff --git a/rostests/winetests/kernel32/thread.c b/rostests/winetests/kernel32/thread.c index 7d83b255a4d..0030422b5fe 100755 --- a/rostests/winetests/kernel32/thread.c +++ b/rostests/winetests/kernel32/thread.c @@ -18,9 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -/* Define _WIN32_WINNT to get SetThreadIdealProcessor on Windows */ -#define _WIN32_WINNT 0x0500 - +#include #include #include @@ -99,6 +97,61 @@ In addition there are no checks that the inheritance works properly in CreateThread */ +/* Functions to ensure that from a group of threads, only one executes + certain chunks of code at a time, and we know which one is executing + it. It basically makes multithreaded execution linear, which defeats + the purpose of multiple threads, but makes testing easy. */ +static HANDLE start_event, stop_event; +static LONG num_synced; + +static void init_thread_sync_helpers(void) +{ + start_event = CreateEvent(NULL, TRUE, FALSE, NULL); + ok(start_event != NULL, "CreateEvent failed\n"); + stop_event = CreateEvent(NULL, TRUE, FALSE, NULL); + ok(stop_event != NULL, "CreateEvent failed\n"); + num_synced = -1; +} + +static BOOL sync_threads_and_run_one(DWORD sync_id, DWORD my_id) +{ + LONG num = InterlockedIncrement(&num_synced); + assert(-1 <= num && num <= 1); + if (num == 1) + { + ResetEvent( stop_event ); + SetEvent( start_event ); + } + else + { + DWORD ret = WaitForSingleObject(start_event, 10000); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed %x\n",ret); + } + return sync_id == my_id; +} + +static void resync_after_run(void) +{ + LONG num = InterlockedDecrement(&num_synced); + assert(-1 <= num && num <= 1); + if (num == -1) + { + ResetEvent( start_event ); + SetEvent( stop_event ); + } + else + { + DWORD ret = WaitForSingleObject(stop_event, 10000); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + } +} + +static void cleanup_thread_sync_helpers(void) +{ + CloseHandle(start_event); + CloseHandle(stop_event); +} + DWORD tlsIndex; typedef struct { @@ -320,6 +373,7 @@ static VOID test_CreateThread_basic(void) int error; DWORD i,j; DWORD GLE, ret; + DWORD tid; /* lstrlenA contains an exception handler so this makes sure exceptions work in the main thread */ ok( lstrlenA( (char *)0xdeadbeef ) == 0, "lstrlenA: unexpected success\n" ); @@ -377,7 +431,7 @@ static VOID test_CreateThread_basic(void) /* Test how passing NULL as a pointer to threadid works */ SetLastError(0xFACEaBAD); - thread[0] = CreateThread(NULL,0,threadFunc2,NULL,0,NULL); + thread[0] = CreateThread(NULL,0,threadFunc2,NULL,0,&tid); GLE = GetLastError(); if (thread[0]) { /* NT */ ok(GLE==0xFACEaBAD, "CreateThread set last error to %d, expected 4207848365\n", GLE); @@ -398,6 +452,7 @@ static VOID test_CreateThread_suspended(void) { HANDLE thread; DWORD threadId; + DWORD suspend_count; int error; thread = CreateThread(NULL,0,threadFunc2,NULL, @@ -419,6 +474,15 @@ static VOID test_CreateThread_suspended(void) if(error!=WAIT_OBJECT_0) { TerminateThread(thread,1); } + + suspend_count = SuspendThread(thread); + ok(suspend_count == -1, "SuspendThread returned %d, expected -1\n", suspend_count); + + suspend_count = ResumeThread(thread); + ok(suspend_count == 0 || + broken(suspend_count == -1), /* win9x */ + "ResumeThread returned %d, expected 0\n", suspend_count); + ok(CloseHandle(thread)!=0,"CloseHandle failed\n"); } @@ -953,6 +1017,183 @@ static void test_RegisterWaitForSingleObject(void) ok(ret, "UnregisterWait failed with error %d\n", GetLastError()); } +static DWORD TLS_main; +static DWORD TLS_index0, TLS_index1; + +static DWORD WINAPI TLS_InheritanceProc(LPVOID p) +{ + /* We should NOT inherit the TLS values from our parent or from the + main thread. */ + LPVOID val; + + val = TlsGetValue(TLS_main); + ok(val == NULL, "TLS inheritance failed\n"); + + val = TlsGetValue(TLS_index0); + ok(val == NULL, "TLS inheritance failed\n"); + + val = TlsGetValue(TLS_index1); + ok(val == NULL, "TLS inheritance failed\n"); + + return 0; +} + +/* Basic TLS usage test. Make sure we can create slots and the values we + store in them are separate among threads. Also test TLS value + inheritance with TLS_InheritanceProc. */ +static DWORD WINAPI TLS_ThreadProc(LPVOID p) +{ + LONG id = (LONG) p; + LPVOID val; + BOOL ret; + + if (sync_threads_and_run_one(0, id)) + { + TLS_index0 = TlsAlloc(); + ok(TLS_index0 != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n"); + } + resync_after_run(); + + if (sync_threads_and_run_one(1, id)) + { + TLS_index1 = TlsAlloc(); + ok(TLS_index1 != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n"); + + /* Slot indices should be different even if created in different + threads. */ + ok(TLS_index0 != TLS_index1, "TlsAlloc failed\n"); + + /* Both slots should be initialized to NULL */ + val = TlsGetValue(TLS_index0); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == NULL, "TLS slot not initialized correctly\n"); + + val = TlsGetValue(TLS_index1); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == NULL, "TLS slot not initialized correctly\n"); + } + resync_after_run(); + + if (sync_threads_and_run_one(0, id)) + { + val = TlsGetValue(TLS_index0); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == NULL, "TLS slot not initialized correctly\n"); + + val = TlsGetValue(TLS_index1); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == NULL, "TLS slot not initialized correctly\n"); + + ret = TlsSetValue(TLS_index0, (LPVOID) 1); + ok(ret, "TlsSetValue failed\n"); + + ret = TlsSetValue(TLS_index1, (LPVOID) 2); + ok(ret, "TlsSetValue failed\n"); + + val = TlsGetValue(TLS_index0); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == (LPVOID) 1, "TLS slot not initialized correctly\n"); + + val = TlsGetValue(TLS_index1); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == (LPVOID) 2, "TLS slot not initialized correctly\n"); + } + resync_after_run(); + + if (sync_threads_and_run_one(1, id)) + { + val = TlsGetValue(TLS_index0); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == NULL, "TLS slot not initialized correctly\n"); + + val = TlsGetValue(TLS_index1); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == NULL, "TLS slot not initialized correctly\n"); + + ret = TlsSetValue(TLS_index0, (LPVOID) 3); + ok(ret, "TlsSetValue failed\n"); + + ret = TlsSetValue(TLS_index1, (LPVOID) 4); + ok(ret, "TlsSetValue failed\n"); + + val = TlsGetValue(TLS_index0); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == (LPVOID) 3, "TLS slot not initialized correctly\n"); + + val = TlsGetValue(TLS_index1); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == (LPVOID) 4, "TLS slot not initialized correctly\n"); + } + resync_after_run(); + + if (sync_threads_and_run_one(0, id)) + { + HANDLE thread; + DWORD waitret, tid; + + val = TlsGetValue(TLS_index0); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == (LPVOID) 1, "TLS slot not initialized correctly\n"); + + val = TlsGetValue(TLS_index1); + ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); + ok(val == (LPVOID) 2, "TLS slot not initialized correctly\n"); + + thread = CreateThread(NULL, 0, TLS_InheritanceProc, 0, 0, &tid); + ok(thread != NULL, "CreateThread failed\n"); + waitret = WaitForSingleObject(thread, 60000); + ok(waitret == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + CloseHandle(thread); + + ret = TlsFree(TLS_index0); + ok(ret, "TlsFree failed\n"); + } + resync_after_run(); + + if (sync_threads_and_run_one(1, id)) + { + ret = TlsFree(TLS_index1); + ok(ret, "TlsFree failed\n"); + } + resync_after_run(); + + return 0; +} + +static void test_TLS(void) +{ + HANDLE threads[2]; + LONG i; + DWORD ret; + BOOL suc; + + init_thread_sync_helpers(); + + /* Allocate a TLS slot in the main thread to test for inheritance. */ + TLS_main = TlsAlloc(); + ok(TLS_main != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n"); + suc = TlsSetValue(TLS_main, (LPVOID) 4114); + ok(suc, "TlsSetValue failed\n"); + + for (i = 0; i < 2; ++i) + { + DWORD tid; + + threads[i] = CreateThread(NULL, 0, TLS_ThreadProc, (LPVOID) i, 0, &tid); + ok(threads[i] != NULL, "CreateThread failed\n"); + } + + ret = WaitForMultipleObjects(2, threads, TRUE, 60000); + ok(ret == WAIT_OBJECT_0 || ret == WAIT_OBJECT_0+1 /* nt4 */, "WaitForMultipleObjects failed %u\n",ret); + + for (i = 0; i < 2; ++i) + CloseHandle(threads[i]); + + suc = TlsFree(TLS_main); + ok(suc, "TlsFree failed\n"); + cleanup_thread_sync_helpers(); +} + START_TEST(thread) { HINSTANCE lib; @@ -986,7 +1227,8 @@ START_TEST(thread) while (1) { HANDLE hThread; - hThread = CreateThread(NULL, 0, threadFunc2, NULL, 0, NULL); + DWORD tid; + hThread = CreateThread(NULL, 0, threadFunc2, NULL, 0, &tid); ok(hThread != NULL, "CreateThread failed, error %u\n", GetLastError()); ok(WaitForSingleObject(hThread, 200) == WAIT_OBJECT_0, @@ -1012,4 +1254,5 @@ START_TEST(thread) #endif test_QueueUserWorkItem(); test_RegisterWaitForSingleObject(); + test_TLS(); } diff --git a/rostests/winetests/kernel32/timer.c b/rostests/winetests/kernel32/timer.c index 34418908705..40b2277dd92 100755 --- a/rostests/winetests/kernel32/timer.c +++ b/rostests/winetests/kernel32/timer.c @@ -18,8 +18,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#define _WIN32_WINNT 0x0501 - #include "wine/test.h" #include "winbase.h" @@ -38,11 +36,17 @@ static void test_timer(void) pCreateWaitableTimerA = (fnCreateWaitableTimerA) GetProcAddress( hker, "CreateWaitableTimerA"); if( !pCreateWaitableTimerA ) + { + skip("CreateWaitableTimerA is not available\n"); return; + } pSetWaitableTimer = (fnSetWaitableTimer) GetProcAddress( hker, "SetWaitableTimer"); if( !pSetWaitableTimer ) + { + skip("SetWaitableTimer is not available\n"); return; + } /* try once with a positive number */ handle = pCreateWaitableTimerA( NULL, 0, NULL ); diff --git a/rostests/winetests/kernel32/toolhelp.c b/rostests/winetests/kernel32/toolhelp.c index 48b6a6b790f..804d266294c 100644 --- a/rostests/winetests/kernel32/toolhelp.c +++ b/rostests/winetests/kernel32/toolhelp.c @@ -102,7 +102,6 @@ static void test_process(DWORD curr_pid, DWORD sub_pcs_pid) { HANDLE hSnapshot; PROCESSENTRY32 pe; - THREADENTRY32 te; MODULEENTRY32 me; unsigned found = 0; int num = 0; @@ -144,9 +143,6 @@ static void test_process(DWORD curr_pid, DWORD sub_pcs_pid) * interesting to be there, especially not the just forked off child */ ok (childpos !=0, "child is not expected to be at position 0.\n"); - te.dwSize = sizeof(te); - ok(!pThread32First( hSnapshot, &te ), "shouldn't return a thread\n"); - me.dwSize = sizeof(me); ok(!pModule32First( hSnapshot, &me ), "shouldn't return a module\n"); @@ -157,7 +153,6 @@ static void test_process(DWORD curr_pid, DWORD sub_pcs_pid) static void test_thread(DWORD curr_pid, DWORD sub_pcs_pid) { HANDLE hSnapshot; - PROCESSENTRY32 pe; THREADENTRY32 te; MODULEENTRY32 me; int num = 0; @@ -175,7 +170,8 @@ static void test_thread(DWORD curr_pid, DWORD sub_pcs_pid) { if (te.th32OwnerProcessID == curr_pid) curr_found++; if (te.th32OwnerProcessID == sub_pcs_pid) sub_found++; - trace("PID=%x TID=%x %d\n", te.th32OwnerProcessID, te.th32ThreadID, te.tpBasePri); + if (winetest_debug > 1) + trace("PID=%x TID=%x %d\n", te.th32OwnerProcessID, te.th32ThreadID, te.tpBasePri); num++; } while (pThread32Next( hSnapshot, &te )); } @@ -191,16 +187,14 @@ static void test_thread(DWORD curr_pid, DWORD sub_pcs_pid) { if (te.th32OwnerProcessID == curr_pid) curr_found++; if (te.th32OwnerProcessID == sub_pcs_pid) sub_found++; - trace("PID=%x TID=%x %d\n", te.th32OwnerProcessID, te.th32ThreadID, te.tpBasePri); + if (winetest_debug > 1) + trace("PID=%x TID=%x %d\n", te.th32OwnerProcessID, te.th32ThreadID, te.tpBasePri); num--; } while (pThread32Next( hSnapshot, &te )); } ok(curr_found == 1, "couldn't find self in thread list\n"); ok(sub_found == 2, "couldn't find sub-process thread's in thread list\n"); - pe.dwSize = sizeof(pe); - ok(!pProcess32First( hSnapshot, &pe ), "shouldn't return a process\n"); - me.dwSize = sizeof(me); ok(!pModule32First( hSnapshot, &me ), "shouldn't return a module\n"); @@ -278,7 +272,7 @@ static void test_module(DWORD pid, const char* expected[], unsigned num_expected pe.dwSize = sizeof(pe); ok(!pProcess32First( hSnapshot, &pe ), "shouldn't return a process\n"); - me.dwSize = sizeof(me); + te.dwSize = sizeof(te); ok(!pThread32First( hSnapshot, &te ), "shouldn't return a thread\n"); CloseHandle(hSnapshot); diff --git a/rostests/winetests/kernel32/version.c b/rostests/winetests/kernel32/version.c index 5371795ba6b..d051b5d875b 100644 --- a/rostests/winetests/kernel32/version.c +++ b/rostests/winetests/kernel32/version.c @@ -92,7 +92,9 @@ static void test_GetVersionEx(void) SetLastError(0xdeadbeef); infoExA.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXA); ret = GetVersionExA((OSVERSIONINFOA *)&infoExA); - ok(ret, "Expected GetVersionExA to succeed\n"); + ok(ret || + broken(ret == 0), /* win95 */ + "Expected GetVersionExA to succeed\n"); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); } @@ -162,8 +164,12 @@ static void test_VerifyVersionInfo(void) pVerSetConditionMask(pVerSetConditionMask(0, VER_MINORVERSION, VER_GREATER_EQUAL), VER_MAJORVERSION, VER_GREATER_EQUAL)); if (servicepack == 0) - ok(!ret && (GetLastError() == ERROR_OLD_WIN_VERSION), - "VerifyVersionInfoA should have failed with ERROR_OLD_WIN_VERSION instead of %d\n", GetLastError()); + { + ok(!ret || broken(ret), /* win2k3 */ + "VerifyVersionInfoA should have failed\n"); + ok(GetLastError() == ERROR_OLD_WIN_VERSION, + "Expected ERROR_OLD_WIN_VERSION instead of %d\n", GetLastError()); + } else ok(ret, "VerifyVersionInfoA failed with error %d\n", GetLastError()); diff --git a/rostests/winetests/kernel32/virtual.c b/rostests/winetests/kernel32/virtual.c index dad82f6612a..5bd0c016642 100755 --- a/rostests/winetests/kernel32/virtual.c +++ b/rostests/winetests/kernel32/virtual.c @@ -22,7 +22,7 @@ #include #include "windef.h" -#include "winbase.h" +#include "psdk/winbase.h" #include "winerror.h" #include "wine/test.h" @@ -32,6 +32,8 @@ static HINSTANCE hkernel32; static LPVOID (WINAPI *pVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD); static BOOL (WINAPI *pVirtualFreeEx)(HANDLE, LPVOID, SIZE_T, DWORD); +static UINT (WINAPI *pGetWriteWatch)(DWORD,LPVOID,SIZE_T,LPVOID*,ULONG_PTR*,ULONG*); +static UINT (WINAPI *pResetWriteWatch)(LPVOID,SIZE_T); /* ############################### */ @@ -253,6 +255,32 @@ static void test_VirtualAlloc(void) ok(old_prot == PAGE_READONLY, "wrong old protection: got %04x instead of PAGE_READONLY\n", old_prot); + /* invalid protection values */ + SetLastError(0xdeadbeef); + addr2 = VirtualAlloc(NULL, 0x1000, MEM_RESERVE, 0); + ok(!addr2, "VirtualAlloc succeeded\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + addr2 = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, 0); + ok(!addr2, "VirtualAlloc succeeded\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + addr2 = VirtualAlloc(addr1, 0x1000, MEM_COMMIT, PAGE_READONLY | PAGE_EXECUTE); + ok(!addr2, "VirtualAlloc succeeded\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ok(!VirtualProtect(addr1, 0x1000, PAGE_READWRITE | PAGE_EXECUTE_WRITECOPY, &old_prot), + "VirtualProtect succeeded\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + ok(!VirtualProtect(addr1, 0x1000, 0, &old_prot), "VirtualProtect succeeded\n"); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); ok(!VirtualFree(addr1, 0x10000, 0), "VirtualFree should fail with type 0\n"); ok(GetLastError() == ERROR_INVALID_PARAMETER, "got %d, expected ERROR_INVALID_PARAMETER\n", GetLastError()); @@ -270,6 +298,7 @@ static void test_VirtualAlloc(void) static void test_MapViewOfFile(void) { static const char testfile[] = "testfile.xxx"; + const char *name; HANDLE file, mapping; void *ptr, *ptr2; MEMORY_BASIC_INFORMATION info; @@ -450,50 +479,63 @@ static void test_MapViewOfFile(void) DeleteFileA( testfile ); SetLastError(0xdeadbeef); - file = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, "Global\\Foo"); + name = "Local\\Foo"; + file = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, name ); + /* nt4 doesn't have Local\\ */ + if (!file && GetLastError() == ERROR_PATH_NOT_FOUND) + { + name = "Foo"; + file = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, name ); + } ok( file != 0, "CreateFileMapping PAGE_READWRITE error %u\n", GetLastError() ); SetLastError(0xdeadbeef); - mapping = OpenFileMapping( FILE_MAP_READ, FALSE, "Global\\Foo" ); + mapping = OpenFileMapping( FILE_MAP_READ, FALSE, name ); ok( mapping != 0, "OpenFileMapping FILE_MAP_READ error %u\n", GetLastError() ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 ); -todo_wine ok( !ptr, "MapViewOfFile FILE_MAP_WRITE should fail\n" ); -todo_wine ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); - SetLastError(0xdeadbeef); - ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 ); - ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() ); - SetLastError(0xdeadbeef); - ok( VirtualQuery( ptr, &info, sizeof(info) ) == sizeof(info), - "VirtualQuery error %u\n", GetLastError() ); - ok( info.BaseAddress == ptr, "%p != %p\n", info.BaseAddress, ptr ); - ok( info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr ); -todo_wine ok( info.AllocationProtect == PAGE_READONLY, "%x != PAGE_READONLY\n", info.AllocationProtect ); - ok( info.RegionSize == 4096, "%lx != 4096\n", info.RegionSize ); - ok( info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State ); -todo_wine ok( info.Protect == PAGE_READONLY, "%x != PAGE_READONLY\n", info.Protect ); + if (!ptr) + { + ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); + SetLastError(0xdeadbeef); + ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 ); + ok( ptr != NULL, "MapViewOfFile FILE_MAP_READ error %u\n", GetLastError() ); + SetLastError(0xdeadbeef); + ok( VirtualQuery( ptr, &info, sizeof(info) ) == sizeof(info), + "VirtualQuery error %u\n", GetLastError() ); + ok( info.BaseAddress == ptr, "%p != %p\n", info.BaseAddress, ptr ); + ok( info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr ); + ok( info.AllocationProtect == PAGE_READONLY, "%x != PAGE_READONLY\n", info.AllocationProtect ); + ok( info.RegionSize == 4096, "%lx != 4096\n", info.RegionSize ); + ok( info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State ); + ok( info.Protect == PAGE_READONLY, "%x != PAGE_READONLY\n", info.Protect ); + } + else win_skip( "no access checks on win9x\n" ); UnmapViewOfFile( ptr ); CloseHandle( mapping ); SetLastError(0xdeadbeef); - mapping = OpenFileMapping( FILE_MAP_WRITE, FALSE, "Global\\Foo" ); + mapping = OpenFileMapping( FILE_MAP_WRITE, FALSE, name ); ok( mapping != 0, "OpenFileMapping FILE_MAP_WRITE error %u\n", GetLastError() ); SetLastError(0xdeadbeef); ptr = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 ); -todo_wine ok( !ptr, "MapViewOfFile FILE_MAP_READ should fail\n" ); -todo_wine ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); - SetLastError(0xdeadbeef); - ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 ); - ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %u\n", GetLastError() ); - SetLastError(0xdeadbeef); - ok( VirtualQuery( ptr, &info, sizeof(info) ) == sizeof(info), - "VirtualQuery error %u\n", GetLastError() ); - ok( info.BaseAddress == ptr, "%p != %p\n", info.BaseAddress, ptr ); - ok( info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr ); - ok( info.AllocationProtect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.AllocationProtect ); - ok( info.RegionSize == 4096, "%lx != 4096\n", info.RegionSize ); - ok( info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State ); - ok( info.Protect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.Protect ); + if (!ptr) + { + ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLastError() ); + SetLastError(0xdeadbeef); + ptr = MapViewOfFile( mapping, FILE_MAP_WRITE, 0, 0, 0 ); + ok( ptr != NULL, "MapViewOfFile FILE_MAP_WRITE error %u\n", GetLastError() ); + SetLastError(0xdeadbeef); + ok( VirtualQuery( ptr, &info, sizeof(info) ) == sizeof(info), + "VirtualQuery error %u\n", GetLastError() ); + ok( info.BaseAddress == ptr, "%p != %p\n", info.BaseAddress, ptr ); + ok( info.AllocationBase == ptr, "%p != %p\n", info.AllocationBase, ptr ); + ok( info.AllocationProtect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.AllocationProtect ); + ok( info.RegionSize == 4096, "%lx != 4096\n", info.RegionSize ); + ok( info.State == MEM_COMMIT, "%x != MEM_COMMIT\n", info.State ); + ok( info.Protect == PAGE_READWRITE, "%x != PAGE_READWRITE\n", info.Protect ); + } + else win_skip( "no access checks on win9x\n" ); UnmapViewOfFile( ptr ); CloseHandle( mapping ); @@ -506,50 +548,100 @@ todo_wine ok( GetLastError() == ERROR_ACCESS_DENIED, "Wrong error %d\n", GetLast ptr = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0); ok(ptr != NULL, "MapViewOfFile failed with error %d\n", GetLastError()); + ptr2 = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0); + /* on NT ptr != ptr2 but on Win9x ptr == ptr2 */ + ok(ptr2 != NULL, "MapViewOfFile failed with error %d\n", GetLastError()); + trace("mapping same section resulted in views %p and %p\n", ptr, ptr2); + ret = VirtualQuery(ptr, &info, sizeof(info)); ok(ret, "VirtualQuery failed with error %d\n", GetLastError()); ok(info.BaseAddress == ptr, "BaseAddress should have been %p but was %p instead\n", ptr, info.BaseAddress); ok(info.AllocationBase == ptr, "AllocationBase should have been %p but was %p instead\n", ptr, info.AllocationBase); - ok(info.AllocationProtect == PAGE_READWRITE, "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect); ok(info.RegionSize == MAPPING_SIZE, "RegionSize should have been 0x%x but was 0x%x\n", MAPPING_SIZE, (unsigned int)info.RegionSize); -todo_wine ok(info.State == MEM_RESERVE, "State should have been MEM_RESERVE instead of 0x%x\n", info.State); -todo_wine - ok(info.Protect == 0, "Protect should have been 0 instead of 0x%x\n", info.Protect); - ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type); + if (info.Type == MEM_PRIVATE) /* win9x is different for uncommitted mappings */ + { + ok(info.AllocationProtect == PAGE_NOACCESS, + "AllocationProtect should have been PAGE_NOACCESS but was 0x%x\n", info.AllocationProtect); + ok(info.Protect == PAGE_NOACCESS, + "Protect should have been PAGE_NOACCESS instead of 0x%x\n", info.Protect); + } + else + { + ok(info.AllocationProtect == PAGE_READWRITE, + "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect); + ok(info.Protect == 0, "Protect should have been 0 instead of 0x%x\n", info.Protect); + ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type); + } - ptr = VirtualAlloc(ptr, 0x10000, MEM_COMMIT, PAGE_READWRITE); + if (ptr != ptr2) + { + ret = VirtualQuery(ptr2, &info, sizeof(info)); + ok(ret, "VirtualQuery failed with error %d\n", GetLastError()); + ok(info.BaseAddress == ptr2, + "BaseAddress should have been %p but was %p instead\n", ptr2, info.BaseAddress); + ok(info.AllocationBase == ptr2, + "AllocationBase should have been %p but was %p instead\n", ptr2, info.AllocationBase); + ok(info.AllocationProtect == PAGE_READWRITE, + "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect); + ok(info.RegionSize == MAPPING_SIZE, + "RegionSize should have been 0x%x but was 0x%x\n", MAPPING_SIZE, (unsigned int)info.RegionSize); + ok(info.State == MEM_RESERVE, + "State should have been MEM_RESERVE instead of 0x%x\n", info.State); + ok(info.Protect == 0, + "Protect should have been 0 instead of 0x%x\n", info.Protect); + ok(info.Type == MEM_MAPPED, + "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type); + } + + ptr = VirtualAlloc(ptr, 0x10000, MEM_COMMIT, PAGE_READONLY); ok(ptr != NULL, "VirtualAlloc failed with error %d\n", GetLastError()); ret = VirtualQuery(ptr, &info, sizeof(info)); ok(ret, "VirtualQuery failed with error %d\n", GetLastError()); ok(info.BaseAddress == ptr, "BaseAddress should have been %p but was %p instead\n", ptr, info.BaseAddress); ok(info.AllocationBase == ptr, "AllocationBase should have been %p but was %p instead\n", ptr, info.AllocationBase); - ok(info.AllocationProtect == PAGE_READWRITE, "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect); -todo_wine ok(info.RegionSize == 0x10000, "RegionSize should have been 0x10000 but was 0x%x\n", (unsigned int)info.RegionSize); ok(info.State == MEM_COMMIT, "State should have been MEM_RESERVE instead of 0x%x\n", info.State); - ok(info.Protect == PAGE_READWRITE, "Protect should have been 0 instead of 0x%x\n", info.Protect); - ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type); - - ptr2 = MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, 0); - /* on NT ptr != ptr2 but on Win9x ptr == ptr2 */ - ok(ptr2 != NULL, "MapViewOfFile failed with error %d\n", GetLastError()); - trace("mapping same section resulted in views %p and %p\n", ptr, ptr2); + ok(info.Protect == PAGE_READONLY, "Protect should have been 0 instead of 0x%x\n", info.Protect); + if (info.Type == MEM_PRIVATE) /* win9x is different for uncommitted mappings */ + { + ok(info.AllocationProtect == PAGE_NOACCESS, + "AllocationProtect should have been PAGE_NOACCESS but was 0x%x\n", info.AllocationProtect); + } + else + { + ok(info.AllocationProtect == PAGE_READWRITE, + "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect); + ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type); + } /* shows that the VirtualAlloc above affects the mapping, not just the * virtual memory in this process - it also affects all other processes * with a view of the mapping, but that isn't tested here */ - ret = VirtualQuery(ptr2, &info, sizeof(info)); - ok(ret, "VirtualQuery failed with error %d\n", GetLastError()); - ok(info.BaseAddress == ptr2, "BaseAddress should have been %p but was %p instead\n", ptr2, info.BaseAddress); - ok(info.AllocationBase == ptr2, "AllocationBase should have been %p but was %p instead\n", ptr2, info.AllocationBase); - ok(info.AllocationProtect == PAGE_READWRITE, "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect); -todo_wine - ok(info.RegionSize == 0x10000, "RegionSize should have been 0x10000 but was 0x%x\n", (unsigned int)info.RegionSize); - ok(info.State == MEM_COMMIT, "State should have been MEM_RESERVE instead of 0x%x\n", info.State); - ok(info.Protect == PAGE_READWRITE, "Protect should have been 0 instead of 0x%x\n", info.Protect); - ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type); + if (ptr != ptr2) + { + ret = VirtualQuery(ptr2, &info, sizeof(info)); + ok(ret, "VirtualQuery failed with error %d\n", GetLastError()); + ok(info.BaseAddress == ptr2, + "BaseAddress should have been %p but was %p instead\n", ptr2, info.BaseAddress); + ok(info.AllocationBase == ptr2, + "AllocationBase should have been %p but was %p instead\n", ptr2, info.AllocationBase); + ok(info.AllocationProtect == PAGE_READWRITE, + "AllocationProtect should have been PAGE_READWRITE but was 0x%x\n", info.AllocationProtect); + ok(info.RegionSize == 0x10000, + "RegionSize should have been 0x10000 but was 0x%x\n", (unsigned int)info.RegionSize); + ok(info.State == MEM_COMMIT, + "State should have been MEM_RESERVE instead of 0x%x\n", info.State); + ok(info.Protect == PAGE_READWRITE, + "Protect should have been 0 instead of 0x%x\n", info.Protect); + ok(info.Type == MEM_MAPPED, "Type should have been MEM_MAPPED instead of 0x%x\n", info.Type); + } + + ret = VirtualFree( ptr, 0x10000, MEM_DECOMMIT ); + ok( !ret || broken(ret) /* win9x */, "VirtualFree succeeded\n" ); + if (!ret) + ok( GetLastError() == ERROR_INVALID_PARAMETER, "VirtualFree failed with %u\n", GetLastError() ); ret = UnmapViewOfFile(ptr2); ok(ret, "UnmapViewOfFile failed with error %d\n", GetLastError()); @@ -622,6 +714,46 @@ static void test_NtMapViewOfSection(void) CloseHandle(hProcess); } +static void test_CreateFileMapping(void) +{ + HANDLE handle, handle2; + + /* test case sensitivity */ + + SetLastError(0xdeadbeef); + handle = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE, 0, 0x1000, + "Wine Test Mapping"); + ok( handle != NULL, "CreateFileMapping failed with error %u\n", GetLastError()); + ok( GetLastError() == 0, "wrong error %u\n", GetLastError()); + + SetLastError(0xdeadbeef); + handle2 = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE, 0, 0x1000, + "Wine Test Mapping"); + ok( handle2 != NULL, "CreateFileMapping failed with error %d\n", GetLastError()); + ok( GetLastError() == ERROR_ALREADY_EXISTS, "wrong error %u\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE, 0, 0x1000, + "WINE TEST MAPPING"); + ok( handle2 != NULL, "CreateFileMapping failed with error %d\n", GetLastError()); + ok( GetLastError() == 0, "wrong error %u\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = OpenFileMappingA( FILE_MAP_ALL_ACCESS, FALSE, "Wine Test Mapping"); + ok( handle2 != NULL, "OpenFileMapping failed with error %d\n", GetLastError()); + CloseHandle( handle2 ); + + SetLastError(0xdeadbeef); + handle2 = OpenFileMappingA( FILE_MAP_ALL_ACCESS, FALSE, "WINE TEST MAPPING"); + ok( !handle2, "OpenFileMapping succeeded\n"); + ok( GetLastError() == ERROR_FILE_NOT_FOUND || GetLastError() == ERROR_INVALID_NAME /* win9x */, + "wrong error %u\n", GetLastError()); + + CloseHandle( handle ); +} + static void test_BadPtr(void) { void *ptr = (void*)1; @@ -631,6 +763,306 @@ static void test_BadPtr(void) ok(IsBadCodePtr(ptr),"IsBadCodePtr(1) failed.\n"); } +static void test_write_watch(void) +{ + char *base; + DWORD ret, size, old_prot; + MEMORY_BASIC_INFORMATION info; + void *results[64]; + ULONG_PTR count; + ULONG pagesize; + + if (!pGetWriteWatch || !pResetWriteWatch) + { + win_skip( "GetWriteWatch not supported\n" ); + return; + } + + size = 0x10000; + base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_COMMIT | MEM_WRITE_WATCH, PAGE_READWRITE ); + if (!base && + (GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_NOT_SUPPORTED)) + { + win_skip( "MEM_WRITE_WATCH not supported\n" ); + return; + } + ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() ); + ret = VirtualQuery( base, &info, sizeof(info) ); + ok(ret, "VirtualQuery failed %u\n", GetLastError()); + ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base ); + ok( info.AllocationProtect == PAGE_READWRITE, "wrong AllocationProtect %x\n", info.AllocationProtect ); + ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize ); + ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State ); + ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect ); + ok( info.Type == MEM_PRIVATE, "wrong Type 0x%x\n", info.Type ); + + count = 64; + SetLastError( 0xdeadbeef ); + ret = pGetWriteWatch( 0, NULL, size, results, &count, &pagesize ); + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER || + broken( GetLastError() == 0xdeadbeef ), /* win98 */ + "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + ret = pGetWriteWatch( 0, GetModuleHandle(0), size, results, &count, &pagesize ); + if (ret) + { + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + } + else /* win98 */ + { + ok( count == 0, "wrong count %lu\n", count ); + } + + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 0, "wrong count %lu\n", count ); + + base[pagesize + 1] = 0x44; + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 1, "wrong count %lu\n", count ); + ok( results[0] == base + pagesize, "wrong result %p\n", results[0] ); + + count = 64; + ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 1, "wrong count %lu\n", count ); + ok( results[0] == base + pagesize, "wrong result %p\n", results[0] ); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 0, "wrong count %lu\n", count ); + + base[2*pagesize + 3] = 0x11; + base[4*pagesize + 8] = 0x11; + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 2, "wrong count %lu\n", count ); + ok( results[0] == base + 2*pagesize, "wrong result %p\n", results[0] ); + ok( results[1] == base + 4*pagesize, "wrong result %p\n", results[1] ); + + count = 64; + ret = pGetWriteWatch( 0, base + 3*pagesize, 2*pagesize, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 1, "wrong count %lu\n", count ); + ok( results[0] == base + 4*pagesize, "wrong result %p\n", results[0] ); + + ret = pResetWriteWatch( base, 3*pagesize ); + ok( !ret, "pResetWriteWatch failed %u\n", GetLastError() ); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 1, "wrong count %lu\n", count ); + ok( results[0] == base + 4*pagesize, "wrong result %p\n", results[0] ); + + *(DWORD *)(base + 2*pagesize - 2) = 0xdeadbeef; + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 3, "wrong count %lu\n", count ); + ok( results[0] == base + pagesize, "wrong result %p\n", results[0] ); + ok( results[1] == base + 2*pagesize, "wrong result %p\n", results[1] ); + ok( results[2] == base + 4*pagesize, "wrong result %p\n", results[2] ); + + count = 1; + ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 1, "wrong count %lu\n", count ); + ok( results[0] == base + pagesize, "wrong result %p\n", results[0] ); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 2, "wrong count %lu\n", count ); + ok( results[0] == base + 2*pagesize, "wrong result %p\n", results[0] ); + ok( results[1] == base + 4*pagesize, "wrong result %p\n", results[1] ); + + /* changing protections doesn't affect watches */ + + ret = VirtualProtect( base, 3*pagesize, PAGE_READONLY, &old_prot ); + ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); + ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot ); + + ret = VirtualQuery( base, &info, sizeof(info) ); + ok(ret, "VirtualQuery failed %u\n", GetLastError()); + ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base ); + ok( info.RegionSize == 3*pagesize, "wrong RegionSize 0x%lx\n", info.RegionSize ); + ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State ); + ok( info.Protect == PAGE_READONLY, "wrong Protect 0x%x\n", info.Protect ); + + ret = VirtualProtect( base, 3*pagesize, PAGE_READWRITE, &old_prot ); + ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); + ok( old_prot == PAGE_READONLY, "wrong old prot %x\n", old_prot ); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 2, "wrong count %lu\n", count ); + ok( results[0] == base + 2*pagesize, "wrong result %p\n", results[0] ); + ok( results[1] == base + 4*pagesize, "wrong result %p\n", results[1] ); + + ret = VirtualQuery( base, &info, sizeof(info) ); + ok(ret, "VirtualQuery failed %u\n", GetLastError()); + ok( info.BaseAddress == base, "BaseAddress %p instead of %p\n", info.BaseAddress, base ); + ok( info.RegionSize == size, "wrong RegionSize 0x%lx\n", info.RegionSize ); + ok( info.State == MEM_COMMIT, "wrong State 0x%x\n", info.State ); + ok( info.Protect == PAGE_READWRITE, "wrong Protect 0x%x\n", info.Protect ); + + /* some invalid parameter tests */ + + SetLastError( 0xdeadbeef ); + count = 0; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + if (ret) + { + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + ret = pGetWriteWatch( 0, base, size, results, NULL, &pagesize ); + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, NULL ); + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + count = 64; + ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize ); + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + count = 0; + ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize ); + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + count = 64; + ret = pGetWriteWatch( 0xdeadbeef, base, size, results, &count, &pagesize ); + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + count = 64; + ret = pGetWriteWatch( 0, base, 0, results, &count, &pagesize ); + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + count = 64; + ret = pGetWriteWatch( 0, base, size * 2, results, &count, &pagesize ); + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + count = 64; + ret = pGetWriteWatch( 0, base + size - pagesize, pagesize + 1, results, &count, &pagesize ); + ok( ret == ~0u, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + ret = pResetWriteWatch( base, 0 ); + ok( ret == ~0u, "ResetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + ret = pResetWriteWatch( GetModuleHandle(0), size ); + ok( ret == ~0u, "ResetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + } + else /* win98 is completely different */ + { + SetLastError( 0xdeadbeef ); + count = 64; + ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize ); + ok( ret == ERROR_INVALID_PARAMETER, "GetWriteWatch succeeded %u\n", ret ); + ok( GetLastError() == 0xdeadbeef, "wrong error %u\n", GetLastError() ); + + count = 0; + ret = pGetWriteWatch( 0, base, size, NULL, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", ret ); + + count = 64; + ret = pGetWriteWatch( 0xdeadbeef, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", ret ); + + count = 64; + ret = pGetWriteWatch( 0, base, 0, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", ret ); + + ret = pResetWriteWatch( base, 0 ); + ok( !ret, "ResetWriteWatch failed %u\n", ret ); + + ret = pResetWriteWatch( GetModuleHandle(0), size ); + ok( !ret, "ResetWriteWatch failed %u\n", ret ); + } + + VirtualFree( base, 0, MEM_FREE ); + + base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_WRITE_WATCH, PAGE_READWRITE ); + ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() ); + VirtualFree( base, 0, MEM_FREE ); + + base = VirtualAlloc( 0, size, MEM_WRITE_WATCH, PAGE_READWRITE ); + ok( !base, "VirtualAlloc succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); + + /* initial protect doesn't matter */ + + base = VirtualAlloc( 0, size, MEM_RESERVE | MEM_WRITE_WATCH, PAGE_NOACCESS ); + ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() ); + base = VirtualAlloc( base, size, MEM_COMMIT, PAGE_NOACCESS ); + ok( base != NULL, "VirtualAlloc failed %u\n", GetLastError() ); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 0, "wrong count %lu\n", count ); + + ret = VirtualProtect( base, 6*pagesize, PAGE_READWRITE, &old_prot ); + ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); + ok( old_prot == PAGE_NOACCESS, "wrong old prot %x\n", old_prot ); + + base[5*pagesize + 200] = 3; + + ret = VirtualProtect( base, 6*pagesize, PAGE_NOACCESS, &old_prot ); + ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); + ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot ); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 1, "wrong count %lu\n", count ); + ok( results[0] == base + 5*pagesize, "wrong result %p\n", results[0] ); + + ret = VirtualFree( base, size, MEM_DECOMMIT ); + ok( ret, "VirtualFree failed %u\n", GetLastError() ); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 1 || broken(count == 0), /* win98 */ + "wrong count %lu\n", count ); + if (count) ok( results[0] == base + 5*pagesize, "wrong result %p\n", results[0] ); + + VirtualFree( base, 0, MEM_FREE ); +} + START_TEST(virtual) { int argc; @@ -662,10 +1094,14 @@ START_TEST(virtual) hkernel32 = GetModuleHandleA("kernel32.dll"); pVirtualAllocEx = (void *) GetProcAddress(hkernel32, "VirtualAllocEx"); pVirtualFreeEx = (void *) GetProcAddress(hkernel32, "VirtualFreeEx"); + pGetWriteWatch = (void *) GetProcAddress(hkernel32, "GetWriteWatch"); + pResetWriteWatch = (void *) GetProcAddress(hkernel32, "ResetWriteWatch"); test_VirtualAllocEx(); test_VirtualAlloc(); test_MapViewOfFile(); test_NtMapViewOfSection(); + test_CreateFileMapping(); test_BadPtr(); + test_write_watch(); } diff --git a/rostests/winetests/kernel32/volume.c b/rostests/winetests/kernel32/volume.c index 9a21db1badc..97e3559c000 100644 --- a/rostests/winetests/kernel32/volume.c +++ b/rostests/winetests/kernel32/volume.c @@ -27,6 +27,8 @@ static BOOL (WINAPI * pGetVolumeNameForVolumeMountPointW)(LPCWSTR, LPWSTR, DWORD static HANDLE (WINAPI *pFindFirstVolumeA)(LPSTR,DWORD); static BOOL (WINAPI *pFindNextVolumeA)(HANDLE,LPSTR,DWORD); static BOOL (WINAPI *pFindVolumeClose)(HANDLE); +static UINT (WINAPI *pGetLogicalDriveStringsA)(UINT,LPSTR); +static UINT (WINAPI *pGetLogicalDriveStringsW)(UINT,LPWSTR); /* ############################### */ @@ -37,6 +39,11 @@ static void test_query_dos_deviceA(void) DWORD ret; BOOL found = FALSE; + if (!pFindFirstVolumeA) { + skip("On win9x, HARDDISK and RAMDISK not present\n"); + return; + } + for (;drivestr[0] <= 'z'; drivestr[0]++) { ret = QueryDosDeviceA( drivestr, buffer, sizeof(buffer)); if(ret) { @@ -44,7 +51,7 @@ static void test_query_dos_deviceA(void) if (strstr(buffer, "HARDDISK") || strstr(buffer, "RAMDISK")) found = TRUE; } } - todo_wine ok(found, "expected at least one devicename to contain HARDDISK or RAMDISK\n"); + ok(found, "expected at least one devicename to contain HARDDISK or RAMDISK\n"); } static void test_FindFirstVolume(void) @@ -134,6 +141,81 @@ static void test_GetVolumeNameForVolumeMountPointW(void) ok(ret == TRUE, "GetVolumeNameForVolumeMountPointW failed\n"); } +static void test_GetLogicalDriveStringsA(void) +{ + UINT size, size2; + char *buf, *ptr; + + if(!pGetLogicalDriveStringsA) { + win_skip("GetLogicalDriveStringsA not available\n"); + return; + } + + size = pGetLogicalDriveStringsA(0, NULL); + ok(size%4 == 1, "size = %d\n", size); + + buf = HeapAlloc(GetProcessHeap(), 0, size); + + *buf = 0; + size2 = pGetLogicalDriveStringsA(2, buf); + ok(size2 == size, "size2 = %d\n", size2); + ok(!*buf, "buf changed\n"); + + size2 = pGetLogicalDriveStringsA(size, buf); + ok(size2 == size-1, "size2 = %d\n", size2); + + for(ptr = buf; ptr < buf+size2; ptr += 4) { + ok(('A' <= *ptr && *ptr <= 'Z') || + (broken('a' <= *ptr && *ptr <= 'z')), /* Win9x and WinMe */ + "device name '%c' is not uppercase\n", *ptr); + ok(ptr[1] == ':', "ptr[1] = %c, expected ':'\n", ptr[1]); + ok(ptr[2] == '\\', "ptr[2] = %c expected '\\'\n", ptr[2]); + ok(!ptr[3], "ptr[3] = %c expected nullbyte\n", ptr[3]); + } + ok(!*ptr, "buf[size2] is not nullbyte\n"); + + HeapFree(GetProcessHeap(), 0, buf); +} + +static void test_GetLogicalDriveStringsW(void) +{ + UINT size, size2; + WCHAR *buf, *ptr; + + if(!pGetLogicalDriveStringsW) { + win_skip("GetLogicalDriveStringsW not available\n"); + return; + } + + SetLastError(0xdeadbeef); + size = pGetLogicalDriveStringsW(0, NULL); + if (size == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { + win_skip("GetLogicalDriveStringsW not implemented\n"); + return; + } + ok(size%4 == 1, "size = %d\n", size); + + buf = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR)); + + *buf = 0; + size2 = pGetLogicalDriveStringsW(2, buf); + ok(size2 == size, "size2 = %d\n", size2); + ok(!*buf, "buf changed\n"); + + size2 = pGetLogicalDriveStringsW(size, buf); + ok(size2 == size-1, "size2 = %d\n", size2); + + for(ptr = buf; ptr < buf+size2; ptr += 4) { + ok('A' <= *ptr && *ptr <= 'Z', "device name '%c' is not uppercase\n", *ptr); + ok(ptr[1] == ':', "ptr[1] = %c, expected ':'\n", ptr[1]); + ok(ptr[2] == '\\', "ptr[2] = %c expected '\\'\n", ptr[2]); + ok(!ptr[3], "ptr[3] = %c expected nullbyte\n", ptr[3]); + } + ok(!*ptr, "buf[size2] is not nullbyte\n"); + + HeapFree(GetProcessHeap(), 0, buf); +} + START_TEST(volume) { hdll = GetModuleHandleA("kernel32.dll"); @@ -142,9 +224,13 @@ START_TEST(volume) pFindFirstVolumeA = (void *) GetProcAddress(hdll, "FindFirstVolumeA"); pFindNextVolumeA = (void *) GetProcAddress(hdll, "FindNextVolumeA"); pFindVolumeClose = (void *) GetProcAddress(hdll, "FindVolumeClose"); + pGetLogicalDriveStringsA = (void *) GetProcAddress(hdll, "GetLogicalDriveStringsA"); + pGetLogicalDriveStringsW = (void *) GetProcAddress(hdll, "GetLogicalDriveStringsW"); test_query_dos_deviceA(); test_FindFirstVolume(); test_GetVolumeNameForVolumeMountPointA(); test_GetVolumeNameForVolumeMountPointW(); + test_GetLogicalDriveStringsA(); + test_GetLogicalDriveStringsW(); }